├── shell.nix ├── Setup.hs ├── nix ├── base-compat.nix ├── contravariant.nix ├── parser-combinators.nix ├── repline.nix ├── time-locale-compat.nix ├── dhall-nix.nix ├── cborg-json.nix ├── base-orphans.nix ├── neat-interpolation.nix ├── free.nix ├── optparse-applicative.nix ├── http-types.nix ├── QuickCheck.nix ├── pretty-show.nix ├── vector.nix ├── semigroupoids.nix ├── megaparsec.nix ├── these.nix ├── hnix-store-core.nix ├── http-client.nix ├── serialise.nix ├── aeson.nix ├── fetchNixpkgs.nix ├── lens.nix ├── dhall.nix └── hnix.nix ├── LICENSE ├── exec └── Main.hs ├── dhall-nix.cabal ├── .travis.yml ├── README.md ├── release.nix └── src └── Dhall └── Nix.hs /shell.nix: -------------------------------------------------------------------------------- 1 | (import ./release.nix).shell 2 | -------------------------------------------------------------------------------- /Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /nix/base-compat.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, base, stdenv, unix }: 2 | mkDerivation { 3 | pname = "base-compat"; 4 | version = "0.10.5"; 5 | sha256 = "990aea21568956d44ab018c5dbfbaea014b9a0d5295d29ca7550149419a6fb41"; 6 | libraryHaskellDepends = [ base unix ]; 7 | description = "A compatibility layer for base"; 8 | license = stdenv.lib.licenses.mit; 9 | } 10 | -------------------------------------------------------------------------------- /nix/contravariant.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, base, StateVar, stdenv, transformers }: 2 | mkDerivation { 3 | pname = "contravariant"; 4 | version = "1.5"; 5 | sha256 = "6ef067b692ad69ffff294b953aa85f3ded459d4ae133c37896222a09280fc3c2"; 6 | libraryHaskellDepends = [ base StateVar transformers ]; 7 | homepage = "http://github.com/ekmett/contravariant/"; 8 | description = "Contravariant functors"; 9 | license = stdenv.lib.licenses.bsd3; 10 | } 11 | -------------------------------------------------------------------------------- /nix/parser-combinators.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, base, stdenv }: 2 | mkDerivation { 3 | pname = "parser-combinators"; 4 | version = "1.0.1"; 5 | sha256 = "edf5ab8fa69a04334baa8707252036563a8339a96a86956c90febe93830cea32"; 6 | libraryHaskellDepends = [ base ]; 7 | homepage = "https://github.com/mrkkrp/parser-combinators"; 8 | description = "Lightweight package providing commonly useful parser combinators"; 9 | license = stdenv.lib.licenses.bsd3; 10 | } 11 | -------------------------------------------------------------------------------- /nix/repline.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, base, containers, haskeline, mtl, process, stdenv 2 | }: 3 | mkDerivation { 4 | pname = "repline"; 5 | version = "0.2.0.0"; 6 | sha256 = "ecc72092d0340b896ee6bf96bf6645694dbcd33361725a2cd28c5ab5d60c02de"; 7 | libraryHaskellDepends = [ base containers haskeline mtl process ]; 8 | homepage = "https://github.com/sdiehl/repline"; 9 | description = "Haskeline wrapper for GHCi-like REPL interfaces"; 10 | license = stdenv.lib.licenses.mit; 11 | } 12 | -------------------------------------------------------------------------------- /nix/time-locale-compat.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, base, old-locale, stdenv, time }: 2 | mkDerivation { 3 | pname = "time-locale-compat"; 4 | version = "0.1.1.5"; 5 | sha256 = "07ff1566de7d851423a843b2de385442319348c621d4f779b3d365ce91ac502c"; 6 | libraryHaskellDepends = [ base old-locale time ]; 7 | homepage = "https://github.com/khibino/haskell-time-locale-compat"; 8 | description = "Compatibile module for time-format locale"; 9 | license = stdenv.lib.licenses.bsd3; 10 | } 11 | -------------------------------------------------------------------------------- /nix/dhall-nix.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, base, containers, data-fix, dhall, hnix 2 | , neat-interpolation, optparse-generic, stdenv, text 3 | }: 4 | mkDerivation { 5 | pname = "dhall-nix"; 6 | version = "1.1.6"; 7 | src = ./..; 8 | isLibrary = true; 9 | isExecutable = true; 10 | libraryHaskellDepends = [ 11 | base containers data-fix dhall hnix neat-interpolation text 12 | ]; 13 | executableHaskellDepends = [ 14 | base dhall hnix optparse-generic text 15 | ]; 16 | description = "Dhall to Nix compiler"; 17 | license = stdenv.lib.licenses.bsd3; 18 | } 19 | -------------------------------------------------------------------------------- /nix/cborg-json.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, aeson, aeson-pretty, base, cborg, scientific 2 | , stdenv, text, unordered-containers, vector 3 | }: 4 | mkDerivation { 5 | pname = "cborg-json"; 6 | version = "0.2.1.0"; 7 | sha256 = "3fb6b54e6ddd322880689fb461f7911aca45b9758482c9f9949619c7d7b52006"; 8 | libraryHaskellDepends = [ 9 | aeson aeson-pretty base cborg scientific text unordered-containers 10 | vector 11 | ]; 12 | homepage = "https://github.com/well-typed/cborg"; 13 | description = "A library for encoding JSON as CBOR"; 14 | license = stdenv.lib.licenses.bsd3; 15 | } 16 | -------------------------------------------------------------------------------- /nix/base-orphans.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, base, ghc-prim, hspec, hspec-discover, QuickCheck 2 | , stdenv 3 | }: 4 | mkDerivation { 5 | pname = "base-orphans"; 6 | version = "0.8.1"; 7 | sha256 = "442bd63aed102e753b2fed15df8ae19f35ee07af26590da63837c523b64a99db"; 8 | libraryHaskellDepends = [ base ghc-prim ]; 9 | testHaskellDepends = [ base hspec QuickCheck ]; 10 | testToolDepends = [ hspec-discover ]; 11 | homepage = "https://github.com/haskell-compat/base-orphans#readme"; 12 | description = "Backwards-compatible orphan instances for base"; 13 | license = stdenv.lib.licenses.mit; 14 | } 15 | -------------------------------------------------------------------------------- /nix/neat-interpolation.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, base, base-prelude, HTF, megaparsec, stdenv 2 | , template-haskell, text 3 | }: 4 | mkDerivation { 5 | pname = "neat-interpolation"; 6 | version = "0.3.2.4"; 7 | sha256 = "de7370d938ffd8c7b52d732f4f088387ed8216cf9767d818e99b7ec827931752"; 8 | libraryHaskellDepends = [ 9 | base base-prelude megaparsec template-haskell text 10 | ]; 11 | testHaskellDepends = [ base-prelude HTF ]; 12 | homepage = "https://github.com/nikita-volkov/neat-interpolation"; 13 | description = "A quasiquoter for neat and simple multiline text interpolation"; 14 | license = stdenv.lib.licenses.mit; 15 | } 16 | -------------------------------------------------------------------------------- /nix/free.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, base, comonad, containers, distributive, exceptions 2 | , mtl, profunctors, semigroupoids, stdenv, template-haskell 3 | , transformers, transformers-base 4 | }: 5 | mkDerivation { 6 | pname = "free"; 7 | version = "5.1"; 8 | sha256 = "70424d5c82dea36a0a29c4f5f6bc047597a947ad46f3d66312e47bbee2eeea84"; 9 | libraryHaskellDepends = [ 10 | base comonad containers distributive exceptions mtl profunctors 11 | semigroupoids template-haskell transformers transformers-base 12 | ]; 13 | homepage = "http://github.com/ekmett/free/"; 14 | description = "Monads for free"; 15 | license = stdenv.lib.licenses.bsd3; 16 | } 17 | -------------------------------------------------------------------------------- /nix/optparse-applicative.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, ansi-wl-pprint, base, bytestring, process 2 | , QuickCheck, stdenv, transformers, transformers-compat 3 | }: 4 | mkDerivation { 5 | pname = "optparse-applicative"; 6 | version = "0.14.3.0"; 7 | sha256 = "72476302fe555a508917b2d7d6121c7b58ea5434cdc08aeb5d4b652e8f0e7663"; 8 | libraryHaskellDepends = [ 9 | ansi-wl-pprint base process transformers transformers-compat 10 | ]; 11 | testHaskellDepends = [ base bytestring QuickCheck ]; 12 | homepage = "https://github.com/pcapriotti/optparse-applicative"; 13 | description = "Utilities and combinators for parsing command line options"; 14 | license = stdenv.lib.licenses.bsd3; 15 | } 16 | -------------------------------------------------------------------------------- /nix/http-types.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, array, base, bytestring, case-insensitive, doctest 2 | , hspec, QuickCheck, quickcheck-instances, stdenv, text 3 | }: 4 | mkDerivation { 5 | pname = "http-types"; 6 | version = "0.12.3"; 7 | sha256 = "4e8a4a66477459fa436a331c75e46857ec8026283df984d54f90576cd3024016"; 8 | libraryHaskellDepends = [ 9 | array base bytestring case-insensitive text 10 | ]; 11 | testHaskellDepends = [ 12 | base bytestring doctest hspec QuickCheck quickcheck-instances text 13 | ]; 14 | homepage = "https://github.com/aristidb/http-types"; 15 | description = "Generic HTTP types for Haskell (for both client and server code)"; 16 | license = stdenv.lib.licenses.bsd3; 17 | } 18 | -------------------------------------------------------------------------------- /nix/QuickCheck.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, base, containers, deepseq, erf, process, random 2 | , stdenv, template-haskell, tf-random, transformers 3 | }: 4 | mkDerivation { 5 | pname = "QuickCheck"; 6 | version = "2.12.6.1"; 7 | sha256 = "0b2aa7f5c625b5875c36f5f548926fcdaedf4311bd3a4c291fcf10b8d7faa170"; 8 | revision = "1"; 9 | editedCabalFile = "0w5gygp6pmyjzjjx5irfflcbx586zfnqidq669ssqqfsadf944xv"; 10 | libraryHaskellDepends = [ 11 | base containers deepseq erf random template-haskell tf-random 12 | transformers 13 | ]; 14 | testHaskellDepends = [ base deepseq process ]; 15 | homepage = "https://github.com/nick8325/quickcheck"; 16 | description = "Automatic testing of Haskell programs"; 17 | license = stdenv.lib.licenses.bsd3; 18 | } 19 | -------------------------------------------------------------------------------- /nix/pretty-show.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, array, base, filepath, ghc-prim, happy 2 | , haskell-lexer, pretty, stdenv, text 3 | }: 4 | mkDerivation { 5 | pname = "pretty-show"; 6 | version = "1.9.5"; 7 | sha256 = "b095bebb79951d2e25a543a591844fb638165672d7b95d325844611297ba423f"; 8 | isLibrary = true; 9 | isExecutable = true; 10 | enableSeparateDataOutput = true; 11 | libraryHaskellDepends = [ 12 | array base filepath ghc-prim haskell-lexer pretty text 13 | ]; 14 | libraryToolDepends = [ happy ]; 15 | executableHaskellDepends = [ base ]; 16 | homepage = "http://wiki.github.com/yav/pretty-show"; 17 | description = "Tools for working with derived `Show` instances and generic inspection of values"; 18 | license = stdenv.lib.licenses.mit; 19 | } 20 | -------------------------------------------------------------------------------- /nix/vector.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, base, base-orphans, deepseq, ghc-prim, HUnit 2 | , primitive, QuickCheck, random, stdenv, template-haskell 3 | , test-framework, test-framework-hunit, test-framework-quickcheck2 4 | , transformers 5 | }: 6 | mkDerivation { 7 | pname = "vector"; 8 | version = "0.12.0.2"; 9 | sha256 = "52e89dacaff10bedb8653181963cae928f9674a099bb706713dae83994bbc0f3"; 10 | libraryHaskellDepends = [ base deepseq ghc-prim primitive ]; 11 | testHaskellDepends = [ 12 | base base-orphans HUnit primitive QuickCheck random 13 | template-haskell test-framework test-framework-hunit 14 | test-framework-quickcheck2 transformers 15 | ]; 16 | homepage = "https://github.com/haskell/vector"; 17 | description = "Efficient Arrays"; 18 | license = stdenv.lib.licenses.bsd3; 19 | } 20 | -------------------------------------------------------------------------------- /nix/semigroupoids.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, base, base-orphans, bifunctors, Cabal 2 | , cabal-doctest, comonad, containers, contravariant, distributive 3 | , doctest, hashable, stdenv, tagged, template-haskell, transformers 4 | , transformers-compat, unordered-containers 5 | }: 6 | mkDerivation { 7 | pname = "semigroupoids"; 8 | version = "5.3.2"; 9 | sha256 = "61a8213df437ee96a20b1c6dec8b5c573e4e0f338eb2061739a67f471d6b9d05"; 10 | setupHaskellDepends = [ base Cabal cabal-doctest ]; 11 | libraryHaskellDepends = [ 12 | base base-orphans bifunctors comonad containers contravariant 13 | distributive hashable tagged template-haskell transformers 14 | transformers-compat unordered-containers 15 | ]; 16 | testHaskellDepends = [ base doctest ]; 17 | homepage = "http://github.com/ekmett/semigroupoids"; 18 | description = "Semigroupoids: Category sans id"; 19 | license = stdenv.lib.licenses.bsd3; 20 | } 21 | -------------------------------------------------------------------------------- /nix/megaparsec.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, base, bytestring, case-insensitive, containers 2 | , criterion, deepseq, hspec, hspec-expectations, mtl 3 | , parser-combinators, QuickCheck, scientific, stdenv, text 4 | , transformers, weigh 5 | }: 6 | mkDerivation { 7 | pname = "megaparsec"; 8 | version = "7.0.4"; 9 | sha256 = "325ba5cee8cdef91e351fb2db0b38562f8345b0bcdfed97045671357501de8c1"; 10 | libraryHaskellDepends = [ 11 | base bytestring case-insensitive containers deepseq mtl 12 | parser-combinators scientific text transformers 13 | ]; 14 | testHaskellDepends = [ 15 | base bytestring case-insensitive containers hspec 16 | hspec-expectations mtl parser-combinators QuickCheck scientific 17 | text transformers 18 | ]; 19 | benchmarkHaskellDepends = [ 20 | base containers criterion deepseq text weigh 21 | ]; 22 | homepage = "https://github.com/mrkkrp/megaparsec"; 23 | description = "Monadic parser combinators"; 24 | license = stdenv.lib.licenses.bsd2; 25 | } 26 | -------------------------------------------------------------------------------- /nix/these.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, aeson, base, base-compat, bifunctors, binary 2 | , containers, data-default-class, deepseq, hashable, keys, lens 3 | , mtl, QuickCheck, quickcheck-instances, semigroupoids, stdenv 4 | , tasty, tasty-quickcheck, transformers, transformers-compat 5 | , unordered-containers, vector, vector-instances 6 | }: 7 | mkDerivation { 8 | pname = "these"; 9 | version = "0.7.6"; 10 | sha256 = "9464b83d98e626360a8ad9836ba77e5201cd1e9c89b95b1b11a28ef3c23ac746"; 11 | libraryHaskellDepends = [ 12 | aeson base base-compat bifunctors binary containers 13 | data-default-class deepseq hashable keys lens mtl QuickCheck 14 | semigroupoids transformers transformers-compat unordered-containers 15 | vector vector-instances 16 | ]; 17 | testHaskellDepends = [ 18 | aeson base base-compat bifunctors binary containers hashable lens 19 | QuickCheck quickcheck-instances tasty tasty-quickcheck transformers 20 | unordered-containers vector 21 | ]; 22 | homepage = "https://github.com/isomorphism/these"; 23 | description = "An either-or-both data type & a generalized 'zip with padding' typeclass"; 24 | license = stdenv.lib.licenses.bsd3; 25 | } 26 | -------------------------------------------------------------------------------- /nix/hnix-store-core.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, base, base16-bytestring, base64-bytestring, binary 2 | , bytestring, containers, cryptohash-md5, cryptohash-sha1 3 | , cryptohash-sha256, directory, filepath, hashable, mtl, process 4 | , regex-base, regex-tdfa-text, stdenv, tasty, tasty-discover 5 | , tasty-hspec, tasty-hunit, tasty-quickcheck, temporary, text, unix 6 | , unordered-containers, vector 7 | }: 8 | mkDerivation { 9 | pname = "hnix-store-core"; 10 | version = "0.1.0.0"; 11 | sha256 = "878c9a1dcb535b76efb7af392f9a9e75b954ce4ebb75acac91036a6c3c1d3df7"; 12 | libraryHaskellDepends = [ 13 | base base16-bytestring binary bytestring containers cryptohash-md5 14 | cryptohash-sha1 cryptohash-sha256 directory filepath hashable mtl 15 | regex-base regex-tdfa-text text unix unordered-containers vector 16 | ]; 17 | testHaskellDepends = [ 18 | base base64-bytestring binary bytestring containers directory 19 | process tasty tasty-discover tasty-hspec tasty-hunit 20 | tasty-quickcheck temporary text 21 | ]; 22 | testToolDepends = [ tasty-discover ]; 23 | homepage = "https://github.com/haskell-nix/hnix-store"; 24 | description = "Core effects for interacting with the Nix store"; 25 | license = stdenv.lib.licenses.asl20; 26 | } 27 | -------------------------------------------------------------------------------- /nix/http-client.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, array, async, base, blaze-builder, bytestring 2 | , case-insensitive, containers, cookie, deepseq, directory 3 | , exceptions, filepath, ghc-prim, hspec, http-types, memory 4 | , mime-types, monad-control, network, network-uri, random, stdenv 5 | , stm, streaming-commons, text, time, transformers, zlib 6 | }: 7 | mkDerivation { 8 | pname = "http-client"; 9 | version = "0.5.14"; 10 | sha256 = "8e50409704021c51a8955b2d03bfec900ebc3e11fbaebf973f2e654d7bde3647"; 11 | revision = "1"; 12 | editedCabalFile = "0xw5ac4cvcd4hcwl7j12adi7sgffjryqhk0x992k3qs1cxyv5028"; 13 | libraryHaskellDepends = [ 14 | array base blaze-builder bytestring case-insensitive containers 15 | cookie deepseq exceptions filepath ghc-prim http-types memory 16 | mime-types network network-uri random stm streaming-commons text 17 | time transformers 18 | ]; 19 | testHaskellDepends = [ 20 | async base blaze-builder bytestring case-insensitive containers 21 | deepseq directory hspec http-types monad-control network 22 | network-uri streaming-commons text time transformers zlib 23 | ]; 24 | doCheck = false; 25 | homepage = "https://github.com/snoyberg/http-client"; 26 | description = "An HTTP client engine"; 27 | license = stdenv.lib.licenses.mit; 28 | } 29 | -------------------------------------------------------------------------------- /nix/serialise.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, aeson, array, base, binary, bytestring, cborg 2 | , cereal, cereal-vector, containers, criterion, deepseq, directory 3 | , filepath, ghc-prim, half, hashable, pretty, primitive, QuickCheck 4 | , quickcheck-instances, semigroups, stdenv, store, tar, tasty 5 | , tasty-hunit, tasty-quickcheck, text, time, unordered-containers 6 | , vector, zlib 7 | }: 8 | mkDerivation { 9 | pname = "serialise"; 10 | version = "0.2.1.0"; 11 | sha256 = "043efc1130b4202f080c5b7d2c319098df032b060655d8193f1fcdbfa3f159a5"; 12 | libraryHaskellDepends = [ 13 | array base bytestring cborg containers ghc-prim half hashable 14 | primitive text time unordered-containers vector 15 | ]; 16 | testHaskellDepends = [ 17 | base bytestring cborg containers directory filepath primitive 18 | QuickCheck quickcheck-instances tasty tasty-hunit tasty-quickcheck 19 | text time unordered-containers vector 20 | ]; 21 | benchmarkHaskellDepends = [ 22 | aeson array base binary bytestring cborg cereal cereal-vector 23 | containers criterion deepseq directory filepath ghc-prim half 24 | pretty semigroups store tar text time vector zlib 25 | ]; 26 | homepage = "https://github.com/well-typed/cborg"; 27 | description = "A binary serialisation library for Haskell values"; 28 | license = stdenv.lib.licenses.bsd3; 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Gabriel Gonzalez 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright notice, 9 | this list of conditions and the following disclaimer in the documentation 10 | and/or other materials provided with the distribution. 11 | * Neither the name of Gabriel Gonzalez nor the names of other contributors 12 | may be used to endorse or promote products derived from this software 13 | without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 22 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /nix/aeson.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, attoparsec, base, base-compat, base-orphans 2 | , base16-bytestring, bytestring, containers, contravariant, deepseq 3 | , directory, dlist, filepath, generic-deriving, ghc-prim, hashable 4 | , hashable-time, integer-logarithms, primitive, QuickCheck 5 | , quickcheck-instances, scientific, stdenv, tagged, tasty 6 | , tasty-hunit, tasty-quickcheck, template-haskell, text 7 | , th-abstraction, time, time-locale-compat, unordered-containers 8 | , uuid-types, vector 9 | }: 10 | mkDerivation { 11 | pname = "aeson"; 12 | version = "1.4.2.0"; 13 | sha256 = "75ce71814a33d5e5568208e6806a8847e7ba47fea74d30f6a8b1b56ecb318bd0"; 14 | revision = "1"; 15 | editedCabalFile = "067y82gq86740j2zj4y6v7z9b5860ncg2g9lfnrpsnb9jqm7arl1"; 16 | libraryHaskellDepends = [ 17 | attoparsec base base-compat bytestring containers contravariant 18 | deepseq dlist ghc-prim hashable primitive scientific tagged 19 | template-haskell text th-abstraction time time-locale-compat 20 | unordered-containers uuid-types vector 21 | ]; 22 | testHaskellDepends = [ 23 | attoparsec base base-compat base-orphans base16-bytestring 24 | bytestring containers directory dlist filepath generic-deriving 25 | ghc-prim hashable hashable-time integer-logarithms QuickCheck 26 | quickcheck-instances scientific tagged tasty tasty-hunit 27 | tasty-quickcheck template-haskell text time time-locale-compat 28 | unordered-containers uuid-types vector 29 | ]; 30 | homepage = "https://github.com/bos/aeson"; 31 | description = "Fast JSON parsing and encoding"; 32 | license = stdenv.lib.licenses.bsd3; 33 | } 34 | -------------------------------------------------------------------------------- /nix/fetchNixpkgs.nix: -------------------------------------------------------------------------------- 1 | { rev # The Git revision of nixpkgs to fetch 2 | , sha256 # The SHA256 of the downloaded data 3 | , outputSha256 ? null # The SHA256 fixed-output hash 4 | , system ? builtins.currentSystem # This is overridable if necessary 5 | }: 6 | 7 | if (0 <= builtins.compareVersions builtins.nixVersion "1.12") 8 | 9 | # In Nix 1.12, we can just give a `sha256` to `builtins.fetchTarball`. 10 | then ( 11 | builtins.fetchTarball { 12 | url = "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz"; 13 | sha256 = outputSha256; 14 | }) 15 | 16 | # This hack should at least work for Nix 1.11 17 | else ( 18 | (rec { 19 | tarball = import { 20 | url = "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz"; 21 | inherit sha256; 22 | }; 23 | 24 | builtin-paths = import ; 25 | 26 | script = builtins.toFile "nixpkgs-unpacker" '' 27 | "$coreutils/mkdir" "$out" 28 | cd "$out" 29 | "$gzip" --decompress < "$tarball" | "$tar" -x --strip-components=1 30 | ''; 31 | 32 | nixpkgs = builtins.derivation ({ 33 | name = "nixpkgs-${builtins.substring 0 6 rev}"; 34 | 35 | builder = builtins.storePath builtin-paths.shell; 36 | 37 | args = [ script ]; 38 | 39 | inherit tarball system; 40 | 41 | tar = builtins.storePath builtin-paths.tar; 42 | gzip = builtins.storePath builtin-paths.gzip; 43 | coreutils = builtins.storePath builtin-paths.coreutils; 44 | } // (if null == outputSha256 then { } else { 45 | outputHashMode = "recursive"; 46 | outputHashAlgo = "sha256"; 47 | outputHash = outputSha256; 48 | })); 49 | }).nixpkgs) 50 | -------------------------------------------------------------------------------- /exec/Main.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Main where 4 | 5 | import Control.Exception (SomeException) 6 | import System.Exit (ExitCode(..)) 7 | 8 | import qualified Control.Exception 9 | import qualified Data.Text.IO 10 | import qualified Dhall 11 | import qualified Dhall.Import 12 | import qualified Dhall.Nix 13 | import qualified Dhall.Parser 14 | import qualified Dhall.TypeCheck 15 | import qualified GHC.IO.Encoding 16 | import qualified Nix.Pretty 17 | import qualified Options.Generic 18 | import qualified System.Exit 19 | import qualified System.IO 20 | 21 | main :: IO () 22 | main = handle (Dhall.detailed (do 23 | GHC.IO.Encoding.setLocaleEncoding GHC.IO.Encoding.utf8 24 | () <- Options.Generic.getRecord "Compile Dhall to Nix" 25 | 26 | inText <- Data.Text.IO.getContents 27 | 28 | expr <- case Dhall.Parser.exprFromText "(stdin)" inText of 29 | Left err -> Control.Exception.throwIO err 30 | Right expr -> return expr 31 | 32 | expr' <- Dhall.Import.load expr 33 | case Dhall.TypeCheck.typeOf expr' of 34 | Left err -> Control.Exception.throwIO err 35 | Right _ -> return () 36 | 37 | nix <- case Dhall.Nix.dhallToNix expr' of 38 | Left err -> Control.Exception.throwIO err 39 | Right nix -> return nix 40 | print (Nix.Pretty.prettyNix nix) )) 41 | 42 | handle :: IO a -> IO a 43 | handle = Control.Exception.handle handler 44 | where 45 | handler :: SomeException -> IO a 46 | handler e = case Control.Exception.fromException e of 47 | Just ExitSuccess -> do 48 | Control.Exception.throwIO e 49 | _ -> do 50 | System.IO.hPutStrLn System.IO.stderr "" 51 | System.IO.hPrint System.IO.stderr e 52 | System.Exit.exitFailure 53 | -------------------------------------------------------------------------------- /dhall-nix.cabal: -------------------------------------------------------------------------------- 1 | Name: dhall-nix 2 | Version: 1.1.6 3 | Cabal-Version: >=1.8.0.2 4 | Build-Type: Simple 5 | Tested-With: GHC == 8.0.1 6 | License: BSD3 7 | License-File: LICENSE 8 | Copyright: 2017 Gabriel Gonzalez 9 | Author: Gabriel Gonzalez 10 | Maintainer: Gabriel439@gmail.com 11 | Bug-Reports: https://github.com/Gabriel439/Haskell-Dhall-Nix-Library/issues 12 | Synopsis: Dhall to Nix compiler 13 | Description: 14 | Use this package if you want to compile Dhall expressions to the Nix language. 15 | You can use this package as a library or an executable: 16 | . 17 | * See the "Dhall.Nix" module if you want to use this package as a library 18 | . 19 | * Use the @dhall-to-nix@ program from this package if you want an executable 20 | . 21 | The "Dhall.Nix" module also contains instructions for how to use this package 22 | Category: Compiler 23 | Source-Repository head 24 | Type: git 25 | Location: https://github.com/Gabriel439/Haskell-Dhall-Nix-Library 26 | 27 | Library 28 | Hs-Source-Dirs: src 29 | Build-Depends: 30 | base >= 4.8.0.0 && < 5 , 31 | containers < 0.7 , 32 | data-fix < 0.3 , 33 | dhall >= 1.19 && < 1.22, 34 | hnix >= 0.5 && < 0.7 , 35 | neat-interpolation < 0.4 , 36 | text >= 0.8.0.0 && < 1.3 37 | Exposed-Modules: 38 | Dhall.Nix 39 | GHC-Options: -Wall 40 | 41 | Executable dhall-to-nix 42 | Hs-Source-Dirs: exec 43 | Main-Is: Main.hs 44 | Build-Depends: 45 | base , 46 | dhall , 47 | dhall-nix , 48 | hnix , 49 | optparse-generic >= 1.1.1 && < 1.4, 50 | text 51 | GHC-Options: -Wall 52 | -------------------------------------------------------------------------------- /nix/lens.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, array, base, base-orphans, bifunctors, bytestring 2 | , Cabal, cabal-doctest, call-stack, comonad, containers 3 | , contravariant, criterion, deepseq, directory, distributive 4 | , doctest, exceptions, filepath, free, generic-deriving, ghc-prim 5 | , hashable, HUnit, kan-extensions, mtl, nats, parallel, profunctors 6 | , QuickCheck, reflection, semigroupoids, semigroups, simple-reflect 7 | , stdenv, tagged, template-haskell, test-framework 8 | , test-framework-hunit, test-framework-quickcheck2 9 | , test-framework-th, text, th-abstraction, transformers 10 | , transformers-compat, unordered-containers, vector, void 11 | }: 12 | mkDerivation { 13 | pname = "lens"; 14 | version = "4.17"; 15 | sha256 = "473664de541023bef44aa29105abbb1e35542e9254cdc846963183e0dd3f08cc"; 16 | setupHaskellDepends = [ base Cabal cabal-doctest filepath ]; 17 | libraryHaskellDepends = [ 18 | array base base-orphans bifunctors bytestring call-stack comonad 19 | containers contravariant distributive exceptions filepath free 20 | ghc-prim hashable kan-extensions mtl parallel profunctors 21 | reflection semigroupoids semigroups tagged template-haskell text 22 | th-abstraction transformers transformers-compat 23 | unordered-containers vector void 24 | ]; 25 | testHaskellDepends = [ 26 | base bytestring containers deepseq directory doctest filepath 27 | generic-deriving HUnit mtl nats parallel QuickCheck semigroups 28 | simple-reflect test-framework test-framework-hunit 29 | test-framework-quickcheck2 test-framework-th text transformers 30 | unordered-containers vector 31 | ]; 32 | benchmarkHaskellDepends = [ 33 | base bytestring comonad containers criterion deepseq 34 | generic-deriving transformers unordered-containers vector 35 | ]; 36 | homepage = "http://github.com/ekmett/lens/"; 37 | description = "Lenses, Folds and Traversals"; 38 | license = stdenv.lib.licenses.bsd2; 39 | } 40 | -------------------------------------------------------------------------------- /nix/dhall.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, aeson, aeson-pretty, ansi-terminal, base 2 | , bytestring, case-insensitive, cborg, cborg-json, containers 3 | , contravariant, criterion, cryptonite, deepseq, Diff, directory 4 | , doctest, dotgen, exceptions, filepath, haskeline, http-client 5 | , http-client-tls, http-types, lens-family-core, megaparsec, memory 6 | , mockery, mtl, optparse-applicative, parsers, prettyprinter 7 | , prettyprinter-ansi-terminal, QuickCheck, quickcheck-instances 8 | , repline, scientific, serialise, stdenv, tasty, tasty-hunit 9 | , tasty-quickcheck, template-haskell, text, transformers 10 | , unordered-containers, uri-encode, vector 11 | }: 12 | mkDerivation { 13 | pname = "dhall"; 14 | version = "1.21.0"; 15 | sha256 = "9b22cc6f7694ef2f5d5d6fa66727044622b9905b2a9da0cdf376c75ad3b9df0e"; 16 | revision = "1"; 17 | editedCabalFile = "0ap1490jks9hmwf73vlrj7bsfrf4m5yvgqxx3ix57w23ia5gy662"; 18 | isLibrary = true; 19 | isExecutable = true; 20 | libraryHaskellDepends = [ 21 | aeson aeson-pretty ansi-terminal base bytestring case-insensitive 22 | cborg cborg-json containers contravariant cryptonite Diff directory 23 | dotgen exceptions filepath haskeline http-client http-client-tls 24 | http-types lens-family-core megaparsec memory mtl 25 | optparse-applicative parsers prettyprinter 26 | prettyprinter-ansi-terminal repline scientific serialise 27 | template-haskell text transformers unordered-containers uri-encode 28 | vector 29 | ]; 30 | executableHaskellDepends = [ base ]; 31 | testHaskellDepends = [ 32 | base bytestring cborg containers deepseq directory doctest filepath 33 | mockery prettyprinter QuickCheck quickcheck-instances serialise 34 | tasty tasty-hunit tasty-quickcheck text transformers vector 35 | ]; 36 | benchmarkHaskellDepends = [ 37 | base bytestring containers criterion directory serialise text 38 | ]; 39 | description = "A configuration language guaranteed to terminate"; 40 | license = stdenv.lib.licenses.bsd3; 41 | } 42 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # This file has been generated -- see https://github.com/hvr/multi-ghc-travis 2 | language: c 3 | sudo: false 4 | 5 | cache: 6 | directories: 7 | - $HOME/.cabsnap 8 | - $HOME/.cabal/packages 9 | 10 | before_cache: 11 | - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log 12 | - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.tar 13 | 14 | matrix: 15 | include: 16 | - env: CABALVER=1.24 GHCVER=8.0.1 17 | compiler: ": #GHC 8.0.1" 18 | addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.1], sources: [hvr-ghc]}} 19 | 20 | before_install: 21 | - unset CC 22 | - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH 23 | 24 | install: 25 | - cabal --version 26 | - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]" 27 | - if [ -f $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz ]; 28 | then 29 | zcat $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz > 30 | $HOME/.cabal/packages/hackage.haskell.org/00-index.tar; 31 | fi 32 | - travis_retry cabal update -v 33 | - sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config 34 | - cabal install --only-dependencies --enable-tests --enable-benchmarks --dry -v > installplan.txt 35 | - sed -i -e '1,/^Resolving /d' installplan.txt; cat installplan.txt 36 | 37 | # check whether current requested install-plan matches cached package-db snapshot 38 | - if diff -u $HOME/.cabsnap/installplan.txt installplan.txt; 39 | then 40 | echo "cabal build-cache HIT"; 41 | rm -rfv .ghc; 42 | cp -a $HOME/.cabsnap/ghc $HOME/.ghc; 43 | cp -a $HOME/.cabsnap/lib $HOME/.cabsnap/share $HOME/.cabsnap/bin $HOME/.cabal/; 44 | else 45 | echo "cabal build-cache MISS"; 46 | rm -rf $HOME/.cabsnap; 47 | mkdir -p $HOME/.ghc $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin; 48 | cabal install --only-dependencies --enable-tests --enable-benchmarks; 49 | fi 50 | 51 | # snapshot package-db on cache miss 52 | - if [ ! -d $HOME/.cabsnap ]; 53 | then 54 | echo "snapshotting package-db to build-cache"; 55 | mkdir $HOME/.cabsnap; 56 | cp -a $HOME/.ghc $HOME/.cabsnap/ghc; 57 | cp -a $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin installplan.txt $HOME/.cabsnap/; 58 | fi 59 | 60 | # Here starts the actual work to be performed for the package under test; 61 | # any command which exits with a non-zero exit code causes the build to fail. 62 | script: 63 | - if [ -f configure.ac ]; then autoreconf -i; fi 64 | - cabal configure --enable-tests --enable-benchmarks -v2 # -v2 provides useful information for debugging 65 | - cabal build # this builds all libraries and executables (including tests/benchmarks) 66 | - cabal test 67 | - cabal check 68 | - cabal sdist # tests that a source-distribution can be generated 69 | 70 | # Check that the resulting source distribution can be built & installed. 71 | # If there are no other `.tar.gz` files in `dist`, this can be even simpler: 72 | # `cabal install --force-reinstalls dist/*-*.tar.gz` 73 | - SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz && 74 | (cd dist && cabal install --force-reinstalls "$SRC_TGZ") 75 | 76 | # EOF 77 | -------------------------------------------------------------------------------- /nix/hnix.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, aeson, array, base, base16-bytestring, binary 2 | , bytestring, comonad, containers, contravariant, criterion 3 | , cryptohash-md5, cryptohash-sha1, cryptohash-sha256 4 | , cryptohash-sha512, data-fix, deepseq, dependent-sum 5 | , deriving-compat, Diff, directory, exceptions, fetchgit, filepath 6 | , free, generic-random, Glob, hashable, hashing, haskeline 7 | , hedgehog, hnix-store-core, http-client, http-client-tls 8 | , http-types, interpolate, lens-family, lens-family-core 9 | , lens-family-th, logict, megaparsec, monad-control, monadlist, mtl 10 | , optparse-applicative, parser-combinators, pretty-show 11 | , prettyprinter, process, ref-tf, regex-tdfa, regex-tdfa-text 12 | , repline, scientific, semigroups, serialise, split, stdenv, syb 13 | , tasty, tasty-hedgehog, tasty-hunit, tasty-quickcheck, tasty-th 14 | , template-haskell, text, these, time, transformers 15 | , transformers-base, unix, unordered-containers, vector, xml 16 | }: 17 | mkDerivation { 18 | pname = "hnix"; 19 | version = "0.6.0"; 20 | src = fetchgit { 21 | url = "https://github.com/haskell-nix/hnix.git"; 22 | sha256 = "15g4brrl8qj5dhx54x0rc4212q11bljvv4wh5qz199p2pk7gbqwk"; 23 | rev = "3d89159ee425bf4671a6e4a610c1527d7ce251a9"; 24 | }; 25 | isLibrary = true; 26 | isExecutable = true; 27 | libraryHaskellDepends = [ 28 | aeson array base base16-bytestring binary bytestring comonad 29 | containers contravariant cryptohash-md5 cryptohash-sha1 30 | cryptohash-sha256 cryptohash-sha512 data-fix deepseq dependent-sum 31 | deriving-compat directory exceptions filepath free hashable hashing 32 | haskeline hnix-store-core http-client http-client-tls http-types 33 | interpolate lens-family lens-family-core lens-family-th logict 34 | megaparsec monad-control monadlist mtl optparse-applicative 35 | parser-combinators pretty-show prettyprinter process ref-tf 36 | regex-tdfa regex-tdfa-text scientific semigroups serialise split 37 | syb template-haskell text these time transformers transformers-base 38 | unix unordered-containers vector xml 39 | ]; 40 | executableHaskellDepends = [ 41 | aeson base base16-bytestring bytestring comonad containers 42 | cryptohash-md5 cryptohash-sha1 cryptohash-sha256 cryptohash-sha512 43 | data-fix deepseq exceptions filepath free hashing haskeline mtl 44 | optparse-applicative pretty-show prettyprinter ref-tf repline 45 | serialise template-haskell text time transformers 46 | unordered-containers 47 | ]; 48 | testHaskellDepends = [ 49 | base base16-bytestring bytestring containers cryptohash-md5 50 | cryptohash-sha1 cryptohash-sha256 cryptohash-sha512 data-fix 51 | deepseq dependent-sum Diff directory exceptions filepath 52 | generic-random Glob hashing hedgehog interpolate megaparsec mtl 53 | optparse-applicative pretty-show prettyprinter process serialise 54 | split tasty tasty-hedgehog tasty-hunit tasty-quickcheck tasty-th 55 | template-haskell text time transformers unix unordered-containers 56 | ]; 57 | benchmarkHaskellDepends = [ 58 | base base16-bytestring bytestring containers criterion 59 | cryptohash-md5 cryptohash-sha1 cryptohash-sha256 cryptohash-sha512 60 | data-fix deepseq exceptions filepath hashing mtl 61 | optparse-applicative serialise template-haskell text time 62 | transformers unordered-containers 63 | ]; 64 | homepage = "https://github.com/haskell-nix/hnix#readme"; 65 | description = "Haskell implementation of the Nix language"; 66 | license = stdenv.lib.licenses.bsd3; 67 | } 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `dhall-nix 1.1.6` 2 | 3 | This `dhall-nix` package provides a Dhall to Nix compiler. You can use this 4 | compiler to program Nix using the Dhall language. This package targets people 5 | who wish Nix had a type system. 6 | 7 | ## Quick start 8 | 9 | If you have Nix installed then you can build and run this package using: 10 | 11 | ```bash 12 | $ nix-build -A dhall-nix release.nix 13 | $ result/bin/dhall-to-nix <<< "λ(x : Bool) → x == False" 14 | x: x == false 15 | $ result/bin/dhall-to-nix <<< "{ foo = 1, bar = True }" 16 | { bar = true; foo = 1; } 17 | $ result/bin/dhall-to-nix <<< "< Left = 2 | Right : Natural >" 18 | { Left, Right }: Left 2 19 | ``` 20 | 21 | However, this package is also designed to be used directly from Nix. You can 22 | use the following `dhallToNix` utility to translate Dhall source code to the 23 | corresponding Nix expression directly within Nix: 24 | 25 | ```nix 26 | dhallToNix = code : 27 | let 28 | file = builtins.toFile "dhall-expr" code; 29 | 30 | drv = pkgs.stdenv.mkDerivation { 31 | name = "dhall-expr-as-nix"; 32 | 33 | buildCommand = '' 34 | dhall-to-nix <<< "${file}" > $out 35 | ''; 36 | 37 | buildInputs = [ pkgs.haskellPackages.dhall-nix ]; 38 | }; 39 | in 40 | import "${drv}"; 41 | ``` 42 | 43 | The above `dhallToNix` utility is now in `nixpkgs` so you can use `pkgs.dhallToNix` 44 | to transform Dhall expressions to Nix expressions 45 | 46 | ## Development status 47 | 48 | [![Build Status](https://travis-ci.org/Gabriel439/Haskell-Dhall-Nix-Library.png)](https://travis-ci.org/Gabriel439/Haskell-Dhall-Nix-Library) 49 | 50 | I don't expect this library to change unless: 51 | 52 | * ... the Dhall language changes, which is possible but not very likely 53 | * ... there are bugs, but the test suite in [release.nix](./release.nix) should 54 | protect against this 55 | 56 | ## License (BSD 3-clause) 57 | 58 | Copyright (c) 2017 Gabriel Gonzalez 59 | All rights reserved. 60 | 61 | Redistribution and use in source and binary forms, with or without modification, 62 | are permitted provided that the following conditions are met: 63 | * Redistributions of source code must retain the above copyright notice, 64 | this list of conditions and the following disclaimer. 65 | * Redistributions in binary form must reproduce the above copyright notice, 66 | this list of conditions and the following disclaimer in the documentation 67 | and/or other materials provided with the distribution. 68 | * Neither the name of Gabriel Gonzalez nor the names of other contributors 69 | may be used to endorse or promote products derived from this software 70 | without specific prior written permission. 71 | 72 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 73 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 74 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 75 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 76 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 77 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 78 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 79 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 80 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 81 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 82 | -------------------------------------------------------------------------------- /release.nix: -------------------------------------------------------------------------------- 1 | let 2 | fetchNixpkgs = import ./nix/fetchNixpkgs.nix; 3 | 4 | nixpkgs = fetchNixpkgs { 5 | rev = "1d4de0d552ae9aa66a5b8dee5fb0650a4372d148"; 6 | 7 | sha256 = "09qx58dp1kbj7cpzp8ahbqfbbab1frb12sh1qng87rybcaz0dz01"; 8 | 9 | outputSha256 = "0xpqc1fhkvvv5dv1zmas2j1q27mi7j7dgyjcdh82mlgl1q63i660"; 10 | }; 11 | 12 | mass = function: names: haskellPackagesNew: haskellPackagesOld: 13 | let 14 | toNameValue = name: { 15 | inherit name; 16 | 17 | value = function haskellPackagesOld."${name}"; 18 | }; 19 | 20 | in 21 | builtins.listToAttrs (map toNameValue names); 22 | 23 | config = { 24 | packageOverrides = pkgs: { 25 | haskellPackages = pkgs.haskellPackages.override (old: { 26 | overrides = 27 | let 28 | dontCheck = 29 | mass pkgs.haskell.lib.dontCheck [ 30 | "adjunctions" 31 | "base-orphans" 32 | "base64-bytestring" 33 | "cereal" 34 | "blaze-builder" 35 | "neat-interpolation" 36 | "pureMD5" 37 | "pem" 38 | "lens" 39 | "th-orphans" 40 | "mockery" 41 | "megaparsec" 42 | "lens-family-th" 43 | "network-uri" 44 | "invariant" 45 | "interpolate" 46 | "http-types" 47 | "parsers" 48 | "dhall" 49 | "aeson" 50 | "half" 51 | "generic-deriving" 52 | "distributive" 53 | "deriving-compat" 54 | "monad-control" 55 | "logging-facade" 56 | "bifunctors" 57 | "exceptions" 58 | "cborg-json" 59 | "cryptohash-sha512" 60 | "Diff" 61 | "hashable" 62 | "hnix" 63 | "hnix-store-core" 64 | "optparse-generic" 65 | "serialise" 66 | "SHA" 67 | "these" 68 | "unordered-containers" 69 | "vector" 70 | ]; 71 | 72 | extension = haskellPackagesNew: haskellPackagesOld: { 73 | dhall-nix = 74 | pkgs.haskell.lib.failOnAllWarnings 75 | (pkgs.haskell.lib.justStaticExecutables 76 | haskellPackagesOld.dhall-nix 77 | ); 78 | }; 79 | 80 | in 81 | pkgs.lib.fold 82 | pkgs.lib.composeExtensions 83 | (old.overrides or (_: _: {})) 84 | [ (pkgs.haskell.lib.packagesFromDirectory { directory = ./nix; }) 85 | dontCheck 86 | extension 87 | ]; 88 | } 89 | ); 90 | }; 91 | }; 92 | 93 | pkgs = 94 | import nixpkgs { inherit config; }; 95 | 96 | inherit (pkgs) dhallToNix; 97 | 98 | in 99 | { dhall-nix = pkgs.haskellPackages.dhall-nix; 100 | 101 | shell = pkgs.haskellPackages.dhall-nix.env; 102 | 103 | # Test that various Dhall to Nix conversions work 104 | tests = 105 | let 106 | testConst = dhallToNix "Type"; 107 | testLam = dhallToNix "λ(x : Bool) → x"; 108 | testPi = dhallToNix "Bool → Bool"; 109 | testApp = dhallToNix "λ(f : Bool → Bool) → λ(x : Bool) → f x"; 110 | testLet = dhallToNix "λ(b : Bool) → let x = b in x"; 111 | testAnnot = dhallToNix "True : Bool"; 112 | testBool = dhallToNix "Bool"; 113 | testBoolLit = dhallToNix "True"; 114 | testBoolAnd = dhallToNix "λ(l : Bool) → λ(r : Bool) → l && r"; 115 | testBoolOr = dhallToNix "λ(l : Bool) → λ(r : Bool) → l || r"; 116 | testBoolEQ = dhallToNix "λ(l : Bool) → λ(r : Bool) → l == r"; 117 | testBoolNE = dhallToNix "λ(l : Bool) → λ(r : Bool) → l != r"; 118 | testBoolIf = dhallToNix "λ(x : Bool) → if x then True else False"; 119 | testNatural = dhallToNix "Natural"; 120 | testNaturalLit = dhallToNix "123"; 121 | testNaturalFold = dhallToNix '' 122 | λ(x : Natural) 123 | → Natural/fold x Natural (λ(n : Natural) → 2 + n) 0 124 | ''; 125 | testNaturalBuild = dhallToNix '' 126 | λ(b : Bool) 127 | → Natural/build 128 | ( λ(natural : Type) 129 | → λ(succ : natural → natural) 130 | → λ(zero : natural) 131 | → if b then succ zero else zero 132 | ) 133 | ''; 134 | testNaturalIsZero = dhallToNix "Natural/isZero"; 135 | testNaturalEven = dhallToNix "Natural/even"; 136 | testNaturalOdd = dhallToNix "Natural/odd"; 137 | testNaturalToInteger = dhallToNix "Natural/toInteger"; 138 | testNaturalShow = dhallToNix "Natural/show"; 139 | testNaturalPlus = dhallToNix "λ(x : Natural) → λ(y : Natural) → x + y"; 140 | testNaturalTimes = dhallToNix "λ(x : Natural) → λ(y : Natural) → x * y"; 141 | testInteger = dhallToNix "Integer"; 142 | testIntegerLit = dhallToNix "+123"; 143 | testIntegerShow = dhallToNix "Integer/show"; 144 | testDouble = dhallToNix "Double"; 145 | testTextLit = dhallToNix ''"ABC"''; 146 | testInterpolation = dhallToNix ''λ(x : Text) → "ABC''${x}GHI"'' "DEF"; 147 | testTextAppend = dhallToNix "λ(x : Text) → λ(y : Text) → x ++ y"; 148 | testList = dhallToNix "List Natural"; 149 | testListLit = dhallToNix "[1, 2, 3] : List Natural"; 150 | testListAppend = dhallToNix '' 151 | λ(xs : List Natural) → λ(ys : List Natural) → xs # ys 152 | ''; 153 | testListBuild = dhallToNix '' 154 | λ(b : Bool) 155 | → List/build 156 | Natural 157 | ( λ(list : Type) 158 | → λ(cons : Natural → list → list) 159 | → λ(nil : list) 160 | → if b then cons 1 (cons 2 (cons 3 nil)) else nil 161 | ) 162 | ''; 163 | testListFold = dhallToNix '' 164 | List/fold 165 | Natural 166 | ([1, 2, 3] : List Natural) 167 | Natural 168 | ''; 169 | testListLength = dhallToNix "List/length Natural"; 170 | testListHead = dhallToNix "List/head Natural"; 171 | testListLast = dhallToNix "List/last Natural"; 172 | testListIndexed = dhallToNix "List/indexed Natural"; 173 | testListReverse = dhallToNix "List/reverse Natural"; 174 | testOptional = dhallToNix "Optional"; 175 | testOptionalLit = dhallToNix '' 176 | λ(b : Bool) 177 | → if b 178 | then ([0] : Optional Natural) 179 | else ([] : Optional Natural) 180 | ''; 181 | testOptionalFold = dhallToNix '' 182 | Optional/fold 183 | Natural 184 | ([1] : Optional Natural) 185 | Natural 186 | ''; 187 | testOptionalBuild = dhallToNix '' 188 | λ(b : Bool) 189 | → Optional/build 190 | Natural 191 | ( λ(optional : Type) 192 | → λ(just : Natural → optional) 193 | → λ(nothing : optional) 194 | → if b then just 1 else nothing 195 | ) 196 | ''; 197 | testNone = dhallToNix "None Natural"; 198 | testSome = dhallToNix "Some 4"; 199 | testRecord = dhallToNix "{}"; 200 | testRecordLit = dhallToNix "{ foo = 1, bar = True}"; 201 | testUnion = dhallToNix "< Left : Natural | Right : Bool >"; 202 | testUnionLit = dhallToNix "< Left = 2 | Right : Bool >"; 203 | testCombine = dhallToNix '' 204 | λ(x : { foo : { bar : Text } }) 205 | → λ(y : { foo : { baz : Bool } }) 206 | → x ∧ y 207 | ''; 208 | testCombineTypes = dhallToNix '' 209 | { foo : Text } ⩓ { bar : Bool, baz : Natural } 210 | ''; 211 | testMerge = dhallToNix '' 212 | λ(r : < Left : Natural | Right : Bool >) 213 | → merge 214 | { Left = Natural/isZero, Right = λ(b : Bool) → b } 215 | r : Bool 216 | ''; 217 | testField = dhallToNix "λ(r : { foo : Bool, bar : Text }) → r.foo"; 218 | testProject = dhallToNix '' 219 | λ(r : { foo : Bool, bar : Text, baz : Natural }) → r.{ foo, bar } 220 | ''; 221 | in 222 | assert (testConst == {}); 223 | assert (testLam true == true); 224 | assert (testPi == {}); 225 | assert (testApp (b : b) true == true); 226 | assert (testLet true == true); 227 | assert (testAnnot == true); 228 | assert (testBool == {}); 229 | assert (testBoolLit == true); 230 | assert (testBoolAnd true false == false); 231 | assert (testBoolOr true false == true); 232 | assert (testBoolEQ true false == false); 233 | assert (testBoolNE true false == true); 234 | assert (testBoolIf true == true); 235 | assert (testNatural == {}); 236 | assert (testNaturalLit == 123); 237 | assert (testNaturalFold 123 == 246); 238 | assert (testNaturalBuild true == 1); 239 | assert (testNaturalBuild false == 0); 240 | assert (testNaturalIsZero 0 == true); 241 | assert (testNaturalIsZero 3 == false); 242 | assert (testNaturalEven 2 == true); 243 | assert (testNaturalEven 3 == false); 244 | assert (testNaturalOdd 2 == false); 245 | assert (testNaturalToInteger 2 == 2); 246 | assert (testNaturalShow 2 == "2"); 247 | assert (testNaturalOdd 3 == true); 248 | assert (testNaturalPlus 2 3 == 5); 249 | assert (testNaturalTimes 2 3 == 6); 250 | assert (testInteger == {}); 251 | assert (testIntegerLit == 123); 252 | assert (testIntegerShow 2 == "+2"); 253 | assert (testIntegerShow (-3) == "-3"); 254 | assert (testDouble == {}); 255 | assert (testTextLit == "ABC"); 256 | assert (testInterpolation == "ABCDEFGHI"); 257 | assert (testTextAppend "ABC" "DEF" == "ABCDEF"); 258 | assert (testList == {}); 259 | assert (testListLit == [1 2 3]); 260 | assert (testListAppend [1 2 3] [4 5 6] == [1 2 3 4 5 6]); 261 | assert (testListBuild false == []); 262 | assert (testListBuild true == [1 2 3]); 263 | assert (testListFold (x : y: x + y) 0 == 6); 264 | assert (testListLength [1 2 3] == 3); 265 | assert (testListLength [] == 0); 266 | assert (testListHead [1 2 3] == 1); 267 | assert (testListHead [] == null); 268 | assert (testListLast [1 2 3] == 3); 269 | assert (testListLast [] == null); 270 | assert (testListIndexed [2 3 5] == [ 271 | { index = 0; value = 2; } 272 | { index = 1; value = 3; } 273 | { index = 2; value = 5; } 274 | ]); 275 | assert (testListReverse [1 2 3] == [3 2 1]); 276 | assert (testOptional {} == {}); 277 | assert (testOptionalLit true == 0); 278 | assert (testOptionalLit false == null); 279 | assert (testOptionalFold (n : n) 0 == 1); 280 | assert (testOptionalBuild true == 1); 281 | assert (testOptionalBuild false == null); 282 | assert (testRecord == {}); 283 | assert (testRecordLit == { foo = 1; bar = true; }); 284 | assert (testUnion == {}); 285 | assert (testUnionLit { Left = n : n == 0; Right = b : b; } == false); 286 | assert ((testCombine { foo.baz = true; } { foo.bar = "ABC"; }) == { 287 | foo = { 288 | baz = true; 289 | bar = "ABC"; 290 | }; 291 | }); 292 | assert (testCombineTypes == {}); 293 | assert (testMerge ({ Left, Right }: Left 2) == false); 294 | assert (testField { foo = true; bar = "ABC"; } == true); 295 | assert (testProject { foo = true; bar = "ABC"; baz = 1; } == { 296 | foo = true; 297 | bar = "ABC"; 298 | }); 299 | pkgs.stdenv.mkDerivation { 300 | name = "tests-pass"; 301 | 302 | buildCommand = "touch $out"; 303 | }; 304 | } 305 | -------------------------------------------------------------------------------- /src/Dhall/Nix.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveDataTypeable #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | {-# LANGUAGE OverloadedLists #-} 4 | {-# LANGUAGE QuasiQuotes #-} 5 | {-# LANGUAGE TypeFamilies #-} 6 | 7 | {-| This library only exports a single `dhallToNix` function for translating a 8 | Dhall syntax tree to a Nix syntax tree for the @hnix@ library 9 | 10 | See the @dhall@ package if you would like to transform Dhall source code 11 | into a Dhall syntax tree. Similarly, see the @hnix@ package if you would 12 | like to translate a Nix syntax tree into Nix source code. 13 | 14 | This package also provides a @dhall-to-nix@ executable which you can use to 15 | compile Dhall source code directly to Nix source code for your convenience. 16 | 17 | Any Dhall expression can be converted into an equivalent Nix expression. 18 | For example, Dhall records can be converted into Nix records: 19 | 20 | > $ dhall-to-nix <<< "{ foo = 1, bar = True }" 21 | > { bar = true; foo = 1; } 22 | 23 | ... and you can also convert Dhall functions to Nix functions, too: 24 | 25 | > $ dhall-to-nix <<< "λ(x : Bool) → x == False" 26 | > x: x == false 27 | 28 | Many Dhall expressions have a straightforward translation to Nix expressions 29 | but there are some translations that are not as obvious. The following 30 | section documents these trickier conversions: 31 | 32 | First, all Dhall types translate to an empty record: 33 | 34 | > $ dhall-to-nix <<< "Integer" 35 | > {} 36 | 37 | Polymorphic Dhall functions translate to Nix functions that ignore their 38 | type argument: 39 | 40 | > $ dhall-to-nix <<< "List/head" 41 | > t: xs: if xs == [] 42 | > then null 43 | > else builtins.head xs 44 | 45 | `Optional` values translate to @null@ if missing or the unwrapped value if 46 | present: 47 | 48 | > $ dhall-to-nix <<< "[] : Optional Integer" 49 | > null 50 | 51 | > $ dhall-to-nix <<< "[1] : Optional Integer" 52 | > 1 53 | 54 | Unions are Church-encoded: 55 | 56 | > $ dhall-to-nix <<< "< Left = True | Right : Natural >" 57 | > { Left, Right }: Left true 58 | 59 | Also, all Dhall expressions are normalized before translation to Nix: 60 | 61 | > $ dhall-to-nix <<< "True == False" 62 | > false 63 | 64 | You can use the @dhall-to-nix@ executable within Nix to assemble Nix 65 | expressions from Dhall expressions using the following @dhallToNix@ utility 66 | function: 67 | 68 | > dhallToNix = code : 69 | > let 70 | > file = builtins.toFile "dhall-expr" code; 71 | > 72 | > drv = pkgs.stdenv.mkDerivation { 73 | > name = "dhall-expr-as-nix"; 74 | > 75 | > buildCommand = '' 76 | > dhall-to-nix <<< "${file}" > $out 77 | > ''; 78 | > 79 | > buildInputs = [ pkgs.haskellPackages.dhall-nix ]; 80 | > }; 81 | > in 82 | > import "${drv}"; 83 | -} 84 | 85 | module Dhall.Nix ( 86 | -- * Dhall to Nix 87 | dhallToNix 88 | 89 | -- * Exceptions 90 | , CompileError(..) 91 | ) where 92 | 93 | import Control.Applicative (empty) 94 | import Control.Exception (Exception) 95 | import Data.Foldable (toList) 96 | import Data.Fix (Fix(..)) 97 | import Data.Traversable (for) 98 | import Data.Typeable (Typeable) 99 | import Dhall.Core (Chunks(..), Const(..), Expr(..), Var(..)) 100 | import Dhall.TypeCheck (X(..)) 101 | import Nix.Atoms (NAtom(..)) 102 | import Nix.Expr 103 | ( Antiquoted(..) 104 | , Binding(..) 105 | , NBinaryOp(..) 106 | , NExprF(..) 107 | , NKeyName(..) 108 | , NString(..) 109 | , Params(..) 110 | , (@@) 111 | , (==>) 112 | , ($+) 113 | ) 114 | 115 | import qualified Data.Text 116 | import qualified Dhall.Core 117 | import qualified Dhall.Map 118 | import qualified NeatInterpolation 119 | import qualified Nix 120 | 121 | {-| This is the exception type for all possible errors that might arise when 122 | translating the Dhall syntax tree to the Nix syntax tree 123 | -} 124 | data CompileError 125 | = CannotReferenceShadowedVariable Var 126 | -- ^ Nix does not provide a way to reference a shadowed variable 127 | deriving (Typeable) 128 | 129 | instance Show CompileError where 130 | show (CannotReferenceShadowedVariable v) = 131 | Data.Text.unpack [NeatInterpolation.text| 132 | $_ERROR: Cannot reference shadowed variable 133 | 134 | Explanation: Whenever you introduce two variables of the same name, the latter 135 | variable takes precedence: 136 | 137 | 138 | This ❰x❱ ... 139 | ⇩ 140 | ┌───────────────────────────────┐ 141 | │ λ(x : Text) → λ(x : Text) → x │ 142 | └───────────────────────────────┘ 143 | ⇧ 144 | ... refers to this ❰x❱ 145 | 146 | 147 | The former variable is "shadowed": 148 | 149 | 150 | ┌───────────────────────────────┐ 151 | │ λ(x : Text) → λ(x : Text) → x │ 152 | └───────────────────────────────┘ 153 | ⇧ 154 | This ❰x❱ is shadowed 155 | 156 | 157 | ... and Dhall lets you reference shadowed variables using the ❰@❱ notation: 158 | 159 | 160 | This ❰x❱ ... 161 | ⇩ 162 | ┌─────────────────────────────────┐ 163 | │ λ(x : Text) → λ(x : Text) → x@1 │ 164 | └─────────────────────────────────┘ 165 | ⇧ 166 | ... now refers to this ❰x❱ 167 | 168 | 169 | However, the Nix language does not let you reference shadowed variables and 170 | there is nothing analogous to ❰@❱ in Nix 171 | 172 | Your code contains the following expression: 173 | 174 | ↳ $txt 175 | 176 | ... which references a shadowed variable and therefore cannot be translated to 177 | Nix 178 | |] 179 | where 180 | txt = Dhall.Core.pretty v 181 | 182 | _ERROR :: Data.Text.Text 183 | _ERROR = "\ESC[1;31mError\ESC[0m" 184 | 185 | instance Exception CompileError 186 | 187 | {-| Convert a Dhall expression to the equivalent Nix expression 188 | 189 | >>> :set -XOverloadedStrings 190 | >>> dhallToNix (Lam "x" Natural (Lam "y" Natural (NaturalPlus "x" "y"))) 191 | Right (NAbs (Param "x") (NAbs (Param "y") (NBinary NPlus (NSym "x") (NSym "y")))) 192 | >>> fmap Nix.Pretty.prettyNix it 193 | Right x: y: x + y 194 | 195 | Precondition: You must first type-check the Dhall expression before passing 196 | the expression to `dhallToNix` 197 | -} 198 | dhallToNix :: Expr s X -> Either CompileError (Fix NExprF) 199 | dhallToNix e = loop (Dhall.Core.normalize e) 200 | where 201 | loop (Const _) = return (Fix (NSet [])) 202 | loop (Var (V a 0)) = return (Fix (NSym a)) 203 | loop (Var a ) = Left (CannotReferenceShadowedVariable a) 204 | loop (Lam a _ c) = do 205 | c' <- loop c 206 | return (Fix (NAbs (Param a) c')) 207 | loop (Pi _ _ _) = return (Fix (NSet [])) 208 | -- None needs a type to convert to an Optional 209 | loop (App None _) = do 210 | return (Fix (NConstant NNull)) 211 | loop (App a b) = do 212 | a' <- loop a 213 | b' <- loop b 214 | return (Fix (NBinary NApp a' b')) 215 | loop (Let as b) = do 216 | as' <- for as $ \a -> do 217 | val <- loop $ Dhall.Core.value a 218 | pure $ NamedVar [StaticKey $ Dhall.Core.variable a] val Nix.nullPos 219 | b' <- loop b 220 | return (Fix (NLet (toList as') b')) 221 | loop (Annot a _) = loop a 222 | loop Bool = return (Fix (NSet [])) 223 | loop (BoolLit b) = return (Fix (NConstant (NBool b))) 224 | loop (BoolAnd a b) = do 225 | a' <- loop a 226 | b' <- loop b 227 | return (Fix (NBinary NAnd a' b')) 228 | loop (BoolOr a b) = do 229 | a' <- loop a 230 | b' <- loop b 231 | return (Fix (NBinary NOr a' b')) 232 | loop (BoolEQ a b) = do 233 | a' <- loop a 234 | b' <- loop b 235 | return (Fix (NBinary NEq a' b')) 236 | loop (BoolNE a b) = do 237 | a' <- loop a 238 | b' <- loop b 239 | return (Fix (NBinary NNEq a' b')) 240 | loop (BoolIf a b c) = do 241 | a' <- loop a 242 | b' <- loop b 243 | c' <- loop c 244 | return (Fix (NIf a' b' c')) 245 | loop Natural = return (Fix (NSet [])) 246 | loop (NaturalLit n) = return (Fix (NConstant (NInt (fromIntegral n)))) 247 | loop NaturalFold = do 248 | let e0 = Fix (NBinary NMinus "n" (Fix (NConstant (NInt 1)))) 249 | let e1 = Fix (NBinary NApp (Fix (NBinary NApp (Fix (NBinary NApp "naturalFold" e0)) "t")) "succ") 250 | let e2 = Fix (NBinary NApp "succ" (Fix (NBinary NApp e1 "zero"))) 251 | let e3 = Fix (NBinary NLte "n" (Fix (NConstant (NInt 0)))) 252 | let e4 = Fix (NAbs "succ" (Fix (NAbs "zero" (Fix (NIf e3 "zero" e2))))) 253 | let e5 = Fix (NAbs "n" (Fix (NAbs "t" e4))) 254 | return (Fix (NLet [NamedVar ["naturalFold"] e5 Nix.nullPos] "naturalFold")) 255 | loop NaturalBuild = do 256 | let e0 = Fix (NBinary NPlus "n" (Fix (NConstant (NInt 1)))) 257 | let e1 = Fix (NBinary NApp (Fix (NBinary NApp "k" (Fix (NSet [])))) (Fix (NAbs "n" e0))) 258 | return (Fix (NAbs "k" (Fix (NBinary NApp e1 (Fix (NConstant (NInt 0))))))) 259 | loop NaturalIsZero = do 260 | let e0 = Fix (NBinary NEq "n" (Fix (NConstant (NInt 0)))) 261 | return (Fix (NAbs "n" e0)) 262 | loop NaturalEven = do 263 | let e0 = Fix (NBinary NMinus "n" (Fix (NConstant (NInt 2)))) 264 | let e1 = Fix (NBinary NApp "naturalEven" e0) 265 | let e2 = Fix (NBinary NNEq "n" (Fix (NConstant (NInt 1)))) 266 | let e3 = Fix (NBinary NEq "n" (Fix (NConstant (NInt 0)))) 267 | let e4 = Fix (NBinary NOr e3 (Fix (NBinary NAnd e2 e1))) 268 | let e5 = NamedVar ["naturalEven"] (Fix (NAbs "n" e4)) Nix.nullPos 269 | let e6 = Fix (NBinary NMinus (Fix (NConstant (NInt 0))) "n") 270 | let e7 = Fix (NBinary NLte "n" (Fix (NConstant (NInt 0)))) 271 | let e8 = Fix (NAbs "n" (Fix (NBinary NApp "naturalEven" (Fix (NIf e7 e6 "n"))))) 272 | return (Fix (NLet [e5] e8)) 273 | loop NaturalOdd = do 274 | let e0 = Fix (NBinary NMinus "n" (Fix (NConstant (NInt 2)))) 275 | let e1 = Fix (NBinary NApp "naturalOdd" e0) 276 | let e2 = Fix (NBinary NNEq "n" (Fix (NConstant (NInt 0)))) 277 | let e3 = Fix (NBinary NEq "n" (Fix (NConstant (NInt 1)))) 278 | let e4 = Fix (NBinary NOr e3 (Fix (NBinary NAnd e2 e1))) 279 | let e5 = NamedVar ["naturalOdd"] (Fix (NAbs "n" e4)) Nix.nullPos 280 | let e6 = Fix (NBinary NMinus (Fix (NConstant (NInt 0))) "n") 281 | let e7 = Fix (NBinary NLte "n" (Fix (NConstant (NInt 0)))) 282 | let e8 = Fix (NAbs "n" (Fix (NBinary NApp "naturalOdd" (Fix (NIf e7 e6 "n"))))) 283 | return (Fix (NLet [e5] e8)) 284 | loop NaturalShow = do 285 | return "toString" 286 | loop NaturalToInteger = do 287 | return (Fix (NAbs "n" "n")) 288 | loop (NaturalPlus a b) = do 289 | a' <- loop a 290 | b' <- loop b 291 | return (Fix (NBinary NPlus a' b')) 292 | loop (NaturalTimes a b) = do 293 | a' <- loop a 294 | b' <- loop b 295 | return (Fix (NBinary NMult a' b')) 296 | loop Integer = return (Fix (NSet [])) 297 | loop (IntegerLit n) = return (Fix (NConstant (NInt (fromIntegral n)))) 298 | loop IntegerShow = do 299 | let e0 = Fix (NBinary NApp "toString" "x") 300 | let e1 = Fix (NBinary NPlus (Fix (NStr "+")) e0) 301 | let e2 = Fix (NBinary NLte (Fix (NConstant (NInt 0))) "x") 302 | let e3 = Fix (NAbs "x" (Fix (NIf e2 e1 e0))) 303 | return e3 304 | loop IntegerToDouble = do 305 | return (Fix (NAbs "x" "x")) 306 | loop Double = return (Fix (NSet [])) 307 | loop (DoubleLit n) = return (Fix (NConstant (NFloat (realToFrac n)))) 308 | loop DoubleShow = do 309 | return "toString" 310 | loop Text = return (Fix (NSet [])) 311 | loop (TextLit (Chunks abs_ c)) = do 312 | let process (a, b) = do 313 | b' <- loop b 314 | return [Plain a, Antiquoted b'] 315 | abs' <- mapM process abs_ 316 | 317 | let chunks = concat abs' ++ [Plain c] 318 | return (Fix (NStr (DoubleQuoted chunks))) 319 | loop (TextAppend a b) = do 320 | a' <- loop a 321 | b' <- loop b 322 | return (Fix (NBinary NPlus a' b')) 323 | loop TextShow = do 324 | let from = 325 | Nix.mkList 326 | [ Nix.mkStr "\"" 327 | , Nix.mkStr "$" 328 | , Nix.mkStr "\\" 329 | -- Nix doesn't support \b and \f 330 | -- , Nix.mkStr "\b" 331 | -- , Nix.mkStr "\f" 332 | , Nix.mkStr "\n" 333 | , Nix.mkStr "\r" 334 | , Nix.mkStr "\t" 335 | ] 336 | 337 | let to = 338 | Nix.mkList 339 | [ Nix.mkStr "\\\"" 340 | , Nix.mkStr "\\u0024" 341 | , Nix.mkStr "\\\\" 342 | -- , Nix.mkStr "\\b" 343 | -- , Nix.mkStr "\\f" 344 | , Nix.mkStr "\\n" 345 | , Nix.mkStr "\\r" 346 | , Nix.mkStr "\\t" 347 | ] 348 | 349 | let replaced = "builtins.replaceStrings" @@ from @@ to @@ "t" 350 | 351 | let quoted = Nix.mkStr "\"" $+ replaced $+ Nix.mkStr "\"" 352 | 353 | return ("t" ==> quoted) 354 | loop List = return (Fix (NAbs "t" (Fix (NSet [])))) 355 | loop (ListAppend a b) = do 356 | a' <- loop a 357 | b' <- loop b 358 | return (Fix (NBinary NConcat a' b')) 359 | loop (ListLit _ bs) = do 360 | bs' <- mapM loop (toList bs) 361 | return (Fix (NList bs')) 362 | loop ListBuild = do 363 | let e0 = Fix (NBinary NApp "k" (Fix (NSet []))) 364 | let e1 = Fix (NBinary NConcat (Fix (NList ["x"])) "xs") 365 | let e2 = Fix (NBinary NApp e0 (Fix (NAbs "x" (Fix (NAbs "xs" e1))))) 366 | let e3 = Fix (NAbs "k" (Fix (NBinary NApp e2 (Fix (NList []))))) 367 | return (Fix (NAbs "t" e3)) 368 | loop ListFold = do 369 | let e0 = Fix (NBinary NApp "f" (Fix (NBinary NApp (Fix (NBinary NApp "cons" "y")) "ys"))) 370 | let e1 = Fix (NAbs "f" (Fix (NAbs "y" (Fix (NAbs "ys" e0))))) 371 | let e2 = Fix (NBinary NApp "builtins.foldl'" e1) 372 | let e3 = Fix (NBinary NApp (Fix (NBinary NApp e2 (Fix (NAbs "ys" "ys")))) "xs") 373 | let e4 = Fix (NAbs "xs" (Fix (NAbs "t" (Fix (NAbs "cons" e3))))) 374 | return (Fix (NAbs "t" e4)) 375 | loop ListLength = return (Fix (NAbs "t" "builtins.length")) 376 | loop ListHead = do 377 | let e0 = Fix (NBinary NApp "builtins.head" "xs") 378 | let e1 = Fix (NBinary NEq "xs" (Fix (NList []))) 379 | let e2 = Fix (NAbs "xs" (Fix (NIf e1 (Fix (NConstant NNull)) e0))) 380 | return (Fix (NAbs "t" e2)) 381 | loop ListLast = do 382 | let e0 = Fix (NBinary NApp "builtins.length" "xs") 383 | let e1 = Fix (NBinary NMinus e0 (Fix (NConstant (NInt 1)))) 384 | let e2 = Fix (NBinary NApp (Fix (NBinary NApp "builtins.elemAt" "xs")) e1) 385 | let e3 = Fix (NBinary NEq "xs" (Fix (NList []))) 386 | let e4 = Fix (NAbs "xs" (Fix (NIf e3 (Fix (NConstant NNull)) e2))) 387 | return (Fix (NAbs "t" e4)) 388 | loop ListIndexed = do 389 | let e0 = Fix (NBinary NApp "builtins.length" "xs") 390 | let e1 = Fix (NBinary NApp (Fix (NBinary NApp "builtins.elemAt" "xs")) "i") 391 | let e2 = 392 | [ NamedVar ["index"] "i" Nix.nullPos 393 | , NamedVar ["value"] e1 Nix.nullPos 394 | ] 395 | let e3 = Fix (NBinary NApp "builtins.genList" (Fix (NAbs "i" (Fix (NSet e2))))) 396 | return (Fix (NAbs "t" (Fix (NAbs "xs" (Fix (NBinary NApp e3 e0)))))) 397 | loop ListReverse = do 398 | let e0 = Fix (NBinary NMinus "n" "i") 399 | let e1 = Fix (NBinary NMinus e0 (Fix (NConstant (NInt 1)))) 400 | let e2 = Fix (NBinary NApp (Fix (NBinary NApp "builtins.elemAt" "xs")) e1) 401 | let e3 = Fix (NBinary NApp "builtins.genList" (Fix (NAbs "i" e2))) 402 | let e4 = Fix (NBinary NApp e3 "n") 403 | let e5 = Fix (NBinary NApp "builtins.length" "xs") 404 | let e6 = Fix (NAbs "xs" (Fix (NLet [NamedVar ["n"] e5 Nix.nullPos] e4))) 405 | return (Fix (NAbs "t" e6)) 406 | loop Optional = return (Fix (NAbs "t" (Fix (NSet [])))) 407 | loop (OptionalLit _ b) = 408 | case b of 409 | Nothing -> return (Fix (NConstant NNull)) 410 | Just c -> loop c 411 | loop (Some a) = loop a 412 | loop None = return (Fix (NConstant NNull)) 413 | loop OptionalFold = do 414 | let e0 = Fix (NBinary NEq "x" (Fix (NConstant NNull))) 415 | let e1 = Fix (NIf e0 "nothing" (Fix (NBinary NApp "just" "x"))) 416 | let e2 = Fix (NAbs "t" (Fix (NAbs "just" (Fix (NAbs "nothing" e1))))) 417 | return (Fix (NAbs "t" (Fix (NAbs "x" e2)))) 418 | loop OptionalBuild = do 419 | let e0 = Pi "nothing" "optional" "optional" 420 | let e1 = Pi "just" (Pi "_" "a" "optional") e0 421 | let e2 = Pi "optional" (Const Type) e1 422 | let e3 = OptionalLit "a" empty 423 | let e4 = Lam "x" "a" (OptionalLit "a" (pure "x")) 424 | let e5 = App (App (App "f" (App Optional "a")) e4) e3 425 | loop (Lam "a" (Const Type) (Lam "f" e2 e5)) 426 | loop (Record _) = return (Fix (NSet [])) 427 | loop (RecordLit a) = do 428 | a' <- traverse loop a 429 | let a'' = do 430 | (k, v) <- Dhall.Map.toList a' 431 | return (NamedVar [StaticKey k] v Nix.nullPos) 432 | return (Fix (NSet a'')) 433 | loop (Union _) = return (Fix (NSet [])) 434 | loop (UnionLit k v kts) = do 435 | v' <- loop v 436 | let e0 = do 437 | k' <- k : Dhall.Map.keys kts 438 | return (k', Nothing) 439 | let e2 = Fix (NBinary NApp (Fix (NSym k)) v') 440 | return (Fix (NAbs (ParamSet e0 False Nothing) e2)) 441 | loop (Combine a b) = do 442 | a' <- loop a 443 | b' <- loop b 444 | let e0 = Fix (NBinary NApp (Fix (NBinary NApp "map" "toKeyVals")) "ks") 445 | let e1 = Fix (NBinary NApp "builtins.concatLists" e0) 446 | let e2 = Fix (NBinary NApp "builtins.listToAttrs" e1) 447 | 448 | let defL = Fix (NBinary NApp (Fix (NBinary NApp "builtins.hasAttr" "k")) "kvsL") 449 | let defR = Fix (NBinary NApp (Fix (NBinary NApp "builtins.hasAttr" "k")) "kvsR") 450 | let valL = Fix (NBinary NApp (Fix (NBinary NApp "builtins.getAttr" "k")) "kvsL") 451 | let valR = Fix (NBinary NApp (Fix (NBinary NApp "builtins.getAttr" "k")) "kvsR") 452 | 453 | let empty_ = Fix (NList []) 454 | let toNameValue v = 455 | let bindings = 456 | [ NamedVar ["name" ] "k" Nix.nullPos 457 | , NamedVar ["value"] v Nix.nullPos 458 | ] 459 | in Fix (NList [Fix (NSet bindings)]) 460 | 461 | let e3 = Fix (NBinary NApp (Fix (NBinary NApp "combine" valL)) valR) 462 | let e4 = Fix (NBinary NApp "builtins.isAttrs" valL) 463 | let e5 = Fix (NBinary NApp "builtins.isAttrs" valR) 464 | let e6 = Fix (NBinary NAnd e4 e5) 465 | let e7 = Fix (NIf e6 (toNameValue e3) (toNameValue valR)) 466 | let e8 = Fix (NIf defR e7 (toNameValue valL)) 467 | let e9 = Fix (NIf defR (toNameValue valR) empty_) 468 | let toKeyVals = Fix (NAbs "k" (Fix (NIf defL e8 e9))) 469 | 470 | let ksL = Fix (NBinary NApp "builtins.attrNames" "kvsL") 471 | let ksR = Fix (NBinary NApp "builtins.attrNames" "kvsR") 472 | let ks = Fix (NBinary NConcat ksL ksR) 473 | 474 | let e10 = 475 | [ NamedVar ["ks" ] ks Nix.nullPos 476 | , NamedVar ["toKeyVals"] toKeyVals Nix.nullPos 477 | ] 478 | let combine = Fix (NAbs "kvsL" (Fix (NAbs "kvsR" (Fix (NLet e10 e2))))) 479 | 480 | let e11 = Fix (NBinary NApp (Fix (NBinary NApp "combine" a')) b') 481 | return (Fix (NLet [NamedVar ["combine"] combine Nix.nullPos] e11)) 482 | loop (CombineTypes _ _) = return (Fix (NSet [])) 483 | loop (Merge a b _) = do 484 | a' <- loop a 485 | b' <- loop b 486 | return (Fix (NBinary NApp b' a')) 487 | loop (Prefer a b) = do 488 | a' <- loop a 489 | b' <- loop b 490 | return (Fix (NBinary NUpdate a' b')) 491 | loop (Field a b) = do 492 | a' <- loop a 493 | return (Fix (NSelect a' [StaticKey b] Nothing)) 494 | loop (Project a b) = do 495 | a' <- loop a 496 | let b' = fmap StaticKey (toList b) 497 | return (Fix (NSet [Inherit (Just a') b' Nix.nullPos])) 498 | loop (ImportAlt a _) = loop a 499 | loop (Note _ b) = loop b 500 | loop (Embed (X x)) = x 501 | --------------------------------------------------------------------------------