update fork from master
This commit is contained in:
commit
ea3b675f28
|
@ -1,7 +1,17 @@
|
|||
/.history
|
||||
/Setup
|
||||
/dist/
|
||||
/nix-test-eval*
|
||||
/nix/
|
||||
TAGS
|
||||
ctags
|
||||
dist-newstyle
|
||||
result
|
||||
|
||||
.cabal-sandbox/
|
||||
.git
|
||||
Dockerfile
|
||||
Makefile
|
||||
README.md
|
||||
cabal.sandbox.config
|
||||
.cabal-sandbox/
|
||||
hnix.cabal
|
||||
|
|
11
.gitignore
vendored
11
.gitignore
vendored
|
@ -1,9 +1,12 @@
|
|||
/Setup
|
||||
/dist/
|
||||
**/*~
|
||||
**/#*
|
||||
**/.#*
|
||||
result
|
||||
/.history
|
||||
/Setup
|
||||
/dist/
|
||||
/nix-test-eval*
|
||||
/nix/
|
||||
TAGS
|
||||
ctags
|
||||
dist-newstyle
|
||||
/.history
|
||||
result
|
||||
|
|
21
.travis.yml
21
.travis.yml
|
@ -10,30 +10,27 @@ language: nix
|
|||
git:
|
||||
depth: 1
|
||||
|
||||
install:
|
||||
- nix-shell --argstr compiler ghc822 --run true
|
||||
- nix-shell --argstr compiler ghc842 --run true
|
||||
|
||||
env:
|
||||
global:
|
||||
- NIXPKGS_TESTS=yes
|
||||
- MATCHING_TESTS=yes
|
||||
matrix:
|
||||
- GHCVERSION=ghc822 STRICT=true TRACING=false PROFILING=false
|
||||
- GHCVERSION=ghc822 STRICT=true TRACING=true PROFILING=false
|
||||
- GHCVERSION=ghc822 STRICT=true TRACING=true PROFILING=true
|
||||
- GHCVERSION=ghc842 STRICT=false TRACING=false PROFILING=false
|
||||
- GHCVERSION=ghc842 STRICT=false TRACING=true PROFILING=false
|
||||
- GHCVERSION=ghc842 STRICT=false TRACING=true PROFILING=true
|
||||
- GHCVERSION=ghc802 STRICT=false TRACING=false
|
||||
- GHCVERSION=ghc802 STRICT=false TRACING=true
|
||||
- GHCVERSION=ghc822 STRICT=true TRACING=false
|
||||
- GHCVERSION=ghc822 STRICT=true TRACING=true
|
||||
- GHCVERSION=ghc843 STRICT=false TRACING=false
|
||||
- GHCVERSION=ghc843 STRICT=false TRACING=true
|
||||
- GHCVERSION=ghcjs
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- env: GHCVERSION=ghc842 STRICT=true
|
||||
- env: GHCVERSION=ghcjs
|
||||
exclude:
|
||||
- env: GHCVERSION=ghc822 STRICT=false
|
||||
|
||||
script:
|
||||
- nix-build --argstr compiler $GHCVERSION --arg doProfiling $PROFILING --arg doTracing $TRACING --arg doStrict $STRICT
|
||||
- bash -xe build.sh
|
||||
|
||||
branches:
|
||||
only:
|
||||
|
|
|
@ -11,6 +11,4 @@ RUN nix-env -f '<nixpkgs>' -i gnutar gzip && \
|
|||
nix-shell -Q -j2 --run true
|
||||
|
||||
COPY . /tmp/build
|
||||
RUN nix-env -f . -i hnix
|
||||
|
||||
CMD ["/root/.nix-profile/bin/hnix"]
|
||||
RUN bash -xe build.sh
|
||||
|
|
24
README.md
24
README.md
|
@ -2,6 +2,7 @@
|
|||
|
||||
[![Build Status](https://api.travis-ci.org/haskell-nix/hnix.svg)](https://travis-ci.org/haskell-nix/hnix)
|
||||
[![Chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/haskell-nix/Lobby)
|
||||
<sup>([Hackage Matrix Builder](https://matrix.hackage.haskell.org/package/hnix))</sup>
|
||||
|
||||
Haskell parser, evaluator and type checker for the Nix language.
|
||||
|
||||
|
@ -21,7 +22,9 @@ $ cabal configure --enable-tests
|
|||
$ cabal build
|
||||
$ cabal test
|
||||
# To run all of the tests, which takes up to a minute:
|
||||
$ LANGUAGE_TESTS=yes NIXPKGS_TESTS=yes cabal test
|
||||
$ env ALL_TESTS=yes cabal test
|
||||
# To run only specific tests (see `tests/Main.hs` for a list)
|
||||
$ env NIXPKGS_TESTS=yes PRETTY_TESTS=yes cabal test
|
||||
$ ./dist/build/hnix/hnix --help
|
||||
```
|
||||
|
||||
|
@ -44,8 +47,8 @@ To build `hnix` for debugging, and with full tracing output and stack traces,
|
|||
use:
|
||||
|
||||
```
|
||||
$ nix-shell --arg doProfiling true
|
||||
$ cabal configure --enable-tests --enable-profiling --flags=tracing
|
||||
$ nix-shell
|
||||
$ cabal configure --enable-tests --enable-profiling --flags=profiling --flags=tracing
|
||||
$ cabal build
|
||||
$ ./dist/build/hnix/hnix -v5 --trace <args> +RTS -xc
|
||||
```
|
||||
|
@ -69,12 +72,23 @@ $ cabal bench
|
|||
To build `hnix` with profiling enabled:
|
||||
|
||||
```
|
||||
$ nix-shell --arg doProfiling true
|
||||
$ cabal configure --enable-tests --enable-profiling
|
||||
$ nix-shell
|
||||
$ cabal configure --enable-tests --enable-profiling --flags=profiling
|
||||
$ cabal build
|
||||
$ ./dist/build/hnix/hnix <args> +RTS -p
|
||||
```
|
||||
|
||||
## Building with GHCJS
|
||||
|
||||
From the project root directory, run:
|
||||
|
||||
```
|
||||
$ NIX_CONF_DIR=$PWD/ghcjs nix-build ghcjs
|
||||
```
|
||||
|
||||
This will build an `hnix` library that can be linked to your GHCJS
|
||||
application.
|
||||
|
||||
## How you can help
|
||||
|
||||
If you're looking for a way to help out, try taking a look
|
||||
|
|
17
build.sh
Executable file
17
build.sh
Executable file
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash -xe
|
||||
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
GHCVERSION=${GHCVERSION:-ghc822}
|
||||
STRICT=${STRICT:-false}
|
||||
TRACING=${TRACING:-false}
|
||||
|
||||
if [ "$GHCVERSION" = "ghcjs" ]; then
|
||||
nix-build --substituters 'https://nixcache.reflex-frp.org?trusted=1' ghcjs
|
||||
else
|
||||
nix-build \
|
||||
--argstr compiler $GHCVERSION \
|
||||
--arg doTracing $TRACING \
|
||||
--arg doStrict $STRICT
|
||||
fi
|
121
default.nix
121
default.nix
|
@ -1,71 +1,88 @@
|
|||
{ compiler ? "ghc822" # "ghc842" also works
|
||||
, doProfiling ? false
|
||||
{ compiler ? "ghc822"
|
||||
|
||||
, doBenchmark ? false
|
||||
, doTracing ? false
|
||||
, doStrict ? false
|
||||
, rev ? "255a833e841628c0b834575664eae373e28cdc27"
|
||||
, sha256 ? "022xm1pf4fpjjy69g7qz6rpqnwpjcy1l0vj49m8xmgn553cs42ch"
|
||||
# , nixpkgs ? import ((import <nixpkgs> {}).fetchFromGitHub {
|
||||
# owner = "NixOS"; repo = "nixpkgs"; inherit rev sha256; }) {
|
||||
, nixpkgs ? import (builtins.fetchTarball {
|
||||
url = "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz";
|
||||
inherit sha256; }) {
|
||||
config.allowUnfree = true;
|
||||
config.allowBroken = false;
|
||||
}
|
||||
|
||||
, rev ? "49bdae006e66e70ad3245a463edc01b5749250d3"
|
||||
, sha256 ? "1ijsifmap47nfzg0spny94lmj66y3x3x8i6vs471bnjamka3dx8p"
|
||||
, pkgs ?
|
||||
if builtins.compareVersions builtins.nixVersion "2.0" < 0
|
||||
then abort "hnix requires at least nix 2.0"
|
||||
else import (builtins.fetchTarball {
|
||||
url = "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz";
|
||||
inherit sha256; }) {
|
||||
config.allowUnfree = true;
|
||||
config.allowBroken = false;
|
||||
}
|
||||
, returnShellEnv ? pkgs.lib.inNixShell
|
||||
, mkDerivation ? null
|
||||
}:
|
||||
|
||||
let inherit (nixpkgs) pkgs;
|
||||
|
||||
haskellPackages = pkgs.haskell.packages.${compiler}.override {
|
||||
overrides = with pkgs.haskell.lib; self: super: rec {
|
||||
serialise = dontCheck super.serialise;
|
||||
|
||||
compact =
|
||||
if compiler == "ghc842"
|
||||
then doJailbreak super.compact
|
||||
else super.compact;
|
||||
|
||||
ghc-datasize =
|
||||
if doProfiling
|
||||
then null
|
||||
else pkgs.haskell.lib.overrideCabal super.ghc-datasize (attrs: {
|
||||
enableLibraryProfiling = false;
|
||||
enableExecutableProfiling = false;
|
||||
});
|
||||
|
||||
ghc-heap-view =
|
||||
if doProfiling
|
||||
then null
|
||||
else pkgs.haskell.lib.overrideCabal super.ghc-heap-view (attrs: {
|
||||
enableLibraryProfiling = false;
|
||||
enableExecutableProfiling = false;
|
||||
});
|
||||
};
|
||||
};
|
||||
let haskellPackages = pkgs.haskell.packages.${compiler};
|
||||
|
||||
in haskellPackages.developPackage {
|
||||
root = ./.;
|
||||
|
||||
source-overrides = {
|
||||
};
|
||||
overrides = with pkgs.haskell.lib; self: super: {
|
||||
megaparsec = super.megaparsec_6_5_0;
|
||||
}
|
||||
//
|
||||
(if compiler == "ghc802"
|
||||
then {
|
||||
concurrent-output = doJailbreak super.concurrent-output;
|
||||
}
|
||||
else {})
|
||||
//
|
||||
(if compiler == "ghcjs" then {} else
|
||||
{
|
||||
cryptohash-md5 = doJailbreak super.cryptohash-md5;
|
||||
cryptohash-sha1 = doJailbreak super.cryptohash-sha1;
|
||||
cryptohash-sha256 = doJailbreak super.cryptohash-sha256;
|
||||
cryptohash-sha512 = doJailbreak super.cryptohash-sha512;
|
||||
serialise = dontCheck super.serialise;
|
||||
|
||||
ghc-datasize =
|
||||
overrideCabal super.ghc-datasize (attrs: {
|
||||
enableLibraryProfiling = false;
|
||||
enableExecutableProfiling = false;
|
||||
});
|
||||
|
||||
ghc-heap-view =
|
||||
overrideCabal super.ghc-heap-view (attrs: {
|
||||
enableLibraryProfiling = false;
|
||||
enableExecutableProfiling = false;
|
||||
});
|
||||
});
|
||||
|
||||
source-overrides =
|
||||
if compiler == "ghc802"
|
||||
then {
|
||||
lens-family-core = "1.2.1";
|
||||
lens-family = "1.2.1";
|
||||
hspec-discover = "2.5.5";
|
||||
}
|
||||
else {};
|
||||
|
||||
modifier = drv: pkgs.haskell.lib.overrideCabal drv (attrs: {
|
||||
testHaskellDepends = attrs.testHaskellDepends ++
|
||||
[
|
||||
pkgs.nix
|
||||
haskellPackages.hpack
|
||||
# haskellPackages.cabal-install
|
||||
];
|
||||
[ pkgs.nix
|
||||
|
||||
enableLibraryProfiling = doProfiling;
|
||||
enableExecutableProfiling = doProfiling;
|
||||
# Use the same version of hpack no matter what the compiler version
|
||||
# is, so that we know exactly what the contents of the generated
|
||||
# .cabal file will be. Otherwise, Travis may error out claiming that
|
||||
# the cabal file needs to be updated because the result is different
|
||||
# that the version we committed to Git.
|
||||
pkgs.haskell.packages.ghc822.hpack
|
||||
pkgs.haskell.packages.ghc822.criterion
|
||||
];
|
||||
|
||||
inherit doBenchmark;
|
||||
|
||||
configureFlags =
|
||||
pkgs.stdenv.lib.optional doTracing "--flags=tracing"
|
||||
++ pkgs.stdenv.lib.optional doProfiling "--flags=profiling"
|
||||
++ pkgs.stdenv.lib.optional doStrict "--ghc-options=-Werror";
|
||||
pkgs.stdenv.lib.optional doTracing "--flags=tracing"
|
||||
++ pkgs.stdenv.lib.optional doStrict "--ghc-options=-Werror";
|
||||
});
|
||||
|
||||
inherit returnShellEnv;
|
||||
}
|
||||
|
|
71
ghcjs/default.nix
Normal file
71
ghcjs/default.nix
Normal file
|
@ -0,0 +1,71 @@
|
|||
{ rpRef ? "ea3c9a1536a987916502701fb6d319a880fdec96" }:
|
||||
|
||||
let rp = builtins.fetchTarball "https://github.com/reflex-frp/reflex-platform/archive/${rpRef}.tar.gz";
|
||||
|
||||
in
|
||||
(import rp {}).project ({ pkgs, ... }:
|
||||
with pkgs.haskell.lib; {
|
||||
name = "hnix-ghcjs";
|
||||
overrides = self: super:
|
||||
let guardGhcjs = p: if self.ghc.isGhcjs or false then null else p;
|
||||
in {
|
||||
cryptohash-md5 = guardGhcjs super.cryptohash-md5;
|
||||
cryptohash-sha1 = guardGhcjs super.cryptohash-sha1;
|
||||
cryptohash-sha256 = guardGhcjs super.cryptohash-sha256;
|
||||
cryptohash-sha512 = guardGhcjs super.cryptohash-sha512;
|
||||
hashing = super.hashing;
|
||||
haskeline = guardGhcjs super.haskeline;
|
||||
serialise = doJailbreak super.serialise;
|
||||
|
||||
Glob = guardGhcjs super.Glob;
|
||||
criterion = guardGhcjs super.criterion;
|
||||
pretty-show = guardGhcjs super.pretty;
|
||||
repline = guardGhcjs super.repline;
|
||||
tasty = guardGhcjs super.tasty;
|
||||
tasty-hunit = guardGhcjs super.tasty;
|
||||
tasty-th = guardGhcjs super.tasty;
|
||||
unix = guardGhcjs super.unix;
|
||||
|
||||
interpolate = self.callCabal2nix "interpolate" (pkgs.fetchFromGitHub {
|
||||
owner = "sol";
|
||||
repo = "interpolate";
|
||||
rev = "2d654444365805458e0310d461b3ecd2826977ff";
|
||||
sha256 = "01g88j6qv33r6j4yl6yisr9sk3kcvgp81z6qmhr94ka8z45raii9";
|
||||
}) {};
|
||||
lens-family-th = self.callCabal2nix "lens-family-th" (pkgs.fetchFromGitHub {
|
||||
owner = "DanBurton";
|
||||
repo = "lens-family-th";
|
||||
rev = "483be4d5b53cc6253e3926623c3aa9334c53debc";
|
||||
sha256 = "099dp4f1wwarvhwgnm4nhymnnwlqgrsgrfd8ch6dwmy6myzv2dij";
|
||||
}) {};
|
||||
megaparsec = dontCheck (self.callCabal2nix "megaparsec" (pkgs.fetchFromGitHub {
|
||||
owner = "mrkkrp";
|
||||
repo = "megaparsec";
|
||||
rev = "7b271a5edc1af59fa435a705349310cfdeaaa7e9";
|
||||
sha256 = "0415z18gl8dgms57rxzp870dpz7rcqvy008wrw5r22xw8qq0s13c";
|
||||
}) {});
|
||||
parser-combinators = self.callCabal2nix "parser-combinators" (pkgs.fetchFromGitHub {
|
||||
owner = "mrkkrp";
|
||||
repo = "parser-combinators";
|
||||
rev = "dd6599224fe7eb224477ef8e9269602fb6b79fe0";
|
||||
sha256 = "11cpfzlb6vl0r5i7vbhp147cfxds248fm5xq8pwxk92d1f5g9pxm";
|
||||
}) {};
|
||||
# Should be callHackage, but it gives an error "found zero or more than one cabal file"
|
||||
# unordered-containers = pkgs.haskellPackages.callHackage "unordered-containers" "0.2.9.0" {};
|
||||
unordered-containers = self.callCabal2nix "unordered-containers" (pkgs.fetchFromGitHub {
|
||||
owner = "tibbe";
|
||||
repo = "unordered-containers";
|
||||
rev = "0a6b84ec103e28b73458f385ef846a7e2d3ea42f";
|
||||
sha256 = "128q8k4py2wr1v0gmyvqvzikk6sksl9aqj0lxzf46763lis8x9my";
|
||||
}) {};
|
||||
};
|
||||
packages = {
|
||||
hnix = ../.;
|
||||
};
|
||||
|
||||
shells = {
|
||||
# ghc = [ "hnix" ];
|
||||
ghcjs = [ "hnix" ];
|
||||
};
|
||||
|
||||
})
|
2
ghcjs/nix.conf
Normal file
2
ghcjs/nix.conf
Normal file
|
@ -0,0 +1,2 @@
|
|||
binary-caches = https://nixcache.reflex-frp.org https://cache.nixos.org/
|
||||
binary-cache-public-keys = ryantrinkle.com-1:JJiAKaRv9mWgpVAz8dwewnZe0AzzEAzPkagE9SP5NWI= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=
|
535
hnix.cabal
535
hnix.cabal
|
@ -2,15 +2,15 @@
|
|||
--
|
||||
-- see: https://github.com/sol/hpack
|
||||
--
|
||||
-- hash: ee15abd2881ed4220e92355a685896317f421697cd97d7b5d384ec57662c8d44
|
||||
-- hash: ba0f61f8a049f6970ff03fd924cfed6fc1251eceb90547c1be8051226c453632
|
||||
|
||||
name: hnix
|
||||
version: 0.5.0
|
||||
version: 0.5.2
|
||||
synopsis: Haskell implementation of the Nix language
|
||||
description: Haskell implementation of the Nix language.
|
||||
category: System, Data, Nix
|
||||
homepage: https://github.com/jwiegley/hnix#readme
|
||||
bug-reports: https://github.com/jwiegley/hnix/issues
|
||||
homepage: https://github.com/haskell-nix/hnix#readme
|
||||
bug-reports: https://github.com/haskell-nix/hnix/issues
|
||||
author: John Wiegley
|
||||
maintainer: johnw@newartisans.com
|
||||
license: BSD3
|
||||
|
@ -19,11 +19,415 @@ build-type: Simple
|
|||
cabal-version: >= 1.10
|
||||
|
||||
extra-source-files:
|
||||
data/let-comments-multiline.nix
|
||||
data/let-comments.nix
|
||||
data/let.nix
|
||||
data/nix/bootstrap.sh
|
||||
data/nix/config/config.guess
|
||||
data/nix/config/config.sub
|
||||
data/nix/config/install-sh
|
||||
data/nix/configure.ac
|
||||
data/nix/COPYING
|
||||
data/nix/corepkgs/buildenv.nix
|
||||
data/nix/corepkgs/config.nix.in
|
||||
data/nix/corepkgs/derivation.nix
|
||||
data/nix/corepkgs/fetchurl.nix
|
||||
data/nix/corepkgs/imported-drv-to-derivation.nix
|
||||
data/nix/corepkgs/local.mk
|
||||
data/nix/corepkgs/unpack-channel.nix
|
||||
data/nix/local.mk
|
||||
data/nix/maintainers/upload-release.pl
|
||||
data/nix/Makefile
|
||||
data/nix/Makefile.config.in
|
||||
data/nix/mk/clean.mk
|
||||
data/nix/mk/dist.mk
|
||||
data/nix/mk/functions.mk
|
||||
data/nix/mk/install.mk
|
||||
data/nix/mk/jars.mk
|
||||
data/nix/mk/lib.mk
|
||||
data/nix/mk/libraries.mk
|
||||
data/nix/mk/patterns.mk
|
||||
data/nix/mk/programs.mk
|
||||
data/nix/mk/README.md
|
||||
data/nix/mk/templates.mk
|
||||
data/nix/mk/tests.mk
|
||||
data/nix/mk/tracing.mk
|
||||
data/nix/nix.spec.in
|
||||
data/nix/perl/configure.ac
|
||||
data/nix/perl/lib/Nix/Config.pm.in
|
||||
data/nix/perl/lib/Nix/CopyClosure.pm
|
||||
data/nix/perl/lib/Nix/Manifest.pm
|
||||
data/nix/perl/lib/Nix/SSH.pm
|
||||
data/nix/perl/lib/Nix/Store.pm
|
||||
data/nix/perl/lib/Nix/Store.xs
|
||||
data/nix/perl/lib/Nix/Utils.pm
|
||||
data/nix/perl/local.mk
|
||||
data/nix/perl/Makefile
|
||||
data/nix/perl/Makefile.config.in
|
||||
data/nix/perl/MANIFEST
|
||||
data/nix/README.md
|
||||
data/nix/release-common.nix
|
||||
data/nix/release.nix
|
||||
data/nix/scripts/install-darwin-multi-user.sh
|
||||
data/nix/scripts/install-multi-user.sh
|
||||
data/nix/scripts/install-nix-from-closure.sh
|
||||
data/nix/scripts/install-systemd-multi-user.sh
|
||||
data/nix/scripts/local.mk
|
||||
data/nix/scripts/nix-http-export.cgi.in
|
||||
data/nix/scripts/nix-profile-daemon.sh.in
|
||||
data/nix/scripts/nix-profile.sh.in
|
||||
data/nix/scripts/nix-reduce-build.in
|
||||
data/nix/shell.nix
|
||||
data/nix/tests/add.sh
|
||||
data/nix/tests/binary-cache.sh
|
||||
data/nix/tests/brotli.sh
|
||||
data/nix/tests/build-dry.sh
|
||||
data/nix/tests/build-hook.nix
|
||||
data/nix/tests/build-remote.sh
|
||||
data/nix/tests/case-hack.sh
|
||||
data/nix/tests/case.nar
|
||||
data/nix/tests/check-refs.nix
|
||||
data/nix/tests/check-refs.sh
|
||||
data/nix/tests/check-reqs.nix
|
||||
data/nix/tests/check-reqs.sh
|
||||
data/nix/tests/check.nix
|
||||
data/nix/tests/check.sh
|
||||
data/nix/tests/common.sh.in
|
||||
data/nix/tests/config.nix
|
||||
data/nix/tests/dependencies.builder0.sh
|
||||
data/nix/tests/dependencies.builder1.sh
|
||||
data/nix/tests/dependencies.builder2.sh
|
||||
data/nix/tests/dependencies.nix
|
||||
data/nix/tests/dependencies.sh
|
||||
data/nix/tests/dump-db.sh
|
||||
data/nix/tests/export-graph.nix
|
||||
data/nix/tests/export-graph.sh
|
||||
data/nix/tests/export.sh
|
||||
data/nix/tests/fetchGit.sh
|
||||
data/nix/tests/fetchMercurial.sh
|
||||
data/nix/tests/fetchurl.sh
|
||||
data/nix/tests/filter-source.nix
|
||||
data/nix/tests/filter-source.sh
|
||||
data/nix/tests/fixed.builder1.sh
|
||||
data/nix/tests/fixed.builder2.sh
|
||||
data/nix/tests/fixed.nix
|
||||
data/nix/tests/fixed.sh
|
||||
data/nix/tests/gc-concurrent.builder.sh
|
||||
data/nix/tests/gc-concurrent.nix
|
||||
data/nix/tests/gc-concurrent.sh
|
||||
data/nix/tests/gc-concurrent2.builder.sh
|
||||
data/nix/tests/gc-runtime.nix
|
||||
data/nix/tests/gc-runtime.sh
|
||||
data/nix/tests/gc.sh
|
||||
data/nix/tests/hash-check.nix
|
||||
data/nix/tests/hash.sh
|
||||
data/nix/tests/import-derivation.nix
|
||||
data/nix/tests/import-derivation.sh
|
||||
data/nix/tests/init.sh
|
||||
data/nix/tests/install-darwin.sh
|
||||
data/nix/tests/lang.sh
|
||||
data/nix/tests/lang/data
|
||||
data/nix/tests/lang/dir1/a.nix
|
||||
data/nix/tests/lang/dir2/a.nix
|
||||
data/nix/tests/lang/dir2/b.nix
|
||||
data/nix/tests/lang/dir3/a.nix
|
||||
data/nix/tests/lang/dir3/b.nix
|
||||
data/nix/tests/lang/dir3/c.nix
|
||||
data/nix/tests/lang/dir4/a.nix
|
||||
data/nix/tests/lang/dir4/c.nix
|
||||
data/nix/tests/lang/eval-fail-abort.nix
|
||||
data/nix/tests/lang/eval-fail-antiquoted-path.nix
|
||||
data/nix/tests/lang/eval-fail-assert.nix
|
||||
data/nix/tests/lang/eval-fail-bad-antiquote-1.nix
|
||||
data/nix/tests/lang/eval-fail-bad-antiquote-2.nix
|
||||
data/nix/tests/lang/eval-fail-bad-antiquote-3.nix
|
||||
data/nix/tests/lang/eval-fail-blackhole.nix
|
||||
data/nix/tests/lang/eval-fail-deepseq.nix
|
||||
data/nix/tests/lang/eval-fail-missing-arg.nix
|
||||
data/nix/tests/lang/eval-fail-path-slash.nix
|
||||
data/nix/tests/lang/eval-fail-remove.nix
|
||||
data/nix/tests/lang/eval-fail-scope-5.nix
|
||||
data/nix/tests/lang/eval-fail-seq.nix
|
||||
data/nix/tests/lang/eval-fail-substring.nix
|
||||
data/nix/tests/lang/eval-fail-to-path.nix
|
||||
data/nix/tests/lang/eval-fail-undeclared-arg.nix
|
||||
data/nix/tests/lang/eval-okay-any-all.exp
|
||||
data/nix/tests/lang/eval-okay-any-all.nix
|
||||
data/nix/tests/lang/eval-okay-arithmetic.exp
|
||||
data/nix/tests/lang/eval-okay-arithmetic.nix
|
||||
data/nix/tests/lang/eval-okay-attrnames.exp
|
||||
data/nix/tests/lang/eval-okay-attrnames.nix
|
||||
data/nix/tests/lang/eval-okay-attrs.exp
|
||||
data/nix/tests/lang/eval-okay-attrs.nix
|
||||
data/nix/tests/lang/eval-okay-attrs2.exp
|
||||
data/nix/tests/lang/eval-okay-attrs2.nix
|
||||
data/nix/tests/lang/eval-okay-attrs3.exp
|
||||
data/nix/tests/lang/eval-okay-attrs3.nix
|
||||
data/nix/tests/lang/eval-okay-attrs4.exp
|
||||
data/nix/tests/lang/eval-okay-attrs4.nix
|
||||
data/nix/tests/lang/eval-okay-attrs5.exp
|
||||
data/nix/tests/lang/eval-okay-attrs5.nix
|
||||
data/nix/tests/lang/eval-okay-autoargs.exp
|
||||
data/nix/tests/lang/eval-okay-autoargs.flags
|
||||
data/nix/tests/lang/eval-okay-autoargs.nix
|
||||
data/nix/tests/lang/eval-okay-backslash-newline-1.exp
|
||||
data/nix/tests/lang/eval-okay-backslash-newline-1.nix
|
||||
data/nix/tests/lang/eval-okay-backslash-newline-2.exp
|
||||
data/nix/tests/lang/eval-okay-backslash-newline-2.nix
|
||||
data/nix/tests/lang/eval-okay-builtins-add.exp
|
||||
data/nix/tests/lang/eval-okay-builtins-add.nix
|
||||
data/nix/tests/lang/eval-okay-builtins.exp
|
||||
data/nix/tests/lang/eval-okay-builtins.nix
|
||||
data/nix/tests/lang/eval-okay-callable-attrs.exp
|
||||
data/nix/tests/lang/eval-okay-callable-attrs.nix
|
||||
data/nix/tests/lang/eval-okay-catattrs.exp
|
||||
data/nix/tests/lang/eval-okay-catattrs.nix
|
||||
data/nix/tests/lang/eval-okay-closure.exp.xml
|
||||
data/nix/tests/lang/eval-okay-closure.nix
|
||||
data/nix/tests/lang/eval-okay-comments.exp
|
||||
data/nix/tests/lang/eval-okay-comments.nix
|
||||
data/nix/tests/lang/eval-okay-concat.exp
|
||||
data/nix/tests/lang/eval-okay-concat.nix
|
||||
data/nix/tests/lang/eval-okay-concatstringssep.exp
|
||||
data/nix/tests/lang/eval-okay-concatstringssep.nix
|
||||
data/nix/tests/lang/eval-okay-context.exp
|
||||
data/nix/tests/lang/eval-okay-context.nix
|
||||
data/nix/tests/lang/eval-okay-curpos.exp
|
||||
data/nix/tests/lang/eval-okay-curpos.nix
|
||||
data/nix/tests/lang/eval-okay-deepseq.exp
|
||||
data/nix/tests/lang/eval-okay-deepseq.nix
|
||||
data/nix/tests/lang/eval-okay-delayed-with-inherit.exp
|
||||
data/nix/tests/lang/eval-okay-delayed-with-inherit.nix
|
||||
data/nix/tests/lang/eval-okay-delayed-with.exp
|
||||
data/nix/tests/lang/eval-okay-delayed-with.nix
|
||||
data/nix/tests/lang/eval-okay-dynamic-attrs-2.exp
|
||||
data/nix/tests/lang/eval-okay-dynamic-attrs-2.nix
|
||||
data/nix/tests/lang/eval-okay-dynamic-attrs-bare.exp
|
||||
data/nix/tests/lang/eval-okay-dynamic-attrs-bare.nix
|
||||
data/nix/tests/lang/eval-okay-dynamic-attrs.exp
|
||||
data/nix/tests/lang/eval-okay-dynamic-attrs.nix
|
||||
data/nix/tests/lang/eval-okay-elem.exp
|
||||
data/nix/tests/lang/eval-okay-elem.nix
|
||||
data/nix/tests/lang/eval-okay-empty-args.exp
|
||||
data/nix/tests/lang/eval-okay-empty-args.nix
|
||||
data/nix/tests/lang/eval-okay-eq-derivations.exp
|
||||
data/nix/tests/lang/eval-okay-eq-derivations.nix
|
||||
data/nix/tests/lang/eval-okay-eq.exp.disabled
|
||||
data/nix/tests/lang/eval-okay-eq.nix
|
||||
data/nix/tests/lang/eval-okay-filter.exp
|
||||
data/nix/tests/lang/eval-okay-filter.nix
|
||||
data/nix/tests/lang/eval-okay-flatten.exp
|
||||
data/nix/tests/lang/eval-okay-flatten.nix
|
||||
data/nix/tests/lang/eval-okay-fromjson.exp
|
||||
data/nix/tests/lang/eval-okay-fromjson.nix
|
||||
data/nix/tests/lang/eval-okay-functionargs.exp.xml
|
||||
data/nix/tests/lang/eval-okay-functionargs.nix
|
||||
data/nix/tests/lang/eval-okay-getattrpos-undefined.exp
|
||||
data/nix/tests/lang/eval-okay-getattrpos-undefined.nix
|
||||
data/nix/tests/lang/eval-okay-getattrpos.exp
|
||||
data/nix/tests/lang/eval-okay-getattrpos.nix
|
||||
data/nix/tests/lang/eval-okay-getenv.exp
|
||||
data/nix/tests/lang/eval-okay-getenv.nix
|
||||
data/nix/tests/lang/eval-okay-hash.exp
|
||||
data/nix/tests/lang/eval-okay-hash.nix
|
||||
data/nix/tests/lang/eval-okay-if.exp
|
||||
data/nix/tests/lang/eval-okay-if.nix
|
||||
data/nix/tests/lang/eval-okay-import.exp
|
||||
data/nix/tests/lang/eval-okay-import.nix
|
||||
data/nix/tests/lang/eval-okay-ind-string.exp
|
||||
data/nix/tests/lang/eval-okay-ind-string.nix
|
||||
data/nix/tests/lang/eval-okay-let.exp
|
||||
data/nix/tests/lang/eval-okay-let.nix
|
||||
data/nix/tests/lang/eval-okay-list.exp
|
||||
data/nix/tests/lang/eval-okay-list.nix
|
||||
data/nix/tests/lang/eval-okay-listtoattrs.exp
|
||||
data/nix/tests/lang/eval-okay-listtoattrs.nix
|
||||
data/nix/tests/lang/eval-okay-logic.exp
|
||||
data/nix/tests/lang/eval-okay-logic.nix
|
||||
data/nix/tests/lang/eval-okay-map.exp
|
||||
data/nix/tests/lang/eval-okay-map.nix
|
||||
data/nix/tests/lang/eval-okay-nested-with.exp
|
||||
data/nix/tests/lang/eval-okay-nested-with.nix
|
||||
data/nix/tests/lang/eval-okay-new-let.exp
|
||||
data/nix/tests/lang/eval-okay-new-let.nix
|
||||
data/nix/tests/lang/eval-okay-null-dynamic-attrs.exp
|
||||
data/nix/tests/lang/eval-okay-null-dynamic-attrs.nix
|
||||
data/nix/tests/lang/eval-okay-overrides.exp
|
||||
data/nix/tests/lang/eval-okay-overrides.nix
|
||||
data/nix/tests/lang/eval-okay-partition.exp
|
||||
data/nix/tests/lang/eval-okay-partition.nix
|
||||
data/nix/tests/lang/eval-okay-path.nix
|
||||
data/nix/tests/lang/eval-okay-pathexists.exp
|
||||
data/nix/tests/lang/eval-okay-pathexists.nix
|
||||
data/nix/tests/lang/eval-okay-patterns.exp
|
||||
data/nix/tests/lang/eval-okay-patterns.nix
|
||||
data/nix/tests/lang/eval-okay-readDir.exp
|
||||
data/nix/tests/lang/eval-okay-readDir.nix
|
||||
data/nix/tests/lang/eval-okay-readfile.exp
|
||||
data/nix/tests/lang/eval-okay-readfile.nix
|
||||
data/nix/tests/lang/eval-okay-redefine-builtin.exp
|
||||
data/nix/tests/lang/eval-okay-redefine-builtin.nix
|
||||
data/nix/tests/lang/eval-okay-regex-match.exp
|
||||
data/nix/tests/lang/eval-okay-regex-match.nix
|
||||
data/nix/tests/lang/eval-okay-regex-split.exp
|
||||
data/nix/tests/lang/eval-okay-regex-split.nix
|
||||
data/nix/tests/lang/eval-okay-remove.exp
|
||||
data/nix/tests/lang/eval-okay-remove.nix
|
||||
data/nix/tests/lang/eval-okay-replacestrings.exp
|
||||
data/nix/tests/lang/eval-okay-replacestrings.nix
|
||||
data/nix/tests/lang/eval-okay-scope-1.exp
|
||||
data/nix/tests/lang/eval-okay-scope-1.nix
|
||||
data/nix/tests/lang/eval-okay-scope-2.exp
|
||||
data/nix/tests/lang/eval-okay-scope-2.nix
|
||||
data/nix/tests/lang/eval-okay-scope-3.exp
|
||||
data/nix/tests/lang/eval-okay-scope-3.nix
|
||||
data/nix/tests/lang/eval-okay-scope-4.exp
|
||||
data/nix/tests/lang/eval-okay-scope-4.nix
|
||||
data/nix/tests/lang/eval-okay-scope-6.exp
|
||||
data/nix/tests/lang/eval-okay-scope-6.nix
|
||||
data/nix/tests/lang/eval-okay-scope-7.exp
|
||||
data/nix/tests/lang/eval-okay-scope-7.nix
|
||||
data/nix/tests/lang/eval-okay-search-path.exp
|
||||
data/nix/tests/lang/eval-okay-search-path.flags
|
||||
data/nix/tests/lang/eval-okay-search-path.nix
|
||||
data/nix/tests/lang/eval-okay-seq.exp
|
||||
data/nix/tests/lang/eval-okay-seq.nix
|
||||
data/nix/tests/lang/eval-okay-sort.exp
|
||||
data/nix/tests/lang/eval-okay-sort.nix
|
||||
data/nix/tests/lang/eval-okay-splitversion.exp
|
||||
data/nix/tests/lang/eval-okay-splitversion.nix
|
||||
data/nix/tests/lang/eval-okay-string.exp
|
||||
data/nix/tests/lang/eval-okay-string.nix
|
||||
data/nix/tests/lang/eval-okay-strings-as-attrs-names.exp
|
||||
data/nix/tests/lang/eval-okay-strings-as-attrs-names.nix
|
||||
data/nix/tests/lang/eval-okay-substring.exp
|
||||
data/nix/tests/lang/eval-okay-substring.nix
|
||||
data/nix/tests/lang/eval-okay-tail-call-1.exp-disabled
|
||||
data/nix/tests/lang/eval-okay-tail-call-1.nix
|
||||
data/nix/tests/lang/eval-okay-tojson.exp
|
||||
data/nix/tests/lang/eval-okay-tojson.nix
|
||||
data/nix/tests/lang/eval-okay-toxml.exp
|
||||
data/nix/tests/lang/eval-okay-toxml.nix
|
||||
data/nix/tests/lang/eval-okay-toxml2.exp
|
||||
data/nix/tests/lang/eval-okay-toxml2.nix
|
||||
data/nix/tests/lang/eval-okay-tryeval.exp
|
||||
data/nix/tests/lang/eval-okay-tryeval.nix
|
||||
data/nix/tests/lang/eval-okay-types.exp
|
||||
data/nix/tests/lang/eval-okay-types.nix
|
||||
data/nix/tests/lang/eval-okay-versions.exp
|
||||
data/nix/tests/lang/eval-okay-versions.nix
|
||||
data/nix/tests/lang/eval-okay-with.exp
|
||||
data/nix/tests/lang/eval-okay-with.nix
|
||||
data/nix/tests/lang/eval-okay-xml.exp.xml
|
||||
data/nix/tests/lang/eval-okay-xml.nix
|
||||
data/nix/tests/lang/imported.nix
|
||||
data/nix/tests/lang/imported2.nix
|
||||
data/nix/tests/lang/lib.nix
|
||||
data/nix/tests/lang/parse-fail-dup-attrs-1.nix
|
||||
data/nix/tests/lang/parse-fail-dup-attrs-2.nix
|
||||
data/nix/tests/lang/parse-fail-dup-attrs-3.nix
|
||||
data/nix/tests/lang/parse-fail-dup-attrs-4.nix
|
||||
data/nix/tests/lang/parse-fail-dup-attrs-6.nix
|
||||
data/nix/tests/lang/parse-fail-dup-attrs-7.nix
|
||||
data/nix/tests/lang/parse-fail-dup-formals.nix
|
||||
data/nix/tests/lang/parse-fail-patterns-1.nix
|
||||
data/nix/tests/lang/parse-fail-regression-20060610.nix
|
||||
data/nix/tests/lang/parse-fail-undef-var-2.nix
|
||||
data/nix/tests/lang/parse-fail-undef-var.nix
|
||||
data/nix/tests/lang/parse-okay-1.nix
|
||||
data/nix/tests/lang/parse-okay-crlf.nix
|
||||
data/nix/tests/lang/parse-okay-dup-attrs-5.nix
|
||||
data/nix/tests/lang/parse-okay-regression-20041027.nix
|
||||
data/nix/tests/lang/parse-okay-regression-751.nix
|
||||
data/nix/tests/lang/parse-okay-subversion.nix
|
||||
data/nix/tests/lang/parse-okay-url.nix
|
||||
data/nix/tests/lang/readDir/bar
|
||||
data/nix/tests/lang/readDir/foo/git-hates-directories
|
||||
data/nix/tests/linux-sandbox.sh
|
||||
data/nix/tests/local.mk
|
||||
data/nix/tests/logging.sh
|
||||
data/nix/tests/misc.sh
|
||||
data/nix/tests/multiple-outputs.nix
|
||||
data/nix/tests/multiple-outputs.sh
|
||||
data/nix/tests/nar-access.nix
|
||||
data/nix/tests/nar-access.sh
|
||||
data/nix/tests/nix-build.sh
|
||||
data/nix/tests/nix-channel.sh
|
||||
data/nix/tests/nix-copy-closure.nix
|
||||
data/nix/tests/nix-profile.sh
|
||||
data/nix/tests/nix-shell.sh
|
||||
data/nix/tests/optimise-store.sh
|
||||
data/nix/tests/parallel.builder.sh
|
||||
data/nix/tests/parallel.nix
|
||||
data/nix/tests/parallel.sh
|
||||
data/nix/tests/pass-as-file.sh
|
||||
data/nix/tests/placeholders.sh
|
||||
data/nix/tests/plugins.sh
|
||||
data/nix/tests/plugins/local.mk
|
||||
data/nix/tests/plugins/plugintest.cc
|
||||
data/nix/tests/pure-eval.nix
|
||||
data/nix/tests/pure-eval.sh
|
||||
data/nix/tests/referrers.sh
|
||||
data/nix/tests/remote-builds.nix
|
||||
data/nix/tests/remote-store.sh
|
||||
data/nix/tests/repair.sh
|
||||
data/nix/tests/restricted.nix
|
||||
data/nix/tests/restricted.sh
|
||||
data/nix/tests/run.nix
|
||||
data/nix/tests/run.sh
|
||||
data/nix/tests/search.nix
|
||||
data/nix/tests/search.sh
|
||||
data/nix/tests/secure-drv-outputs.nix
|
||||
data/nix/tests/secure-drv-outputs.sh
|
||||
data/nix/tests/setuid.nix
|
||||
data/nix/tests/shell.nix
|
||||
data/nix/tests/shell.shebang.rb
|
||||
data/nix/tests/shell.shebang.sh
|
||||
data/nix/tests/signing.sh
|
||||
data/nix/tests/simple.builder.sh
|
||||
data/nix/tests/simple.nix
|
||||
data/nix/tests/simple.sh
|
||||
data/nix/tests/structured-attrs.nix
|
||||
data/nix/tests/structured-attrs.sh
|
||||
data/nix/tests/tarball.sh
|
||||
data/nix/tests/timeout.nix
|
||||
data/nix/tests/timeout.sh
|
||||
data/nix/tests/user-envs.builder.sh
|
||||
data/nix/tests/user-envs.nix
|
||||
data/nix/tests/user-envs.sh
|
||||
data/nix/version
|
||||
data/nixpkgs-all-packages-pretty.nix
|
||||
data/nixpkgs-all-packages.nix
|
||||
data/simple-pretty.nix
|
||||
data/simple.nix
|
||||
LICENSE
|
||||
package.yaml
|
||||
README.md
|
||||
tests/eval-compare/builtins.split-01.nix
|
||||
tests/eval-compare/builtins.split-02.nix
|
||||
tests/eval-compare/builtins.split-03.nix
|
||||
tests/eval-compare/builtins.split-04.nix
|
||||
tests/eval-compare/ind-string-01.nix
|
||||
tests/eval-compare/ind-string-02.nix
|
||||
tests/eval-compare/ind-string-03.nix
|
||||
tests/eval-compare/ind-string-04.nix
|
||||
tests/eval-compare/ind-string-05.nix
|
||||
tests/eval-compare/ind-string-06.nix
|
||||
tests/eval-compare/ind-string-07.nix
|
||||
tests/eval-compare/ind-string-08.nix
|
||||
tests/eval-compare/ind-string-09.nix
|
||||
tests/eval-compare/ind-string-10.nix
|
||||
tests/eval-compare/ind-string-11.nix
|
||||
tests/eval-compare/ind-string-12.nix
|
||||
tests/eval-compare/ind-string-13.nix
|
||||
tests/eval-compare/ind-string-14.nix
|
||||
tests/eval-compare/ind-string-15.nix
|
||||
tests/eval-compare/ind-string-16.nix
|
||||
tests/eval-compare/ind-string-17.nix
|
||||
|
||||
source-repository head
|
||||
type: git
|
||||
location: https://github.com/jwiegley/hnix
|
||||
location: https://github.com/haskell-nix/hnix
|
||||
|
||||
flag optimize
|
||||
description: Enable all optimization flags
|
||||
|
@ -57,7 +461,6 @@ library
|
|||
Nix.Expr.Types.Annotated
|
||||
Nix.Frames
|
||||
Nix.Lint
|
||||
Nix.NixString
|
||||
Nix.Normal
|
||||
Nix.Options
|
||||
Nix.Parser
|
||||
|
@ -86,38 +489,31 @@ library
|
|||
, ansi-wl-pprint
|
||||
, array >=0.4 && <0.6
|
||||
, base >=4.9 && <5
|
||||
, base16-bytestring
|
||||
, binary
|
||||
, bytestring
|
||||
, compact
|
||||
, containers
|
||||
, cryptohash
|
||||
, data-fix
|
||||
, deepseq
|
||||
, deriving-compat >=0.3 && <0.5
|
||||
, deepseq >=1.4.2 && <1.5
|
||||
, deriving-compat >=0.3 && <0.6
|
||||
, directory
|
||||
, exceptions
|
||||
, filepath
|
||||
, hashable
|
||||
, haskeline
|
||||
, hashing
|
||||
, http-client
|
||||
, http-client-tls
|
||||
, http-types
|
||||
, lens-family
|
||||
, lens-family-core
|
||||
, interpolate
|
||||
, lens-family-th
|
||||
, logict
|
||||
, megaparsec
|
||||
, megaparsec >=6.5 && <7.0
|
||||
, monadlist
|
||||
, mtl
|
||||
, optparse-applicative
|
||||
, pretty-show
|
||||
, process
|
||||
, regex-tdfa
|
||||
, regex-tdfa-text
|
||||
, scientific
|
||||
, semigroups >=0.18 && <0.19
|
||||
, serialise
|
||||
, split
|
||||
, syb
|
||||
, template-haskell
|
||||
|
@ -129,11 +525,42 @@ library
|
|||
, unordered-containers >=0.2.9 && <0.3
|
||||
, vector
|
||||
, xml
|
||||
if flag(optimize)
|
||||
ghc-options: -fexpose-all-unfoldings -fspecialise-aggressively -O2
|
||||
if flag(tracing)
|
||||
cpp-options: -DENABLE_TRACING=1
|
||||
if os(linux) && impl(ghc >= 8.2) && impl(ghc < 8.3)
|
||||
build-depends:
|
||||
compact
|
||||
if !impl(ghcjs)
|
||||
build-depends:
|
||||
base16-bytestring
|
||||
, cryptohash-md5
|
||||
, cryptohash-sha1
|
||||
, cryptohash-sha256
|
||||
, cryptohash-sha512
|
||||
, serialise
|
||||
if impl(ghc < 8.1)
|
||||
build-depends:
|
||||
lens-family ==1.2.1
|
||||
, lens-family-core ==1.2.1
|
||||
else
|
||||
build-depends:
|
||||
lens-family >=1.2.2
|
||||
, lens-family-core >=1.2.2
|
||||
if impl(ghc < 8.4.0) && !flag(profiling)
|
||||
build-depends:
|
||||
ghc-datasize
|
||||
if impl(ghcjs)
|
||||
build-depends:
|
||||
hashable >=1.2.4 && <1.3
|
||||
else
|
||||
exposed-modules:
|
||||
Nix.Options.Parser
|
||||
build-depends:
|
||||
hashable >=1.2.5 && <1.3
|
||||
, haskeline
|
||||
, pretty-show
|
||||
default-language: Haskell2010
|
||||
|
||||
executable hnix
|
||||
|
@ -149,26 +576,42 @@ executable hnix
|
|||
, ansi-wl-pprint
|
||||
, base >=4.9 && <5
|
||||
, bytestring
|
||||
, compact
|
||||
, containers
|
||||
, data-fix
|
||||
, deepseq
|
||||
, deepseq >=1.4.2 && <1.5
|
||||
, exceptions
|
||||
, filepath
|
||||
, hashing
|
||||
, haskeline
|
||||
, hnix
|
||||
, mtl
|
||||
, optparse-applicative
|
||||
, pretty-show
|
||||
, repline
|
||||
, serialise
|
||||
, template-haskell
|
||||
, text
|
||||
, time
|
||||
, transformers
|
||||
, unordered-containers >=0.2.9 && <0.3
|
||||
if flag(optimize)
|
||||
ghc-options: -fexpose-all-unfoldings -fspecialise-aggressively -O2
|
||||
if flag(tracing)
|
||||
cpp-options: -DENABLE_TRACING=1
|
||||
if os(linux) && impl(ghc >= 8.2) && impl(ghc < 8.3)
|
||||
build-depends:
|
||||
compact
|
||||
if !impl(ghcjs)
|
||||
build-depends:
|
||||
base16-bytestring
|
||||
, cryptohash-md5
|
||||
, cryptohash-sha1
|
||||
, cryptohash-sha256
|
||||
, cryptohash-sha512
|
||||
, serialise
|
||||
if impl(ghcjs)
|
||||
buildable: False
|
||||
else
|
||||
buildable: True
|
||||
default-language: Haskell2010
|
||||
|
||||
test-suite hnix-tests
|
||||
|
@ -180,6 +623,7 @@ test-suite hnix-tests
|
|||
ParserTests
|
||||
PrettyParseTests
|
||||
PrettyTests
|
||||
ReduceExprTests
|
||||
TestCommon
|
||||
Paths_hnix
|
||||
hs-source-dirs:
|
||||
|
@ -188,18 +632,18 @@ test-suite hnix-tests
|
|||
build-depends:
|
||||
Diff
|
||||
, Glob
|
||||
, QuickCheck
|
||||
, ansi-wl-pprint
|
||||
, base >=4.9 && <5
|
||||
, bytestring
|
||||
, compact
|
||||
, containers
|
||||
, data-fix
|
||||
, deepseq
|
||||
, deepseq >=1.4.2 && <1.5
|
||||
, directory
|
||||
, exceptions
|
||||
, filepath
|
||||
, generic-random
|
||||
, hashing
|
||||
, hedgehog
|
||||
, hnix
|
||||
, interpolate
|
||||
, megaparsec
|
||||
|
@ -207,10 +651,9 @@ test-suite hnix-tests
|
|||
, optparse-applicative
|
||||
, pretty-show
|
||||
, process
|
||||
, quickcheck-instances
|
||||
, serialise
|
||||
, split
|
||||
, tasty
|
||||
, tasty-hedgehog
|
||||
, tasty-hunit
|
||||
, tasty-quickcheck
|
||||
, tasty-th
|
||||
|
@ -220,9 +663,27 @@ test-suite hnix-tests
|
|||
, transformers
|
||||
, unix
|
||||
, unordered-containers >=0.2.9 && <0.3
|
||||
if flag(optimize)
|
||||
ghc-options: -fexpose-all-unfoldings -fspecialise-aggressively -O2
|
||||
if flag(tracing)
|
||||
cpp-options: -DENABLE_TRACING=1
|
||||
if os(linux) && impl(ghc >= 8.2) && impl(ghc < 8.3)
|
||||
build-depends:
|
||||
compact
|
||||
if !impl(ghcjs)
|
||||
build-depends:
|
||||
base16-bytestring
|
||||
, cryptohash-md5
|
||||
, cryptohash-sha1
|
||||
, cryptohash-sha256
|
||||
, cryptohash-sha512
|
||||
, serialise
|
||||
if impl(ghcjs)
|
||||
buildable: False
|
||||
else
|
||||
buildable: True
|
||||
default-language: Haskell2010
|
||||
build-tool-depends: hspec-discover:hspec-discover == 2.*
|
||||
|
||||
benchmark hnix-benchmarks
|
||||
type: exitcode-stdio-1.0
|
||||
|
@ -237,22 +698,38 @@ benchmark hnix-benchmarks
|
|||
ansi-wl-pprint
|
||||
, base >=4.9 && <5
|
||||
, bytestring
|
||||
, compact
|
||||
, containers
|
||||
, criterion
|
||||
, data-fix
|
||||
, deepseq
|
||||
, deepseq >=1.4.2 && <1.5
|
||||
, exceptions
|
||||
, filepath
|
||||
, hashing
|
||||
, hnix
|
||||
, mtl
|
||||
, optparse-applicative
|
||||
, serialise
|
||||
, template-haskell
|
||||
, text
|
||||
, time
|
||||
, transformers
|
||||
, unordered-containers >=0.2.9 && <0.3
|
||||
if flag(optimize)
|
||||
ghc-options: -fexpose-all-unfoldings -fspecialise-aggressively -O2
|
||||
if flag(tracing)
|
||||
cpp-options: -DENABLE_TRACING=1
|
||||
if os(linux) && impl(ghc >= 8.2) && impl(ghc < 8.3)
|
||||
build-depends:
|
||||
compact
|
||||
if !impl(ghcjs)
|
||||
build-depends:
|
||||
base16-bytestring
|
||||
, cryptohash-md5
|
||||
, cryptohash-sha1
|
||||
, cryptohash-sha256
|
||||
, cryptohash-sha512
|
||||
, serialise
|
||||
if impl(ghcjs)
|
||||
buildable: False
|
||||
else
|
||||
buildable: True
|
||||
default-language: Haskell2010
|
||||
|
|
|
@ -28,6 +28,7 @@ import Nix
|
|||
import Nix.Convert
|
||||
import qualified Nix.Eval as Eval
|
||||
-- import Nix.Lint
|
||||
import Nix.Options.Parser
|
||||
import qualified Nix.Type.Env as Env
|
||||
import qualified Nix.Type.Infer as HM
|
||||
import Nix.Utils
|
||||
|
@ -143,7 +144,7 @@ main = do
|
|||
. A.encodingToLazyByteString
|
||||
. toEncodingSorted
|
||||
<=< fromNix
|
||||
| normalize opts =
|
||||
| strict opts =
|
||||
liftIO . print . prettyNValueNF <=< normalForm
|
||||
| values opts =
|
||||
liftIO . print <=< prettyNValueProv
|
||||
|
|
|
@ -103,7 +103,7 @@ exec update source = do
|
|||
go expr = do
|
||||
val <- evalExprLoc expr
|
||||
opts :: Nix.Options <- asks (view hasLens)
|
||||
if | normalize opts ->
|
||||
if | strict opts ->
|
||||
liftIO . print . prettyNValueNF =<< normalForm val
|
||||
| values opts ->
|
||||
liftIO . print =<< prettyNValueProv val
|
||||
|
|
147
package.yaml
147
package.yaml
|
@ -1,7 +1,7 @@
|
|||
name: hnix
|
||||
version: 0.5.0
|
||||
version: 0.5.2
|
||||
synopsis: Haskell implementation of the Nix language
|
||||
github: jwiegley/hnix
|
||||
github: haskell-nix/hnix
|
||||
author: John Wiegley
|
||||
maintainer: johnw@newartisans.com
|
||||
category: System, Data, Nix
|
||||
|
@ -11,29 +11,28 @@ description:
|
|||
Haskell implementation of the Nix language.
|
||||
|
||||
extra-source-files:
|
||||
- LICENSE
|
||||
- README.md
|
||||
|
||||
dependencies:
|
||||
- base >= 4.9 && < 5
|
||||
- ansi-wl-pprint
|
||||
- bytestring
|
||||
- compact
|
||||
- containers
|
||||
- data-fix
|
||||
- deepseq
|
||||
- exceptions
|
||||
- filepath
|
||||
- mtl
|
||||
- optparse-applicative
|
||||
- serialise
|
||||
- template-haskell
|
||||
- text
|
||||
- time
|
||||
- transformers
|
||||
- unordered-containers >= 0.2.9 && < 0.3
|
||||
|
||||
ghc-options:
|
||||
- -Wall
|
||||
- package.yaml
|
||||
- data/*
|
||||
- data/nix/*
|
||||
- data/nix/corepkgs/*
|
||||
- data/nix/config/*
|
||||
- data/nix/perl/*
|
||||
- data/nix/perl/lib/Nix/*
|
||||
- data/nix/tests/*
|
||||
- data/nix/tests/plugins/*
|
||||
- data/nix/tests/lang/*
|
||||
- data/nix/tests/lang/readDir/*
|
||||
- data/nix/tests/lang/readDir/foo/*
|
||||
- data/nix/tests/lang/dir2/*
|
||||
- data/nix/tests/lang/dir4/*
|
||||
- data/nix/tests/lang/dir3/*
|
||||
- data/nix/tests/lang/dir1/*
|
||||
- data/nix/maintainers/*
|
||||
- data/nix/mk/*
|
||||
- data/nix/scripts/*
|
||||
- tests/eval-compare/*
|
||||
|
||||
flags:
|
||||
tracing:
|
||||
|
@ -51,6 +50,27 @@ flags:
|
|||
manual: True
|
||||
default: False
|
||||
|
||||
ghc-options:
|
||||
- -Wall
|
||||
|
||||
dependencies:
|
||||
- base >= 4.9 && < 5
|
||||
- ansi-wl-pprint
|
||||
- bytestring
|
||||
- containers
|
||||
- data-fix
|
||||
- deepseq >= 1.4.2 && < 1.5
|
||||
- exceptions
|
||||
- filepath
|
||||
- hashing
|
||||
- mtl
|
||||
- optparse-applicative
|
||||
- template-haskell
|
||||
- text
|
||||
- time
|
||||
- transformers
|
||||
- unordered-containers >= 0.2.9 && < 0.3
|
||||
|
||||
when:
|
||||
- condition: flag(optimize)
|
||||
ghc-options:
|
||||
|
@ -58,38 +78,44 @@ when:
|
|||
- -fspecialise-aggressively
|
||||
- -O2
|
||||
|
||||
when:
|
||||
- condition: flag(tracing)
|
||||
cpp-options: -DENABLE_TRACING=1
|
||||
|
||||
- condition: "os(linux) && impl(ghc >= 8.2) && impl(ghc < 8.3)"
|
||||
dependencies:
|
||||
- compact
|
||||
|
||||
- condition: "!impl(ghcjs)"
|
||||
dependencies:
|
||||
- base16-bytestring
|
||||
- cryptohash-md5
|
||||
- cryptohash-sha1
|
||||
- cryptohash-sha256
|
||||
- cryptohash-sha512
|
||||
- serialise
|
||||
|
||||
library:
|
||||
source-dirs: src
|
||||
dependencies:
|
||||
- aeson
|
||||
- ansi-wl-pprint
|
||||
- array >= 0.4 && < 0.6
|
||||
- base16-bytestring
|
||||
- array >= 0.4 && < 0.6
|
||||
- binary
|
||||
- cryptohash
|
||||
- deriving-compat >= 0.3 && < 0.5
|
||||
- deriving-compat >= 0.3 && < 0.6
|
||||
- directory
|
||||
- hashable
|
||||
- http-types
|
||||
- http-client
|
||||
- http-client-tls
|
||||
- haskeline
|
||||
- lens-family
|
||||
- lens-family-core
|
||||
- interpolate
|
||||
- lens-family-th
|
||||
- logict
|
||||
- megaparsec
|
||||
- megaparsec >= 6.5 && < 7.0
|
||||
- monadlist
|
||||
- pretty-show
|
||||
- process
|
||||
- regex-tdfa
|
||||
- regex-tdfa-text
|
||||
- scientific
|
||||
- semigroups >= 0.18 && < 0.19
|
||||
- semigroups >= 0.18 && < 0.19
|
||||
- split
|
||||
- syb
|
||||
- these
|
||||
|
@ -97,10 +123,32 @@ library:
|
|||
- vector
|
||||
- xml
|
||||
when:
|
||||
- condition: impl(ghc < 8.4.0) && !flag(profiling)
|
||||
- condition: "impl(ghc < 8.1)"
|
||||
then:
|
||||
dependencies:
|
||||
- lens-family == 1.2.1
|
||||
- lens-family-core == 1.2.1
|
||||
else:
|
||||
dependencies:
|
||||
- lens-family >= 1.2.2
|
||||
- lens-family-core >= 1.2.2
|
||||
|
||||
- condition: "impl(ghc < 8.4.0) && !flag(profiling)"
|
||||
dependencies:
|
||||
- ghc-datasize
|
||||
|
||||
- condition: "impl(ghcjs)"
|
||||
then:
|
||||
dependencies:
|
||||
- hashable >= 1.2.4 && < 1.3
|
||||
else:
|
||||
exposed-modules:
|
||||
- Nix.Options.Parser
|
||||
dependencies:
|
||||
- hashable >= 1.2.5 && < 1.3
|
||||
- haskeline
|
||||
- pretty-show
|
||||
|
||||
executables:
|
||||
hnix:
|
||||
source-dirs: main
|
||||
|
@ -111,12 +159,21 @@ executables:
|
|||
- pretty-show
|
||||
- repline
|
||||
- haskeline
|
||||
when:
|
||||
- condition: "impl(ghcjs)"
|
||||
then:
|
||||
buildable: false
|
||||
else:
|
||||
buildable: true
|
||||
|
||||
tests:
|
||||
hnix-tests:
|
||||
source-dirs: tests
|
||||
main: Main.hs
|
||||
ghc-options: -threaded
|
||||
verbatim:
|
||||
build-tool-depends:
|
||||
hspec-discover:hspec-discover == 2.*
|
||||
dependencies:
|
||||
- hnix
|
||||
- Glob
|
||||
|
@ -125,16 +182,22 @@ tests:
|
|||
- process
|
||||
- split
|
||||
- tasty
|
||||
- tasty-hedgehog
|
||||
- tasty-hunit
|
||||
- tasty-th
|
||||
- unix
|
||||
- QuickCheck
|
||||
- quickcheck-instances
|
||||
- hedgehog
|
||||
- generic-random
|
||||
- Diff
|
||||
- megaparsec
|
||||
- tasty-quickcheck
|
||||
- pretty-show
|
||||
when:
|
||||
- condition: "impl(ghcjs)"
|
||||
then:
|
||||
buildable: false
|
||||
else:
|
||||
buildable: true
|
||||
|
||||
benchmarks:
|
||||
hnix-benchmarks:
|
||||
|
@ -143,3 +206,9 @@ benchmarks:
|
|||
dependencies:
|
||||
- hnix
|
||||
- criterion
|
||||
when:
|
||||
- condition: "impl(ghcjs)"
|
||||
then:
|
||||
buildable: false
|
||||
else:
|
||||
buildable: true
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DeriveAnyClass #-}
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
|
@ -5,7 +6,9 @@
|
|||
|
||||
module Nix.Atoms where
|
||||
|
||||
#ifdef MIN_VERSION_serialise
|
||||
import Codec.Serialise
|
||||
#endif
|
||||
import Control.DeepSeq
|
||||
import Data.Data
|
||||
import Data.Hashable
|
||||
|
@ -25,10 +28,12 @@ data NAtom
|
|||
| NBool Bool
|
||||
-- | Null values. There's only one of this variant.
|
||||
| NNull
|
||||
-- | URIs, which are just string literals, but do not need quotes.
|
||||
| NUri Text
|
||||
deriving (Eq, Ord, Generic, Typeable, Data, Show, Read, NFData,
|
||||
Serialise, Hashable)
|
||||
Hashable)
|
||||
|
||||
#ifdef MIN_VERSION_serialise
|
||||
instance Serialise NAtom
|
||||
#endif
|
||||
|
||||
-- | Translate an atom into its nix representation.
|
||||
atomText :: NAtom -> Text
|
||||
|
@ -36,4 +41,3 @@ atomText (NInt i) = pack (show i)
|
|||
atomText (NFloat f) = pack (show f)
|
||||
atomText (NBool b) = if b then "true" else "false"
|
||||
atomText NNull = "null"
|
||||
atomText (NUri uri) = uri
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE AllowAmbiguousTypes #-}
|
||||
{-# LANGUAGE ConstraintKinds #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
|
@ -7,7 +8,9 @@
|
|||
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||
{-# LANGUAGE MultiWayIf #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE PackageImports #-}
|
||||
{-# LANGUAGE PartialTypeSignatures #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE TupleSections #-}
|
||||
|
@ -24,17 +27,30 @@ import Control.Monad
|
|||
import Control.Monad.Catch
|
||||
import Control.Monad.ListM (sortByM)
|
||||
import Control.Monad.Reader (asks)
|
||||
import qualified Crypto.Hash.MD5 as MD5
|
||||
import qualified Crypto.Hash.SHA1 as SHA1
|
||||
import qualified Crypto.Hash.SHA256 as SHA256
|
||||
import qualified Crypto.Hash.SHA512 as SHA512
|
||||
|
||||
-- Using package imports here because there is a bug in cabal2nix that forces
|
||||
-- us to put the hashing package in the unconditional dependency list.
|
||||
-- See https://github.com/NixOS/cabal2nix/issues/348 for more info
|
||||
#if MIN_VERSION_hashing(0, 1, 0)
|
||||
import Crypto.Hash
|
||||
import qualified "hashing" Crypto.Hash.MD5 as MD5
|
||||
import qualified "hashing" Crypto.Hash.SHA1 as SHA1
|
||||
import qualified "hashing" Crypto.Hash.SHA256 as SHA256
|
||||
import qualified "hashing" Crypto.Hash.SHA512 as SHA512
|
||||
#else
|
||||
import Data.ByteString.Base16 as Base16
|
||||
import qualified "cryptohash-md5" Crypto.Hash.MD5 as MD5
|
||||
import qualified "cryptohash-sha1" Crypto.Hash.SHA1 as SHA1
|
||||
import qualified "cryptohash-sha256" Crypto.Hash.SHA256 as SHA256
|
||||
import qualified "cryptohash-sha512" Crypto.Hash.SHA512 as SHA512
|
||||
#endif
|
||||
|
||||
import qualified Data.Aeson as A
|
||||
import qualified Data.Aeson.Encoding as A
|
||||
import Data.Align (alignWith)
|
||||
import Data.Array
|
||||
import Data.ByteString (ByteString)
|
||||
import qualified Data.ByteString as B
|
||||
import Data.ByteString.Base16 as Base16
|
||||
import qualified Data.ByteString.Lazy as LBS
|
||||
import Data.Char (isDigit)
|
||||
import Data.Coerce
|
||||
|
@ -46,6 +62,7 @@ import Data.Maybe
|
|||
import Data.Semigroup
|
||||
import Data.Set (Set)
|
||||
import qualified Data.Set as S
|
||||
import Data.String.Interpolate.IsString
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as Text
|
||||
import Data.Text.Encoding
|
||||
|
@ -54,7 +71,6 @@ import qualified Data.Text.Lazy.Builder as Builder
|
|||
import Data.These (fromThese)
|
||||
import qualified Data.Time.Clock.POSIX as Time
|
||||
import Data.Traversable (mapM)
|
||||
import Language.Haskell.TH.Syntax (addDependentFile, runIO)
|
||||
import Nix.Atoms
|
||||
import Nix.Convert
|
||||
import Nix.Effects
|
||||
|
@ -128,12 +144,41 @@ builtinsList = sequence [
|
|||
, add0 Normal "currentSystem" currentSystem
|
||||
, add0 Normal "currentTime" currentTime_
|
||||
, add2 Normal "deepSeq" deepSeq
|
||||
, add0 TopLevel "derivation" $(do
|
||||
let f = "data/nix/corepkgs/derivation.nix"
|
||||
addDependentFile f
|
||||
Success expr <- runIO $ parseNixFile f
|
||||
|
||||
, add0 TopLevel "derivation" $(do
|
||||
-- This is compiled in so that we only parse and evaluate it once,
|
||||
-- at compile-time.
|
||||
let Success expr = parseNixText [i|
|
||||
/* This is the implementation of the ‘derivation’ builtin function.
|
||||
It's actually a wrapper around the ‘derivationStrict’ primop. */
|
||||
|
||||
drvAttrs @ { outputs ? [ "out" ], ... }:
|
||||
|
||||
let
|
||||
|
||||
strict = derivationStrict drvAttrs;
|
||||
|
||||
commonAttrs = drvAttrs // (builtins.listToAttrs outputsList) //
|
||||
{ all = map (x: x.value) outputsList;
|
||||
inherit drvAttrs;
|
||||
};
|
||||
|
||||
outputToAttrListElement = outputName:
|
||||
{ name = outputName;
|
||||
value = commonAttrs // {
|
||||
outPath = builtins.getAttr outputName strict;
|
||||
drvPath = strict.drvPath;
|
||||
type = "derivation";
|
||||
inherit outputName;
|
||||
};
|
||||
};
|
||||
|
||||
outputsList = map outputToAttrListElement outputs;
|
||||
|
||||
in (builtins.head outputsList).value|]
|
||||
[| cata Eval.eval expr |]
|
||||
)
|
||||
|
||||
, add TopLevel "derivationStrict" derivationStrict_
|
||||
, add TopLevel "dirOf" dirOf
|
||||
, add2 Normal "div" div_
|
||||
|
@ -178,6 +223,7 @@ builtinsList = sequence [
|
|||
, add TopLevel "placeholder" placeHolder
|
||||
, add Normal "readDir" readDir_
|
||||
, add Normal "readFile" readFile_
|
||||
, add2 Normal "findFile" findFile_
|
||||
, add2 TopLevel "removeAttrs" removeAttrs
|
||||
, add3 Normal "replaceStrings" replaceStrings
|
||||
, add2 TopLevel "scopedImport" scopedImport
|
||||
|
@ -195,6 +241,7 @@ builtinsList = sequence [
|
|||
, add' Normal "toJSON"
|
||||
(arity1 $ decodeUtf8 . LBS.toStrict . A.encodingToLazyByteString
|
||||
. toEncodingSorted)
|
||||
, add2 Normal "toFile" toFile
|
||||
, add Normal "toPath" toPath
|
||||
, add TopLevel "toString" toString
|
||||
, add Normal "toXML" toXML_
|
||||
|
@ -250,8 +297,7 @@ nixPath = fmap nvList $ flip foldNixPath [] $ \p mn rest ->
|
|||
nvStr (makeNixStringWithoutContext $ Text.pack (fromMaybe "" mn))) ]) : rest
|
||||
|
||||
toString :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
toString str =
|
||||
str >>= normalForm >>= valueText False >>= toNix @NixString
|
||||
toString str = str >>= coerceToString False >>= toNix @NixString . Text.pack
|
||||
|
||||
hasAttr :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
hasAttr x y =
|
||||
|
@ -269,26 +315,19 @@ hasContext :: MonadNix e m => m (NValue m) -> m (NValue m)
|
|||
hasContext =
|
||||
toNix . not . null . stringContextOnly <=< fromValue
|
||||
|
||||
getAttr :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
getAttr x y = x >>= \x' -> y >>= \y' -> case (x', y') of
|
||||
(NVStr ns, NVSet aset _) ->
|
||||
case stringNoContext ns of
|
||||
Just key -> attrsetGet key aset >>= force'
|
||||
Nothing -> throwError $ ErrorCall $ "Invalid NixString for builtin.getAttr: "
|
||||
++ show (ns, aset)
|
||||
(x, y) -> throwError $ ErrorCall $ "Invalid types for builtin.getAttr: "
|
||||
++ show (x, y)
|
||||
getAttr :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
getAttr x y =
|
||||
fromValue @Text x >>= \key ->
|
||||
fromValue @(AttrSet (NThunk m), AttrSet SourcePos) y >>= \(aset, _) ->
|
||||
attrsetGet key aset >>= force'
|
||||
|
||||
unsafeGetAttrPos :: forall e m. MonadNix e m
|
||||
=> m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
unsafeGetAttrPos x y = x >>= \x' -> y >>= \y' -> case (x', y') of
|
||||
(NVStr ns, NVSet _ apos) ->
|
||||
case stringNoContext ns of
|
||||
Just key -> case M.lookup key apos of
|
||||
Nothing -> pure $ nvConstant NNull
|
||||
Just delta -> toValue delta
|
||||
Nothing -> throwError $ ErrorCall $ "Invalid NixString for unsafeGetAttrPos " ++ show apos
|
||||
(x, y) -> throwError $ ErrorCall $ "Invalid types for builtin.unsafeGetAttrPos: "
|
||||
(NVStr ns _, NVSet _ apos) -> case M.lookup (stringIntentionallyDropContext key) apos of
|
||||
Nothing -> pure $ nvConstant NNull
|
||||
Just delta -> toValue delta
|
||||
(x, y) -> throwError $ ErrorCall $ "Invalid types for builtins.unsafeGetAttrPos: "
|
||||
++ show (x, y)
|
||||
|
||||
-- This function is a bit special in that it doesn't care about the contents
|
||||
|
@ -318,11 +357,14 @@ mul_ x y = x >>= \x' -> y >>= \y' -> case (x', y') of
|
|||
|
||||
div_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
div_ x y = x >>= \x' -> y >>= \y' -> case (x', y') of
|
||||
(NVConstant (NInt x), NVConstant (NInt y)) ->
|
||||
(NVConstant (NInt x), NVConstant (NInt y)) | y /= 0 ->
|
||||
toNix (floor (fromInteger x / fromInteger y :: Double) :: Integer)
|
||||
(NVConstant (NFloat x), NVConstant (NInt y)) -> toNix (x / fromInteger y)
|
||||
(NVConstant (NInt x), NVConstant (NFloat y)) -> toNix (fromInteger x / y)
|
||||
(NVConstant (NFloat x), NVConstant (NFloat y)) -> toNix (x / y)
|
||||
(NVConstant (NFloat x), NVConstant (NInt y)) | y /= 0 ->
|
||||
toNix (x / fromInteger y)
|
||||
(NVConstant (NInt x), NVConstant (NFloat y)) | y /= 0 ->
|
||||
toNix (fromInteger x / y)
|
||||
(NVConstant (NFloat x), NVConstant (NFloat y)) | y /= 0 ->
|
||||
toNix (x / y)
|
||||
(_, _) ->
|
||||
throwError $ Division x' y'
|
||||
|
||||
|
@ -668,6 +710,13 @@ functionArgs fun = fun >>= \case
|
|||
v -> throwError $ ErrorCall $
|
||||
"builtins.functionArgs: expected function, got " ++ show v
|
||||
|
||||
toFile :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
toFile name s = do
|
||||
name' <- fromValue name
|
||||
s' <- fromValue s
|
||||
mres <- toFile_ (Text.unpack name') (Text.unpack s')
|
||||
toNix $ Text.pack $ unStorePath mres
|
||||
|
||||
toPath :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
toPath = fromValue @Path >=> toNix @Path
|
||||
|
||||
|
@ -771,14 +820,33 @@ listToAttrs = fromValue @[NThunk m] >=> \l ->
|
|||
|
||||
hashString :: MonadNix e m => Text -> Text -> Prim m Text
|
||||
hashString algo s = Prim $ do
|
||||
hash <- case algo of
|
||||
"md5" -> pure MD5.hash
|
||||
"sha1" -> pure SHA1.hash
|
||||
"sha256" -> pure SHA256.hash
|
||||
"sha512" -> pure SHA512.hash
|
||||
case algo of
|
||||
"md5" -> pure $
|
||||
#if MIN_VERSION_hashing(0, 1, 0)
|
||||
Text.pack $ show (hash (encodeUtf8 s) :: MD5.MD5)
|
||||
#else
|
||||
decodeUtf8 $ Base16.encode $ MD5.hash $ encodeUtf8 s
|
||||
#endif
|
||||
"sha1" -> pure $
|
||||
#if MIN_VERSION_hashing(0, 1, 0)
|
||||
Text.pack $ show (hash (encodeUtf8 s) :: SHA1.SHA1)
|
||||
#else
|
||||
decodeUtf8 $ Base16.encode $ SHA1.hash $ encodeUtf8 s
|
||||
#endif
|
||||
"sha256" -> pure $
|
||||
#if MIN_VERSION_hashing(0, 1, 0)
|
||||
Text.pack $ show (hash (encodeUtf8 s) :: SHA256.SHA256)
|
||||
#else
|
||||
decodeUtf8 $ Base16.encode $ SHA256.hash $ encodeUtf8 s
|
||||
#endif
|
||||
"sha512" -> pure $
|
||||
#if MIN_VERSION_hashing(0, 1, 0)
|
||||
Text.pack $ show (hash (encodeUtf8 s) :: SHA512.SHA512)
|
||||
#else
|
||||
decodeUtf8 $ Base16.encode $ SHA512.hash $ encodeUtf8 s
|
||||
#endif
|
||||
_ -> throwError $ ErrorCall $ "builtins.hashString: "
|
||||
++ "expected \"md5\", \"sha1\", \"sha256\", or \"sha512\", got " ++ show algo
|
||||
pure $ decodeUtf8 $ Base16.encode $ hash $ encodeUtf8 s
|
||||
|
||||
placeHolder :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
placeHolder = fromValue @Text >=> \_ -> do
|
||||
|
@ -799,6 +867,19 @@ readFile_ :: MonadNix e m => m (NValue m) -> m (NValue m)
|
|||
readFile_ path =
|
||||
path >>= absolutePathFromValue >>= Nix.Render.readFile >>= toNix
|
||||
|
||||
findFile_ :: forall e m. MonadNix e m
|
||||
=> m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
findFile_ aset filePath =
|
||||
aset >>= \aset' ->
|
||||
filePath >>= \filePath' ->
|
||||
case (aset', filePath') of
|
||||
(NVList x, NVStr ns) -> do
|
||||
mres <- findPath x (Text.unpack (stringIntentionallyDropContext ns))
|
||||
pure $ nvPath mres
|
||||
(NVList _, y) -> throwError $ ErrorCall $ "expected a string, got " ++ show y
|
||||
(x, NVStr _ _) -> throwError $ ErrorCall $ "expected a list, got " ++ show x
|
||||
(x, y) -> throwError $ ErrorCall $ "Invalid types for builtins.findFile: " ++ show (x, y)
|
||||
|
||||
data FileType
|
||||
= FileTypeRegular
|
||||
| FileTypeDirectory
|
||||
|
@ -845,8 +926,7 @@ typeOf v = v >>= toNix @Text . \case
|
|||
NFloat _ -> "float"
|
||||
NBool _ -> "bool"
|
||||
NNull -> "null"
|
||||
NUri _ -> "string"
|
||||
NVStr _ -> "string"
|
||||
NVStr _ -> "string"
|
||||
NVList _ -> "list"
|
||||
NVSet _ _ -> "set"
|
||||
NVClosure {} -> "lambda"
|
||||
|
@ -886,14 +966,12 @@ fetchTarball v = v >>= \case
|
|||
"builtins.fetchTarball: Missing url attribute"
|
||||
Just url -> force url $ go (M.lookup "sha256" s)
|
||||
v@NVStr {} -> go Nothing v
|
||||
v@(NVConstant (NUri _)) -> go Nothing v
|
||||
v -> throwError $ ErrorCall $
|
||||
"builtins.fetchTarball: Expected URI or set, got " ++ show v
|
||||
where
|
||||
go :: Maybe (NThunk m) -> NValue m -> m (NValue m)
|
||||
go msha = \case
|
||||
NVStr ns -> fetch (stringIntentionallyDropContext ns) msha
|
||||
NVConstant (NUri uri) -> fetch uri msha
|
||||
v -> throwError $ ErrorCall $
|
||||
"builtins.fetchTarball: Expected URI or string, got " ++ show v
|
||||
|
||||
|
@ -922,14 +1000,12 @@ fetchurl :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
|||
fetchurl v = v >>= \case
|
||||
NVSet s _ -> attrsetGet "url" s >>= force ?? (go (M.lookup "sha256" s))
|
||||
v@NVStr {} -> go Nothing v
|
||||
v@(NVConstant (NUri _)) -> go Nothing v
|
||||
v -> throwError $ ErrorCall $ "builtins.fetchurl: Expected URI or set, got "
|
||||
++ show v
|
||||
where
|
||||
go :: Maybe (NThunk m) -> NValue m -> m (NValue m)
|
||||
go _msha = \case
|
||||
NVStr ns -> getURL (stringIntentionallyDropContext ns) -- msha
|
||||
NVConstant (NUri uri) -> getURL uri -- msha
|
||||
v -> throwError $ ErrorCall $
|
||||
"builtins.fetchurl: Expected URI or string, got " ++ show v
|
||||
|
||||
|
|
|
@ -148,7 +148,6 @@ instance Convertible e m
|
|||
instance (Convertible e m, MonadEffects m)
|
||||
=> FromValue Text m (NValueNF m) where
|
||||
fromValueMay = \case
|
||||
Fix (NVConstantF (NUri u)) -> pure $ Just u
|
||||
Fix (NVStrF ns) -> pure $ stringNoContext ns
|
||||
Fix (NVPathF p) -> Just . Text.pack . unStorePath <$> addPath p
|
||||
Fix (NVSetF s _) -> case M.lookup "outPath" s of
|
||||
|
@ -162,7 +161,6 @@ instance (Convertible e m, MonadEffects m)
|
|||
instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m, MonadEffects m)
|
||||
=> FromValue Text m (NValue m) where
|
||||
fromValueMay = \case
|
||||
NVConstant (NUri u) -> pure $ Just u
|
||||
NVStr ns -> pure $ stringNoContext ns
|
||||
NVPath p -> Just . Text.pack . unStorePath <$> addPath p
|
||||
NVSet s _ -> case M.lookup "outPath" s of
|
||||
|
@ -176,7 +174,6 @@ instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m, MonadEffects m)
|
|||
instance (Convertible e m, MonadEffects m)
|
||||
=> FromValue NixString m (NValueNF m) where
|
||||
fromValueMay = \case
|
||||
Fix (NVConstantF (NUri u)) -> pure $ Just (makeNixStringWithoutContext u)
|
||||
Fix (NVStrF ns) -> pure $ Just ns
|
||||
Fix (NVPathF p) -> Just . makeNixStringWithoutContext . Text.pack . unStorePath <$> addPath p
|
||||
Fix (NVSetF s _) -> case M.lookup "outPath" s of
|
||||
|
@ -190,7 +187,6 @@ instance (Convertible e m, MonadEffects m)
|
|||
instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m, MonadEffects m)
|
||||
=> FromValue NixString m (NValue m) where
|
||||
fromValueMay = \case
|
||||
NVConstant (NUri u) -> pure $ Just (makeNixStringWithoutContext u)
|
||||
NVStr ns -> pure $ Just ns
|
||||
NVPath p -> Just . makeNixStringWithoutContext . Text.pack . unStorePath <$> addPath p
|
||||
NVSet s _ -> case M.lookup "outPath" s of
|
||||
|
@ -224,7 +220,6 @@ newtype Path = Path { getPath :: FilePath }
|
|||
|
||||
instance Convertible e m => FromValue Path m (NValueNF m) where
|
||||
fromValueMay = \case
|
||||
Fix (NVConstantF (NUri u)) -> pure $ Just (Path (Text.unpack u))
|
||||
Fix (NVPathF p) -> pure $ Just (Path p)
|
||||
Fix (NVStrF ns) -> pure $ Path . Text.unpack <$> stringNoContext ns
|
||||
Fix (NVSetF s _) -> case M.lookup "outPath" s of
|
||||
|
@ -238,7 +233,6 @@ instance Convertible e m => FromValue Path m (NValueNF m) where
|
|||
instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m)
|
||||
=> FromValue Path m (NValue m) where
|
||||
fromValueMay = \case
|
||||
NVConstant (NUri u) -> pure $ Just (Path (Text.unpack u))
|
||||
NVPath p -> pure $ Just (Path p)
|
||||
NVStr ns -> pure $ Path . Text.unpack <$> stringNoContext ns
|
||||
NVSet s _ -> case M.lookup "outPath" s of
|
||||
|
@ -328,7 +322,6 @@ instance (Convertible e m, MonadEffects m)
|
|||
NFloat n -> toJSON n
|
||||
NBool b -> toJSON b
|
||||
NNull -> A.Null
|
||||
NUri u -> toJSON u
|
||||
Fix (NVStrF ns) -> pure $ toJSON <$> stringNoContext ns
|
||||
Fix (NVListF l) -> fmap (A.Array . V.fromList) . sequence
|
||||
<$> traverse fromValueMay l
|
||||
|
|
278
src/Nix/Eval.hs
278
src/Nix/Eval.hs
|
@ -1,40 +1,33 @@
|
|||
{-# LANGUAGE AllowAmbiguousTypes #-}
|
||||
{-# LANGUAGE ApplicativeDo #-}
|
||||
{-# LANGUAGE ConstraintKinds #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE FunctionalDependencies #-}
|
||||
{-# LANGUAGE GADTs #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||
{-# LANGUAGE MultiWayIf #-}
|
||||
{-# LANGUAGE PartialTypeSignatures #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE TupleSections #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
|
||||
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
|
||||
|
||||
module Nix.Eval where
|
||||
|
||||
import Control.Arrow (first)
|
||||
import Control.Monad
|
||||
import Control.Monad.Fix
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.State.Strict
|
||||
import Data.Align.Key
|
||||
import Data.Fix
|
||||
import Data.Align.Key (alignWithKey)
|
||||
import Data.Either (isRight)
|
||||
import Data.Fix (Fix(Fix))
|
||||
import Data.HashMap.Lazy (HashMap)
|
||||
import qualified Data.HashMap.Lazy as M
|
||||
import Data.List (partition, foldl')
|
||||
import Data.List (partition)
|
||||
import Data.List.NonEmpty (NonEmpty(..))
|
||||
import qualified Data.List.NonEmpty as NE
|
||||
import Data.Maybe (fromMaybe, catMaybes)
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as Text
|
||||
import Data.These
|
||||
import Data.These (These(..))
|
||||
import Data.Traversable (for)
|
||||
import Nix.Atoms
|
||||
import Nix.Convert
|
||||
|
@ -47,13 +40,12 @@ import Nix.Thunk
|
|||
import Nix.Utils
|
||||
|
||||
class (Show v, Monad m) => MonadEval v m | v -> m where
|
||||
freeVariable :: Text -> m v
|
||||
attrMissing :: NonEmpty Text -> Maybe v -> m v
|
||||
evaledSym :: Text -> v -> m v
|
||||
|
||||
freeVariable :: Text -> m v
|
||||
attrMissing :: NonEmpty Text -> Maybe v -> m v
|
||||
evaledSym :: Text -> v -> m v
|
||||
evalCurPos :: m v
|
||||
evalConstant :: NAtom -> m v
|
||||
evalString :: NixString -> m v
|
||||
evalString :: NString (m v) -> m v
|
||||
evalLiteralPath :: FilePath -> m v
|
||||
evalEnvPath :: FilePath -> m v
|
||||
evalUnary :: NUnaryOp -> v -> m v
|
||||
|
@ -67,7 +59,6 @@ class (Show v, Monad m) => MonadEval v m | v -> m where
|
|||
evalAbs :: Params (m v)
|
||||
-> (forall a. m v -> (AttrSet (m v) -> m v -> m (a, v)) -> m (a, v))
|
||||
-> m v
|
||||
|
||||
{-
|
||||
evalSelect :: v -> NonEmpty Text -> Maybe (m v) -> m v
|
||||
evalHasAttr :: v -> NonEmpty Text -> m v
|
||||
|
@ -83,7 +74,6 @@ class (Show v, Monad m) => MonadEval v m | v -> m where
|
|||
evalLetElem :: Text -> m v -> m v
|
||||
evalLet :: m v -> m v
|
||||
-}
|
||||
|
||||
evalError :: Exception s => s -> m a
|
||||
|
||||
type MonadNixEval e v t m =
|
||||
|
@ -112,54 +102,35 @@ eval (NSym "__curPos") = evalCurPos
|
|||
eval (NSym var) =
|
||||
lookupVar var >>= maybe (freeVariable var) (force ?? evaledSym var)
|
||||
|
||||
eval (NConstant x) = evalConstant x
|
||||
eval (NStr str) = assembleString str >>= \case
|
||||
Nothing -> evalError @v $ ErrorCall "failed to evaluate string"
|
||||
Just e -> evalString e
|
||||
eval (NLiteralPath p) = evalLiteralPath p
|
||||
eval (NEnvPath p) = evalEnvPath p
|
||||
eval (NUnary op arg) = evalUnary op =<< arg
|
||||
eval (NConstant x) = evalConstant x
|
||||
eval (NStr str) = evalString str
|
||||
eval (NLiteralPath p) = evalLiteralPath p
|
||||
eval (NEnvPath p) = evalEnvPath p
|
||||
eval (NUnary op arg) = evalUnary op =<< arg
|
||||
|
||||
eval (NBinary NApp fun arg) = do
|
||||
scope <- currentScopes @_ @t
|
||||
evalApp ?? withScopes scope arg =<< fun
|
||||
fun >>= (`evalApp` withScopes scope arg)
|
||||
|
||||
eval (NBinary op larg rarg) = larg >>= \lval -> evalBinary op lval rarg
|
||||
eval (NBinary op larg rarg) = larg >>= evalBinary op ?? rarg
|
||||
|
||||
eval (NSelect aset attr alt) = do
|
||||
traceM "NSelect"
|
||||
mres <- evalSelect aset attr
|
||||
traceM "NSelect..2"
|
||||
case mres of
|
||||
Right v -> v
|
||||
Left (s, ks) -> fromMaybe (attrMissing ks (Just s)) alt
|
||||
eval (NSelect aset attr alt) = evalSelect aset attr >>= either go id
|
||||
where
|
||||
go (s, ks) = fromMaybe (attrMissing ks (Just s)) alt
|
||||
|
||||
eval (NHasAttr aset attr) =
|
||||
toValue . either (const False) (const True) =<< evalSelect aset attr
|
||||
eval (NHasAttr aset attr) = evalSelect aset attr >>= toValue . isRight
|
||||
|
||||
eval (NList l) = do
|
||||
scope <- currentScopes
|
||||
toValue =<< for l (thunk . withScopes @t scope)
|
||||
for l (thunk . withScopes @t scope) >>= toValue
|
||||
|
||||
eval (NSet binds) = do
|
||||
traceM "NSet..1"
|
||||
(s, p) <- evalBinds True False binds
|
||||
traceM $ "NSet..2: s = " ++ show (void s)
|
||||
traceM $ "NSet..2: p = " ++ show (void p)
|
||||
toValue (s, p)
|
||||
eval (NSet binds) =
|
||||
evalBinds False (desugarBinds (eval . NSet) binds) >>= toValue
|
||||
|
||||
eval (NRecSet binds) = do
|
||||
traceM "NRecSet..1"
|
||||
(s, p) <- evalBinds True True (desugarBinds (eval . NRecSet) binds)
|
||||
traceM $ "NRecSet..2: s = " ++ show (void s)
|
||||
traceM $ "NRecSet..2: p = " ++ show (void p)
|
||||
toValue (s, p)
|
||||
eval (NRecSet binds) =
|
||||
evalBinds True (desugarBinds (eval . NRecSet) binds) >>= toValue
|
||||
|
||||
eval (NLet binds body) = do
|
||||
traceM "Let..1"
|
||||
(s, _) <- evalBinds True True binds
|
||||
traceM $ "Let..2: s = " ++ show (void s)
|
||||
pushScope s body
|
||||
eval (NLet binds body) = evalBinds True binds >>= (pushScope ?? body) . fst
|
||||
|
||||
eval (NIf cond t f) = cond >>= \v -> evalIf v t f
|
||||
|
||||
|
@ -173,99 +144,99 @@ eval (NAbs params body) = do
|
|||
-- we defer here so the present scope is restored when the parameters and
|
||||
-- body are forced during application.
|
||||
scope <- currentScopes @_ @t
|
||||
evalAbs params $ \arg k ->
|
||||
withScopes @t scope $ do
|
||||
args <- buildArgument params arg
|
||||
pushScope args (k (M.map (`force` pure) args) body)
|
||||
evalAbs params $ \arg k -> withScopes @t scope $ do
|
||||
args <- buildArgument params arg
|
||||
pushScope args (k (M.map (`force` pure) args) body)
|
||||
|
||||
-- | If you know that the 'scope' action will result in an 'AttrSet t', then
|
||||
-- this implementation may be used as an implementation for 'evalWith'.
|
||||
evalWithAttrSet :: forall e v t m. MonadNixEval e v t m => m v -> m v -> m v
|
||||
evalWithAttrSet scope body = do
|
||||
evalWithAttrSet aset body = do
|
||||
-- The scope is deliberately wrapped in a thunk here, since it is
|
||||
-- evaluated each time a name is looked up within the weak scope, and
|
||||
-- we want to be sure the action it evaluates is to force a thunk, so
|
||||
-- its value is only computed once.
|
||||
cur <- currentScopes @_ @t
|
||||
s <- thunk $ withScopes cur scope
|
||||
scope <- currentScopes @_ @t
|
||||
s <- thunk $ withScopes scope aset
|
||||
pushWeakScope ?? body $ force s $
|
||||
fmap fst . fromValue @(AttrSet t, AttrSet SourcePos)
|
||||
|
||||
attrSetAlter :: forall e v t m. MonadNixEval e v t m
|
||||
=> [Text]
|
||||
-> SourcePos
|
||||
-> AttrSet (m v)
|
||||
-> AttrSet SourcePos
|
||||
-> m v
|
||||
-> m (AttrSet (m v))
|
||||
attrSetAlter [] _ _ =
|
||||
-> m (AttrSet (m v), AttrSet SourcePos)
|
||||
attrSetAlter [] _ _ _ _ =
|
||||
evalError @v $ ErrorCall "invalid selector with no components"
|
||||
attrSetAlter (p:ps) m val = case M.lookup p m of
|
||||
Nothing
|
||||
| null ps -> go
|
||||
| otherwise -> recurse M.empty
|
||||
Just x
|
||||
| null ps -> go
|
||||
| otherwise ->
|
||||
x >>= fromValue @(AttrSet t, AttrSet SourcePos)
|
||||
>>= \(s, _) -> recurse (force ?? pure <$> s)
|
||||
where
|
||||
go = return $ M.insert p val m
|
||||
|
||||
recurse s = attrSetAlter ps s val <&> \m' ->
|
||||
M.insert p (toValue @(AttrSet t, AttrSet SourcePos)
|
||||
=<< fmap (, mempty)
|
||||
(fmap (value @_ @_ @m) <$> sequence m')) m
|
||||
attrSetAlter (k:ks) pos m p val = case M.lookup k m of
|
||||
Nothing | null ks -> go
|
||||
| otherwise -> recurse M.empty M.empty
|
||||
Just x | null ks -> go
|
||||
| otherwise ->
|
||||
x >>= fromValue @(AttrSet t, AttrSet SourcePos)
|
||||
>>= \(st, sp) -> recurse (force ?? pure <$> st) sp
|
||||
where
|
||||
go = return (M.insert k val m, M.insert k pos p)
|
||||
|
||||
recurse st sp = attrSetAlter ks pos st sp val <&> \(st', _) ->
|
||||
( M.insert k (toValue @(AttrSet t, AttrSet SourcePos)
|
||||
=<< (, mempty) . fmap value <$> sequence st') st
|
||||
, M.insert k pos sp )
|
||||
|
||||
desugarBinds :: forall r. ([Binding r] -> r) -> [Binding r] -> [Binding r]
|
||||
desugarBinds embed binds = evalState (mapM (go <=< collect) binds) M.empty
|
||||
where
|
||||
collect :: Binding r
|
||||
-> State (HashMap VarName (Maybe SourcePos, [Binding r]))
|
||||
-> State (HashMap VarName (SourcePos, [Binding r]))
|
||||
(Either VarName (Binding r))
|
||||
collect (NamedVar (StaticKey x p:|y:ys) val) = do
|
||||
collect (NamedVar (StaticKey x :| y:ys) val p) = do
|
||||
m <- get
|
||||
let v = case M.lookup x m of
|
||||
Nothing -> (p, [NamedVar (y:|ys) val])
|
||||
Just (p, v) -> (p, NamedVar (y:|ys) val : v)
|
||||
put $ M.insert x v m
|
||||
put $ M.insert x ?? m $ case M.lookup x m of
|
||||
Nothing -> (p, [NamedVar (y:|ys) val p])
|
||||
Just (q, v) -> (q, NamedVar (y:|ys) val q : v)
|
||||
pure $ Left x
|
||||
collect x = pure $ Right x
|
||||
|
||||
go :: Either VarName (Binding r)
|
||||
-> State (HashMap VarName (Maybe SourcePos, [Binding r]))
|
||||
-> State (HashMap VarName (SourcePos, [Binding r]))
|
||||
(Binding r)
|
||||
go (Right x) = pure x
|
||||
go (Left x) = do
|
||||
Just (p, v) <- gets $ M.lookup x
|
||||
pure $ NamedVar (StaticKey x p :| []) (embed v)
|
||||
pure $ NamedVar (StaticKey x :| []) (embed v) p
|
||||
|
||||
evalBinds :: forall e v t m. MonadNixEval e v t m
|
||||
=> Bool
|
||||
-> Bool
|
||||
-> [Binding (m v)]
|
||||
-> m (AttrSet t, AttrSet SourcePos)
|
||||
evalBinds allowDynamic recursive binds = do
|
||||
evalBinds recursive binds = do
|
||||
scope <- currentScopes @_ @t
|
||||
buildResult scope . concat =<< mapM (go scope) (moveOverridesLast binds)
|
||||
where
|
||||
moveOverridesLast = (\(x, y) -> y ++ x) .
|
||||
partition (\case NamedVar (StaticKey "__overrides" _ :| []) _ -> True
|
||||
partition (\case NamedVar (StaticKey "__overrides" :| []) _ _pos -> True
|
||||
_ -> False)
|
||||
|
||||
go :: Scopes m t -> Binding (m v) -> m [([Text], Maybe SourcePos, m v)]
|
||||
go _ (NamedVar (StaticKey "__overrides" _ :| []) finalValue) =
|
||||
go :: Scopes m t -> Binding (m v) -> m [([Text], SourcePos, m v)]
|
||||
go _ (NamedVar (StaticKey "__overrides" :| []) finalValue pos) =
|
||||
finalValue >>= fromValue >>= \(o', p') ->
|
||||
return $ map (\(k, v) -> ([k], M.lookup k p', force v pure))
|
||||
-- jww (2018-05-09): What to do with the key position here?
|
||||
return $ map (\(k, v) -> ([k], fromMaybe pos (M.lookup k p'),
|
||||
force v pure))
|
||||
(M.toList o')
|
||||
|
||||
go _ (NamedVar pathExpr finalValue) = do
|
||||
let go :: NAttrPath (m v) -> m ([Text], Maybe SourcePos, m v)
|
||||
go _ (NamedVar pathExpr finalValue pos) = do
|
||||
let go :: NAttrPath (m v) -> m ([Text], SourcePos, m v)
|
||||
go = \case
|
||||
h :| t -> evalSetterKeyName allowDynamic h >>= \case
|
||||
(Nothing, _) ->
|
||||
pure ([], Nothing,
|
||||
h :| t -> evalSetterKeyName h >>= \case
|
||||
Nothing ->
|
||||
pure ([], nullPos,
|
||||
toValue @(AttrSet t, AttrSet SourcePos)
|
||||
(mempty, mempty))
|
||||
(Just k, pos) -> case t of
|
||||
Just k -> case t of
|
||||
[] -> pure ([k], pos, finalValue)
|
||||
x:xs -> do
|
||||
(restOfPath, _, v) <- go (x:|xs)
|
||||
|
@ -276,10 +247,10 @@ evalBinds allowDynamic recursive binds = do
|
|||
([], _, _) -> []
|
||||
result -> [result]
|
||||
|
||||
go scope (Inherit ms names) = fmap catMaybes $ forM names $ \name ->
|
||||
evalSetterKeyName allowDynamic name >>= \case
|
||||
(Nothing, _) -> return Nothing
|
||||
(Just key, pos) -> return $ Just ([key], pos, do
|
||||
go scope (Inherit ms names pos) = fmap catMaybes $ forM names $
|
||||
evalSetterKeyName >=> \case
|
||||
Nothing -> pure Nothing
|
||||
Just key -> pure $ Just ([key], pos, do
|
||||
mv <- case ms of
|
||||
Nothing -> withScopes scope $ lookupVar key
|
||||
Just s -> s
|
||||
|
@ -291,97 +262,55 @@ evalBinds allowDynamic recursive binds = do
|
|||
Just v -> force v pure)
|
||||
|
||||
buildResult :: Scopes m t
|
||||
-> [([Text], Maybe SourcePos, m v)]
|
||||
-> [([Text], SourcePos, m v)]
|
||||
-> m (AttrSet t, AttrSet SourcePos)
|
||||
buildResult scope bindings = do
|
||||
s <- foldM insert M.empty bindings
|
||||
(s, p) <- foldM insert (M.empty, M.empty) bindings
|
||||
res <- if recursive
|
||||
then loebM (encapsulate <$> s)
|
||||
else traverse (thunk . withScopes scope) s
|
||||
return (res, foldl' go M.empty bindings)
|
||||
else traverse mkThunk s
|
||||
return (res, p)
|
||||
where
|
||||
go m ([k], Just pos, _) = M.insert k pos m
|
||||
go m _ = m
|
||||
mkThunk = thunk . withScopes scope
|
||||
|
||||
encapsulate f attrs =
|
||||
thunk . withScopes scope . pushScope attrs $ f
|
||||
encapsulate f attrs = mkThunk . pushScope attrs $ f
|
||||
|
||||
insert m (path, _, value) = attrSetAlter path m value
|
||||
insert (m, p) (path, pos, value) = attrSetAlter path pos m p value
|
||||
|
||||
evalSelect :: forall e v t m. MonadNixEval e v t m
|
||||
=> m v
|
||||
-> NAttrPath (m v)
|
||||
-> m (Either (v, NonEmpty Text) (m v))
|
||||
evalSelect aset attr = do
|
||||
traceM "evalSelect"
|
||||
s <- aset
|
||||
traceM "evalSelect..2"
|
||||
path <- evalSelector True attr
|
||||
traceM $ "evalSelect..3: " ++ show path
|
||||
res <- extract s path
|
||||
traceM "evalSelect..4"
|
||||
return res
|
||||
path <- traverse evalGetterKeyName attr
|
||||
extract s path
|
||||
where
|
||||
extract x path@(k:|ks) = fromValueMay x >>= \case
|
||||
Just (s :: AttrSet t, p :: AttrSet SourcePos) ->
|
||||
case M.lookup k s of
|
||||
Just t -> do
|
||||
traceM $ "Forcing value at selector " ++ Text.unpack k
|
||||
case ks of
|
||||
[] -> pure $ Right $ force t pure
|
||||
y:ys -> force t $ extract ?? (y:|ys)
|
||||
Nothing ->
|
||||
Left . (, path) <$> toValue (s, p)
|
||||
Nothing ->
|
||||
return $ Left (x, path)
|
||||
|
||||
evalSelector :: (MonadEval v m, FromValue NixString m v)
|
||||
=> Bool -> NAttrPath (m v) -> m (NonEmpty Text)
|
||||
evalSelector allowDynamic binds =
|
||||
NE.map fst <$> traverse (evalGetterKeyName allowDynamic) binds
|
||||
Just (s :: AttrSet t, p :: AttrSet SourcePos)
|
||||
| Just t <- M.lookup k s -> case ks of
|
||||
[] -> pure $ Right $ force t pure
|
||||
y:ys -> force t $ extract ?? (y:|ys)
|
||||
| otherwise -> Left . (, path) <$> toValue (s, p)
|
||||
Nothing -> return $ Left (x, path)
|
||||
|
||||
-- | Evaluate a component of an attribute path in a context where we are
|
||||
-- *retrieving* a value
|
||||
evalGetterKeyName :: (MonadEval v m, FromValue NixString m v)
|
||||
=> Bool -> NKeyName (m v) -> m (Text, Maybe SourcePos)
|
||||
evalGetterKeyName canBeDynamic
|
||||
| canBeDynamic = evalKeyNameDynamicNotNull
|
||||
| otherwise = evalKeyNameStatic
|
||||
|
||||
evalKeyNameStatic :: forall v m. MonadEval v m
|
||||
=> NKeyName (m v) -> m (Text, Maybe SourcePos)
|
||||
evalKeyNameStatic = \case
|
||||
StaticKey k p -> pure (k, p)
|
||||
DynamicKey _ ->
|
||||
evalError @v $ ErrorCall "dynamic attribute not allowed in this context"
|
||||
|
||||
evalKeyNameDynamicNotNull
|
||||
:: forall v m. (MonadEval v m, FromValue NixString m v)
|
||||
=> NKeyName (m v) -> m (Text, Maybe SourcePos)
|
||||
evalKeyNameDynamicNotNull = evalKeyNameDynamicNullable >=> \case
|
||||
(Nothing, _) ->
|
||||
evalError @v $ ErrorCall "value is null while a string was expected"
|
||||
(Just k, p) -> pure (k, p)
|
||||
evalGetterKeyName :: forall v m. (MonadEval v m, FromValue NixString m v)
|
||||
=> NKeyName (m v) -> m Text
|
||||
evalGetterKeyName = evalSetterKeyName >=> \case
|
||||
Just k -> pure k
|
||||
Nothing -> evalError @v $ ErrorCall "value is null while a string was expected"
|
||||
|
||||
-- | Evaluate a component of an attribute path in a context where we are
|
||||
-- *binding* a value
|
||||
evalSetterKeyName :: (MonadEval v m, FromValue NixString m v)
|
||||
=> Bool -> NKeyName (m v) -> m (Maybe Text, Maybe SourcePos)
|
||||
evalSetterKeyName canBeDynamic
|
||||
| canBeDynamic = evalKeyNameDynamicNullable
|
||||
| otherwise = fmap (first Just) . evalKeyNameStatic
|
||||
|
||||
-- | Returns Nothing iff the key value is null
|
||||
evalKeyNameDynamicNullable
|
||||
:: forall v m. (MonadEval v m, FromValue NixString m v)
|
||||
=> NKeyName (m v)
|
||||
-> m (Maybe Text, Maybe SourcePos)
|
||||
evalKeyNameDynamicNullable = \case
|
||||
StaticKey k p -> pure (Just k, p)
|
||||
DynamicKey k ->
|
||||
runAntiquoted "\n" assembleString (>>= fromValueMay) k
|
||||
<&> \case Just ns -> (stringNoContext ns, Nothing)
|
||||
_ -> (Nothing, Nothing)
|
||||
=> NKeyName (m v) -> m (Maybe Text)
|
||||
evalSetterKeyName = \case
|
||||
StaticKey k -> pure (Just k)
|
||||
DynamicKey k -> runAntiquoted "\n" assembleString (>>= fromValueMay) k
|
||||
<&> \case Just (t, _) -> Just t
|
||||
_ -> Nothing
|
||||
|
||||
assembleString :: forall v m. (MonadEval v m, FromValue NixString m v)
|
||||
=> NString (m v) -> m (Maybe NixString)
|
||||
|
@ -389,17 +318,16 @@ assembleString = \case
|
|||
Indented _ parts -> fromParts parts
|
||||
DoubleQuoted parts -> fromParts parts
|
||||
where
|
||||
go = runAntiquoted "\n" (pure . Just . makeNixStringWithoutContext) (>>= fromValueMay)
|
||||
fromParts = fmap (fmap mconcat . sequence) . traverse go
|
||||
|
||||
fromParts parts = fmap mconcat . sequence <$> mapM go parts
|
||||
go = runAntiquoted "\n" (pure . Just . makeNixStringWithoutContext) (>>= fromValueMay)
|
||||
|
||||
buildArgument :: forall e v t m. MonadNixEval e v t m
|
||||
=> Params (m v) -> m v -> m (AttrSet t)
|
||||
buildArgument params arg = do
|
||||
scope <- currentScopes @_ @t
|
||||
case params of
|
||||
Param name -> M.singleton name
|
||||
<$> thunk (withScopes scope arg)
|
||||
Param name -> M.singleton name <$> thunk (withScopes scope arg)
|
||||
ParamSet s isVariadic m ->
|
||||
arg >>= fromValue @(AttrSet t, AttrSet SourcePos)
|
||||
>>= \(args, _) -> do
|
||||
|
|
195
src/Nix/Exec.hs
195
src/Nix/Exec.hs
|
@ -44,6 +44,7 @@ import Data.IORef
|
|||
import Data.List
|
||||
import qualified Data.List.NonEmpty as NE
|
||||
import Data.List.Split
|
||||
import Data.Monoid
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as Text
|
||||
import Data.Typeable
|
||||
|
@ -67,7 +68,9 @@ import Nix.Scope
|
|||
import Nix.Thunk
|
||||
import Nix.Utils
|
||||
import Nix.Value
|
||||
#ifdef MIN_VERSION_haskeline
|
||||
import System.Console.Haskeline.MonadException hiding (catch)
|
||||
#endif
|
||||
import System.Directory
|
||||
import System.Environment
|
||||
import System.Exit (ExitCode (ExitSuccess))
|
||||
|
@ -77,6 +80,9 @@ import System.Posix.Files
|
|||
import System.Process (readProcessWithExitCode)
|
||||
import Text.PrettyPrint.ANSI.Leijen (text)
|
||||
import qualified Text.PrettyPrint.ANSI.Leijen as P
|
||||
#ifdef MIN_VERSION_pretty_show
|
||||
import qualified Text.Show.Pretty as PS
|
||||
#endif
|
||||
|
||||
#ifdef MIN_VERSION_ghc_datasize
|
||||
#if MIN_VERSION_ghc_datasize(0,2,0) && __GLASGOW_HASKELL__ >= 804
|
||||
|
@ -179,11 +185,13 @@ instance MonadNix e m => MonadEval (NValue m) m where
|
|||
span <- currentPos
|
||||
pure $ nvConstantP (Provenance scope (NConstant_ span c)) c
|
||||
|
||||
evalString ns = do
|
||||
scope <- currentScopes
|
||||
span <- currentPos
|
||||
pure $ nvStrP (Provenance scope
|
||||
(NStr_ span (DoubleQuoted [Plain (stringIntentionallyDropContext ns)]))) ns
|
||||
evalString = assembleString >=> \case
|
||||
Just (s, c) -> do
|
||||
scope <- currentScopes
|
||||
span <- currentPos
|
||||
pure $ nvStrP (Provenance scope
|
||||
(NStr_ span (DoubleQuoted [Plain s]))) s c
|
||||
Nothing -> nverr $ ErrorCall "Failed to assemble string"
|
||||
|
||||
evalLiteralPath p = do
|
||||
scope <- currentScopes
|
||||
|
@ -323,8 +331,8 @@ execBinaryOp scope span op lval rarg = do
|
|||
NBool l, NBool r) -> toBool $ not l || r
|
||||
_ -> nverr $ ErrorCall $ unsupportedTypes lval rval
|
||||
|
||||
(NVStr ls, NVStr rs) -> case op of
|
||||
NPlus -> pure $ bin nvStrP (ls `mappend` rs)
|
||||
(NVStr ls lc, NVStr rs rc) -> case op of
|
||||
NPlus -> pure $ bin nvStrP (ls `mappend` rs) (lc `mappend` rc)
|
||||
NEq -> toBool =<< valueEq lval rval
|
||||
NNEq -> toBool . not =<< valueEq lval rval
|
||||
NLt -> toBool $ ls < rs
|
||||
|
@ -361,6 +369,20 @@ execBinaryOp scope span op lval rarg = do
|
|||
NNEq -> toBool . not =<< valueEq (nvSet M.empty M.empty) rval
|
||||
_ -> nverr $ ErrorCall $ unsupportedTypes lval rval
|
||||
|
||||
(ls@NVSet {}, NVStr rs) -> case op of
|
||||
NPlus -> (\lx -> bin nvStrP (modifyNixContents (Text.pack lx `mappend`) rs))
|
||||
<$> coerceToString False ls
|
||||
NEq -> toBool =<< valueEq lval rval
|
||||
NNEq -> toBool . not =<< valueEq lval rval
|
||||
_ -> nverr $ ErrorCall $ unsupportedTypes lval rval
|
||||
|
||||
(NVStr ls, rs@NVSet {}) -> case op of
|
||||
NPlus -> (\rx -> bin nvStrP (modifyNixContents (`mappend` Text.pack rx) ls))
|
||||
<$> coerceToString False rs
|
||||
NEq -> toBool =<< valueEq lval rval
|
||||
NNEq -> toBool . not =<< valueEq lval rval
|
||||
_ -> nverr $ ErrorCall $ unsupportedTypes lval rval
|
||||
|
||||
(NVList ls, NVList rs) -> case op of
|
||||
NConcat -> pure $ bin nvListP $ ls ++ rs
|
||||
NEq -> toBool =<< valueEq lval rval
|
||||
|
@ -382,9 +404,7 @@ execBinaryOp scope span op lval rarg = do
|
|||
(NVPath p, NVStr ns) -> case op of
|
||||
NEq -> toBool $ Just p == fmap Text.unpack (stringNoContext ns)
|
||||
NNEq -> toBool $ Just p /= fmap Text.unpack (stringNoContext ns)
|
||||
NPlus -> case stringNoContext ns of
|
||||
Just s -> bin nvPathP <$> makeAbsolutePath (p `mappend` Text.unpack s)
|
||||
Nothing -> nverr $ ErrorCall $ unsupportedTypes lval rval
|
||||
NPlus -> bin nvPathP <$> makeAbsolutePath (p `mappend` Text.unpack (stringIntentionallyDropContext ns))
|
||||
_ -> nverr $ ErrorCall $ unsupportedTypes lval rval
|
||||
|
||||
(NVPath ls, NVPath rs) -> case op of
|
||||
|
@ -419,27 +439,29 @@ execBinaryOp scope span op lval rarg = do
|
|||
toInt = pure . bin nvConstantP . NInt
|
||||
toFloat = pure . bin nvConstantP . NFloat
|
||||
|
||||
coerceToString :: MonadNix e m => NValue m -> m String
|
||||
coerceToString = \case
|
||||
NVConstant (NBool b)
|
||||
| b -> pure "1"
|
||||
| otherwise -> pure ""
|
||||
NVConstant (NInt n) -> pure $ show n
|
||||
NVConstant (NFloat n) -> pure $ show n
|
||||
NVConstant (NUri u) -> pure $ show u
|
||||
NVConstant NNull -> pure ""
|
||||
coerceToString :: MonadNix e m => Bool -> NValue m -> m String
|
||||
coerceToString copyToStore = go
|
||||
where
|
||||
go = \case
|
||||
NVConstant (NBool b)
|
||||
| b -> pure "1"
|
||||
| otherwise -> pure ""
|
||||
NVConstant (NInt n) -> pure $ show n
|
||||
NVConstant (NFloat n) -> pure $ show n
|
||||
NVConstant NNull -> pure ""
|
||||
|
||||
NVStr ns -> pure $ Text.unpack $ stringIntentionallyDropContext ns
|
||||
NVPath p -> unStorePath <$> addPath p
|
||||
NVList l -> unwords <$> traverse (`force` coerceToString) l
|
||||
NVStr ns _ -> pure $ Text.unpack (stringIntentionallyDropContext ns)
|
||||
NVPath p | copyToStore -> unStorePath <$> addPath p
|
||||
| otherwise -> pure p
|
||||
NVList l -> unwords <$> traverse (`force` go) l
|
||||
|
||||
v@(NVSet s _) | Just p <- M.lookup "__toString" s ->
|
||||
force p $ (`callFunc` pure v) >=> coerceToString
|
||||
v@(NVSet s _) | Just p <- M.lookup "__toString" s ->
|
||||
force p $ (`callFunc` pure v) >=> go
|
||||
|
||||
NVSet s _ | Just p <- M.lookup "outPath" s ->
|
||||
force p coerceToString
|
||||
NVSet s _ | Just p <- M.lookup "outPath" s ->
|
||||
force p go
|
||||
|
||||
v -> throwError $ ErrorCall $ "Expected a string, but saw: " ++ show v
|
||||
v -> throwError $ ErrorCall $ "Expected a string, but saw: " ++ show v
|
||||
|
||||
newtype Lazy m a = Lazy
|
||||
{ runLazy :: ReaderT (Context (Lazy m) (NThunk (Lazy m)))
|
||||
|
@ -466,10 +488,12 @@ instance MonadCatch m => MonadCatch (Lazy m) where
|
|||
instance MonadThrow m => MonadThrow (Lazy m) where
|
||||
throwM = Lazy . throwM
|
||||
|
||||
#ifdef MIN_VERSION_haskeline
|
||||
instance MonadException m => MonadException (Lazy m) where
|
||||
controlIO f = Lazy $ controlIO $ \(RunIO run) ->
|
||||
let run' = RunIO (fmap Lazy . run . runLazy)
|
||||
in runLazy <$> f run'
|
||||
#endif
|
||||
|
||||
instance (MonadFix m, MonadCatch m, MonadIO m, Alternative m,
|
||||
MonadPlus m, Typeable m)
|
||||
|
@ -484,6 +508,12 @@ instance (MonadFix m, MonadCatch m, MonadIO m, Alternative m,
|
|||
_ -> throwError $ ErrorCall $
|
||||
"addPath: failed: nix-store --add " ++ show path
|
||||
|
||||
toFile_ filepath content = do
|
||||
liftIO $ writeFile filepath content
|
||||
storepath <- addPath filepath
|
||||
liftIO $ removeFile filepath
|
||||
return storepath
|
||||
|
||||
makeAbsolutePath origPath = do
|
||||
origPathExpanded <- liftIO $ expandHomePath origPath
|
||||
absPath <- if isAbsolute origPathExpanded then pure origPathExpanded else do
|
||||
|
@ -502,6 +532,8 @@ instance (MonadFix m, MonadCatch m, MonadIO m, Alternative m,
|
|||
|
||||
findEnvPath = findEnvPathM
|
||||
|
||||
findPath = findPathM
|
||||
|
||||
pathExists = liftIO . fileExist
|
||||
|
||||
importPath scope origPath = do
|
||||
|
@ -570,7 +602,7 @@ instance (MonadFix m, MonadCatch m, MonadIO m, Alternative m,
|
|||
"__ignoreNulls" -> pure Nothing
|
||||
_ -> force v $ \case
|
||||
NVConstant NNull | ignoreNulls -> pure Nothing
|
||||
v' -> Just <$> (toNix =<< Text.pack <$> coerceToString v')
|
||||
v' -> Just <$> (toNix =<< Text.pack <$> coerceToString True v')
|
||||
|
||||
nixInstantiateExpr expr = do
|
||||
traceM $ "Executing: "
|
||||
|
@ -613,12 +645,12 @@ instance (MonadFix m, MonadCatch m, MonadIO m, Alternative m,
|
|||
-- return response
|
||||
let status = statusCode (responseStatus response)
|
||||
if status /= 200
|
||||
then throwError $ ErrorCall $
|
||||
then throwError $ ErrorCall $
|
||||
"fail, got " ++ show status ++ " when fetching url:" ++ urlstr
|
||||
else -- do
|
||||
-- let bstr = responseBody response
|
||||
-- liftIO $ print bstr
|
||||
throwError $ ErrorCall $
|
||||
throwError $ ErrorCall $
|
||||
"success in downloading but hnix-store is not yet ready; url = " ++ urlstr
|
||||
|
||||
traceEffect = liftIO . putStrLn
|
||||
|
@ -676,49 +708,66 @@ x <///> y | isAbsolute y || "." `isPrefixOf` y = x </> y
|
|||
joinPath $ head [ xs ++ drop (length tx) ys
|
||||
| tx <- tails xs, tx `elem` inits ys ]
|
||||
|
||||
nixFilePath :: (MonadEffects m, MonadIO m) => FilePath -> m (Maybe FilePath)
|
||||
nixFilePath path = do
|
||||
path <- makeAbsolutePath path
|
||||
exists <- liftIO $ doesDirectoryExist path
|
||||
path' <- if exists
|
||||
then makeAbsolutePath $ path </> "default.nix"
|
||||
else return path
|
||||
exists <- liftIO $ doesFileExist path'
|
||||
return $ if exists then Just path' else Nothing
|
||||
|
||||
findEnvPathM :: forall e m. (MonadNix e m, MonadIO m)
|
||||
=> FilePath -> m FilePath
|
||||
findEnvPathM name = do
|
||||
mres <- lookupVar @_ @(NThunk m) "__nixPath"
|
||||
mpath <- case mres of
|
||||
Nothing -> error "impossible"
|
||||
Just x -> force x $ fromValue >=> \(l :: [NThunk m]) ->
|
||||
foldM go Nothing l
|
||||
findPathBy :: forall e m. (MonadNix e m, MonadIO m) =>
|
||||
(FilePath -> m (Maybe FilePath)) ->
|
||||
[NThunk m] -> FilePath -> m FilePath
|
||||
findPathBy finder l name = do
|
||||
mpath <- foldM go Nothing l
|
||||
case mpath of
|
||||
Nothing ->
|
||||
throwError $ ErrorCall $ "file '" ++ name
|
||||
++ "' was not found in the Nix search path"
|
||||
++ " (add it using $NIX_PATH or -I)"
|
||||
Just path -> return path
|
||||
where
|
||||
go :: Maybe FilePath -> NThunk m -> m (Maybe FilePath)
|
||||
go p@(Just _) _ = pure p
|
||||
go Nothing l = force l $ fromValue >=> \(s :: HashMap Text (NThunk m)) ->
|
||||
case M.lookup "path" s of
|
||||
Just p -> force p $ fromValue >=> \(Path path) ->
|
||||
case M.lookup "prefix" s of
|
||||
Nothing -> tryPath path Nothing
|
||||
Just pf -> force pf $ fromValueMay >=> \case
|
||||
Just (pfx :: Text) | not (Text.null pfx) ->
|
||||
tryPath path (Just (Text.unpack pfx))
|
||||
_ -> tryPath path Nothing
|
||||
Nothing ->
|
||||
throwError $ ErrorCall $ "__nixPath must be a list of attr sets"
|
||||
++ " with 'path' elements, but saw: " ++ show s
|
||||
where
|
||||
go :: Maybe FilePath -> NThunk m -> m (Maybe FilePath)
|
||||
go p@(Just _) _ = pure p
|
||||
go Nothing l = force l $ fromValue >=>
|
||||
\(s :: HashMap Text (NThunk m)) ->
|
||||
case M.lookup "path" s of
|
||||
Just p -> force p $ fromValue >=> \(Path path) ->
|
||||
case M.lookup "prefix" s of
|
||||
Nothing -> tryPath path Nothing
|
||||
Just pf -> force pf $ fromValueMay >=> \case
|
||||
Just (pfx :: Text) | not (Text.null pfx) ->
|
||||
tryPath path (Just (Text.unpack pfx))
|
||||
_ -> tryPath path Nothing
|
||||
Nothing ->
|
||||
throwError $ ErrorCall $ "__nixPath must be a list of attr sets"
|
||||
++ " with 'path' elements, but saw: " ++ show s
|
||||
|
||||
tryPath p (Just n) | n':ns <- splitDirectories name, n == n' =
|
||||
nixFilePath $ p <///> joinPath ns
|
||||
tryPath p _ = nixFilePath $ p <///> name
|
||||
tryPath p (Just n) | n':ns <- splitDirectories name, n == n' =
|
||||
finder $ p <///> joinPath ns
|
||||
tryPath p _ = finder $ p <///> name
|
||||
|
||||
findPathM :: forall e m. (MonadNix e m, MonadIO m) =>
|
||||
[NThunk m] -> FilePath -> m FilePath
|
||||
findPathM l name = findPathBy path l name
|
||||
where
|
||||
path :: (MonadEffects m, MonadIO m) => FilePath -> m (Maybe FilePath)
|
||||
path path = do
|
||||
path <- makeAbsolutePath path
|
||||
exists <- liftIO $ doesPathExist path
|
||||
return $ if exists then Just path else Nothing
|
||||
|
||||
findEnvPathM :: forall e m. (MonadNix e m, MonadIO m)
|
||||
=> FilePath -> m FilePath
|
||||
findEnvPathM name = do
|
||||
mres <- lookupVar @_ @(NThunk m) "__nixPath"
|
||||
case mres of
|
||||
Nothing -> error "impossible"
|
||||
Just x -> force x $ fromValue >=> \(l :: [NThunk m]) ->
|
||||
findPathBy nixFilePath l name
|
||||
where
|
||||
nixFilePath :: (MonadEffects m, MonadIO m) => FilePath -> m (Maybe FilePath)
|
||||
nixFilePath path = do
|
||||
path <- makeAbsolutePath path
|
||||
exists <- liftIO $ doesDirectoryExist path
|
||||
path' <- if exists
|
||||
then makeAbsolutePath $ path </> "default.nix"
|
||||
else return path
|
||||
exists <- liftIO $ doesFileExist path'
|
||||
return $ if exists then Just path' else Nothing
|
||||
|
||||
addTracing :: (MonadNix e m, Has e Options, MonadIO m,
|
||||
MonadReader Int n, Alternative n)
|
||||
|
@ -732,13 +781,17 @@ addTracing k v = do
|
|||
opts :: Options <- asks (view hasLens)
|
||||
let rendered =
|
||||
if verbose opts >= Chatty
|
||||
then show (void x)
|
||||
else show (prettyNix (Fix (Fix (NSym "?") <$ x)))
|
||||
msg x = "eval: " ++ replicate depth ' ' ++ x
|
||||
loc <- renderLocation span (text (msg rendered ++ " ..."))
|
||||
#ifdef MIN_VERSION_pretty_show
|
||||
then text $ PS.ppShow (void x)
|
||||
#else
|
||||
then text $ show (void x)
|
||||
#endif
|
||||
else prettyNix (Fix (Fix (NSym "?") <$ x))
|
||||
msg x = text ("eval: " ++ replicate depth ' ') <> x
|
||||
loc <- renderLocation span (msg rendered <> text " ...\n")
|
||||
liftIO $ putStr $ show loc
|
||||
res <- k v'
|
||||
liftIO $ putStrLn $ msg (rendered ++ " ...done")
|
||||
liftIO $ print $ msg rendered <> text " ...done"
|
||||
return res
|
||||
|
||||
evalExprLoc :: forall e m. (MonadNix e m, Has e Options, MonadIO m)
|
||||
|
|
|
@ -13,6 +13,7 @@ import Data.Monoid
|
|||
import Data.Text (Text)
|
||||
import Nix.Atoms
|
||||
import Nix.Expr.Types
|
||||
import Text.Megaparsec.Pos (SourcePos)
|
||||
|
||||
-- | Make an integer literal expression.
|
||||
mkInt :: Integer -> NExpr
|
||||
|
@ -40,13 +41,6 @@ mkIndentedStr w = Fix . NStr . Indented w . \case
|
|||
"" -> []
|
||||
x -> [Plain x]
|
||||
|
||||
-- | Make a literal URI expression.
|
||||
mkUri :: Text -> NExpr
|
||||
mkUri = Fix . mkUriF
|
||||
|
||||
mkUriF :: Text -> NExprF a
|
||||
mkUriF = NConstant . NUri
|
||||
|
||||
-- | Make a path. Use 'True' if the path should be read from the
|
||||
-- environment, else 'False'.
|
||||
mkPath :: Bool -> FilePath -> NExpr
|
||||
|
@ -78,7 +72,7 @@ mkSymF :: Text -> NExprF a
|
|||
mkSymF = NSym
|
||||
|
||||
mkSelector :: Text -> NAttrPath NExpr
|
||||
mkSelector = (:| []) . flip StaticKey Nothing
|
||||
mkSelector = (:| []) . StaticKey
|
||||
|
||||
mkBool :: Bool -> NExpr
|
||||
mkBool = Fix . mkBoolF
|
||||
|
@ -140,16 +134,16 @@ mkDots e keys = Fix $ NSelect e (map (StaticKey ?? Nothing) keys) Nothing
|
|||
-}
|
||||
|
||||
-- | An `inherit` clause without an expression to pull from.
|
||||
inherit :: [NKeyName e] -> Binding e
|
||||
inherit :: [NKeyName e] -> SourcePos -> Binding e
|
||||
inherit = Inherit Nothing
|
||||
|
||||
-- | An `inherit` clause with an expression to pull from.
|
||||
inheritFrom :: e -> [NKeyName e] -> Binding e
|
||||
inheritFrom :: e -> [NKeyName e] -> SourcePos -> Binding e
|
||||
inheritFrom expr = Inherit (Just expr)
|
||||
|
||||
-- | Shorthand for producing a binding of a name to an expression.
|
||||
bindTo :: Text -> NExpr -> Binding NExpr
|
||||
bindTo name = NamedVar (mkSelector name)
|
||||
bindTo name x = NamedVar (mkSelector name) x nullPos
|
||||
|
||||
-- | Infix version of bindTo.
|
||||
($=) :: Text -> NExpr -> Binding NExpr
|
||||
|
@ -233,5 +227,5 @@ infixl 1 @@
|
|||
infixr 1 ==>
|
||||
|
||||
(@.) :: NExpr -> Text -> NExpr
|
||||
obj @. name = Fix (NSelect obj (StaticKey name Nothing :| []) Nothing)
|
||||
obj @. name = Fix (NSelect obj (StaticKey name :| []) Nothing)
|
||||
infixl 2 @.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{-# LANGUAGE BangPatterns #-}
|
||||
{-# LANGUAGE ConstraintKinds #-}
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DeriveAnyClass #-}
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
{-# LANGUAGE DeriveFoldable #-}
|
||||
|
@ -26,8 +27,10 @@
|
|||
-- | The nix expression type and supporting types.
|
||||
module Nix.Expr.Types where
|
||||
|
||||
#ifdef MIN_VERSION_serialise
|
||||
import Codec.Serialise (Serialise)
|
||||
import qualified Codec.Serialise as Ser
|
||||
#endif
|
||||
import Control.Applicative
|
||||
import Control.DeepSeq
|
||||
import Control.Monad
|
||||
|
@ -40,7 +43,9 @@ import Data.Eq.Deriving
|
|||
import Data.Fix
|
||||
import Data.Functor.Classes
|
||||
import Data.Hashable
|
||||
#if MIN_VERSION_hashable(1, 2, 5)
|
||||
import Data.Hashable.Lifted
|
||||
#endif
|
||||
import Data.List (inits, tails)
|
||||
import Data.List.NonEmpty (NonEmpty(..))
|
||||
import qualified Data.List.NonEmpty as NE
|
||||
|
@ -53,19 +58,37 @@ import GHC.Exts
|
|||
import GHC.Generics
|
||||
import Language.Haskell.TH.Syntax
|
||||
import Lens.Family2
|
||||
import Lens.Family2.Stock (_1)
|
||||
import Lens.Family2.TH
|
||||
import Nix.Atoms
|
||||
import Nix.Utils
|
||||
import Text.Megaparsec.Pos
|
||||
import Text.Read.Deriving
|
||||
import Text.Show.Deriving
|
||||
#if MIN_VERSION_base(4, 10, 0)
|
||||
import Type.Reflection (eqTypeRep)
|
||||
import qualified Type.Reflection as Reflection
|
||||
#endif
|
||||
|
||||
type VarName = Text
|
||||
|
||||
instance Hashable1 NonEmpty -- an unfortunate orphan
|
||||
-- unfortunate orphans
|
||||
#if MIN_VERSION_hashable(1, 2, 5)
|
||||
instance Hashable1 NonEmpty
|
||||
#endif
|
||||
|
||||
#if !MIN_VERSION_base(4, 10, 0)
|
||||
instance Eq1 NonEmpty where
|
||||
liftEq eq (a NE.:| as) (b NE.:| bs) = eq a b && liftEq eq as bs
|
||||
instance Show1 NonEmpty where
|
||||
liftShowsPrec shwP shwL p (a NE.:| as) = showParen (p > 5) $
|
||||
shwP 6 a . showString " :| " . shwL as
|
||||
#endif
|
||||
|
||||
#if !MIN_VERSION_binary(0, 8, 4)
|
||||
instance Binary a => Binary (NE.NonEmpty a) where
|
||||
get = fmap NE.fromList Bin.get
|
||||
put = Bin.put . NE.toList
|
||||
#endif
|
||||
|
||||
-- | The main nix expression type. This is polymorphic so that it can be made
|
||||
-- a functor, which allows us to traverse expressions and map functions over
|
||||
|
@ -113,35 +136,71 @@ data NExprF r
|
|||
| NAssert !r !r
|
||||
-- ^ Assert that the first returns true before evaluating the second.
|
||||
deriving (Ord, Eq, Generic, Generic1, Typeable, Data, Functor,
|
||||
Foldable, Traversable, Show, NFData, NFData1, Serialise,
|
||||
Hashable, Hashable1)
|
||||
Foldable, Traversable, Show, NFData,
|
||||
Hashable)
|
||||
|
||||
#if MIN_VERSION_hashable(1, 2, 5)
|
||||
instance Hashable1 NExprF
|
||||
#endif
|
||||
|
||||
#if MIN_VERSION_deepseq(1, 4, 3)
|
||||
instance NFData1 NExprF
|
||||
#endif
|
||||
|
||||
#ifdef MIN_VERSION_serialise
|
||||
instance Serialise r => Serialise (NExprF r)
|
||||
#endif
|
||||
|
||||
-- | We make an `IsString` for expressions, where the string is interpreted
|
||||
-- as an identifier. This is the most common use-case...
|
||||
instance IsString NExpr where
|
||||
fromString = Fix . NSym . fromString
|
||||
|
||||
#if MIN_VERSION_base(4, 10, 0)
|
||||
instance Lift (Fix NExprF) where
|
||||
lift = dataToExpQ $ \b ->
|
||||
case Reflection.typeOf b `eqTypeRep` Reflection.typeRep @Text of
|
||||
Just HRefl -> Just [| pack $(liftString $ unpack b) |]
|
||||
Nothing -> Nothing
|
||||
#else
|
||||
instance Lift (Fix NExprF) where
|
||||
lift = dataToExpQ $ \b -> case cast b of
|
||||
Just t -> Just [| pack $(liftString $ unpack t) |]
|
||||
Nothing -> Nothing
|
||||
#endif
|
||||
|
||||
-- | The monomorphic expression type is a fixed point of the polymorphic one.
|
||||
type NExpr = Fix NExprF
|
||||
|
||||
#ifdef MIN_VERSION_serialise
|
||||
instance Serialise NExpr
|
||||
#endif
|
||||
|
||||
-- | A single line of the bindings section of a let expression or of a set.
|
||||
data Binding r
|
||||
= NamedVar !(NAttrPath r) !r
|
||||
= NamedVar !(NAttrPath r) !r !SourcePos
|
||||
-- ^ An explicit naming, such as @x = y@ or @x.y = z@.
|
||||
| Inherit !(Maybe r) ![NKeyName r]
|
||||
| Inherit !(Maybe r) ![NKeyName r] !SourcePos
|
||||
-- ^ Using a name already in scope, such as @inherit x;@ which is shorthand
|
||||
-- for @x = x;@ or @inherit (x) y;@ which means @y = x.y;@.
|
||||
-- for @x = x;@ or @inherit (x) y;@ which means @y = x.y;@. The
|
||||
-- unsafeGetAttrPos for every name so inherited is the position of the
|
||||
-- first name, whether that be the first argument to this constructor, or
|
||||
-- the first member of the list in the second argument.
|
||||
deriving (Generic, Generic1, Typeable, Data, Ord, Eq, Functor,
|
||||
Foldable, Traversable, Show, NFData, NFData1, Serialise,
|
||||
Hashable, Hashable1)
|
||||
Foldable, Traversable, Show, NFData,
|
||||
Hashable)
|
||||
|
||||
#if MIN_VERSION_hashable(1, 2, 5)
|
||||
instance Hashable1 Binding
|
||||
#endif
|
||||
|
||||
#if MIN_VERSION_deepseq(1, 4, 3)
|
||||
instance NFData1 Binding
|
||||
#endif
|
||||
|
||||
#ifdef MIN_VERSION_serialise
|
||||
instance Serialise r => Serialise (Binding r)
|
||||
#endif
|
||||
|
||||
-- | @Params@ represents all the ways the formal parameters to a
|
||||
-- function can be represented.
|
||||
|
@ -153,8 +212,19 @@ data Params r
|
|||
-- bind to the set in the function body. The bool indicates whether it is
|
||||
-- variadic or not.
|
||||
deriving (Ord, Eq, Generic, Generic1, Typeable, Data, Functor, Show,
|
||||
Foldable, Traversable, NFData, NFData1, Serialise,
|
||||
Hashable, Hashable1)
|
||||
Foldable, Traversable, NFData, Hashable)
|
||||
|
||||
#if MIN_VERSION_hashable(1, 2, 5)
|
||||
instance Hashable1 Params
|
||||
#endif
|
||||
|
||||
#if MIN_VERSION_deepseq(1, 4, 3)
|
||||
instance NFData1 Params
|
||||
#endif
|
||||
|
||||
#ifdef MIN_VERSION_serialise
|
||||
instance Serialise r => Serialise (Params r)
|
||||
#endif
|
||||
|
||||
-- This uses an association list because nix XML serialization preserves the
|
||||
-- order of the param set.
|
||||
|
@ -167,8 +237,10 @@ instance IsString (Params r) where
|
|||
-- antiquoted (surrounded by ${...}) or plain (not antiquoted).
|
||||
data Antiquoted (v :: *) (r :: *) = Plain !v | EscapedNewline | Antiquoted !r
|
||||
deriving (Ord, Eq, Generic, Generic1, Typeable, Data, Functor, Foldable,
|
||||
Traversable, Show, Read, NFData, NFData1, Serialise,
|
||||
Hashable, Hashable1)
|
||||
Traversable, Show, Read, NFData, Hashable)
|
||||
|
||||
#if MIN_VERSION_hashable(1, 2, 5)
|
||||
instance Hashable v => Hashable1 (Antiquoted v)
|
||||
|
||||
instance Hashable2 Antiquoted where
|
||||
liftHashWithSalt2 ha _ salt (Plain a) =
|
||||
|
@ -177,6 +249,15 @@ instance Hashable2 Antiquoted where
|
|||
salt `hashWithSalt` (1 :: Int)
|
||||
liftHashWithSalt2 _ hb salt (Antiquoted b) =
|
||||
hb (salt `hashWithSalt` (2 :: Int)) b
|
||||
#endif
|
||||
|
||||
#if MIN_VERSION_deepseq(1, 4, 3)
|
||||
instance NFData v => NFData1 (Antiquoted v)
|
||||
#endif
|
||||
|
||||
#ifdef MIN_VERSION_serialise
|
||||
instance (Serialise v, Serialise r) => Serialise (Antiquoted v r)
|
||||
#endif
|
||||
|
||||
-- | An 'NString' is a list of things that are either a plain string
|
||||
-- or an antiquoted expression. After the antiquotes have been evaluated,
|
||||
|
@ -190,8 +271,19 @@ data NString r
|
|||
-- their indentation will be stripped, but the amount stripped is
|
||||
-- remembered.
|
||||
deriving (Eq, Ord, Generic, Generic1, Typeable, Data, Functor, Foldable,
|
||||
Traversable, Show, Read, NFData, NFData1, Serialise,
|
||||
Hashable, Hashable1)
|
||||
Traversable, Show, Read, NFData, Hashable)
|
||||
|
||||
#if MIN_VERSION_hashable(1, 2, 5)
|
||||
instance Hashable1 NString
|
||||
#endif
|
||||
|
||||
#if MIN_VERSION_deepseq(1, 4, 3)
|
||||
instance NFData1 NString
|
||||
#endif
|
||||
|
||||
#ifdef MIN_VERSION_serialise
|
||||
instance Serialise r => Serialise (NString r)
|
||||
#endif
|
||||
|
||||
-- | For the the 'IsString' instance, we use a plain doublequoted string.
|
||||
instance IsString (NString r) where
|
||||
|
@ -219,9 +311,12 @@ instance IsString (NString r) where
|
|||
-- parser still considers it a 'DynamicKey' for simplicity.
|
||||
data NKeyName r
|
||||
= DynamicKey !(Antiquoted (NString r) r)
|
||||
| StaticKey !VarName !(Maybe SourcePos)
|
||||
| StaticKey !VarName
|
||||
deriving (Eq, Ord, Generic, Typeable, Data, Show, Read, NFData,
|
||||
Serialise, Hashable)
|
||||
Hashable)
|
||||
|
||||
#ifdef MIN_VERSION_serialise
|
||||
instance Serialise r => Serialise (NKeyName r)
|
||||
|
||||
instance Serialise Pos where
|
||||
encode x = Ser.encode (unPos x)
|
||||
|
@ -230,6 +325,7 @@ instance Serialise Pos where
|
|||
instance Serialise SourcePos where
|
||||
encode (SourcePos f l c) = Ser.encode f <> Ser.encode l <> Ser.encode c
|
||||
decode = SourcePos <$> Ser.decode <*> Ser.decode <*> Ser.decode
|
||||
#endif
|
||||
|
||||
instance Hashable Pos where
|
||||
hashWithSalt salt x = hashWithSalt salt (unPos x)
|
||||
|
@ -243,33 +339,37 @@ instance Generic1 NKeyName where
|
|||
from1 = id
|
||||
to1 = id
|
||||
|
||||
#if MIN_VERSION_deepseq(1, 4, 3)
|
||||
instance NFData1 NKeyName where
|
||||
liftRnf _ (StaticKey !_ !_) = ()
|
||||
liftRnf _ (StaticKey !_) = ()
|
||||
liftRnf _ (DynamicKey (Plain !_)) = ()
|
||||
liftRnf _ (DynamicKey EscapedNewline) = ()
|
||||
liftRnf k (DynamicKey (Antiquoted r)) = k r
|
||||
#endif
|
||||
|
||||
-- | Most key names are just static text, so this instance is convenient.
|
||||
instance IsString (NKeyName r) where
|
||||
fromString = flip StaticKey Nothing . fromString
|
||||
fromString = StaticKey . fromString
|
||||
|
||||
instance Eq1 NKeyName where
|
||||
liftEq eq (DynamicKey a) (DynamicKey b) = liftEq2 (liftEq eq) eq a b
|
||||
liftEq _ (StaticKey a _) (StaticKey b _) = a == b
|
||||
liftEq _ (StaticKey a) (StaticKey b) = a == b
|
||||
liftEq _ _ _ = False
|
||||
|
||||
#if MIN_VERSION_hashable(1, 2, 5)
|
||||
instance Hashable1 NKeyName where
|
||||
liftHashWithSalt h salt (DynamicKey a) =
|
||||
liftHashWithSalt2 (liftHashWithSalt h) h (salt `hashWithSalt` (0 :: Int)) a
|
||||
liftHashWithSalt _ salt (StaticKey n p) =
|
||||
salt `hashWithSalt` (1 :: Int) `hashWithSalt` n `hashWithSalt` p
|
||||
liftHashWithSalt _ salt (StaticKey n) =
|
||||
salt `hashWithSalt` (1 :: Int) `hashWithSalt` n
|
||||
#endif
|
||||
|
||||
-- Deriving this instance automatically is not possible because @r@
|
||||
-- occurs not only as last argument in @Antiquoted (NString r) r@
|
||||
instance Show1 NKeyName where
|
||||
liftShowsPrec sp sl p = \case
|
||||
DynamicKey a -> showsUnaryWith (liftShowsPrec2 (liftShowsPrec sp sl) (liftShowList sp sl) sp sl) "DynamicKey" p a
|
||||
StaticKey t _ -> showsUnaryWith showsPrec "StaticKey" p t
|
||||
StaticKey t -> showsUnaryWith showsPrec "StaticKey" p t
|
||||
|
||||
-- Deriving this instance automatically is not possible because @r@
|
||||
-- occurs not only as last argument in @Antiquoted (NString r) r@
|
||||
|
@ -286,9 +386,9 @@ instance Foldable NKeyName where
|
|||
instance Traversable NKeyName where
|
||||
traverse f = \case
|
||||
DynamicKey (Plain str) -> DynamicKey . Plain <$> traverse f str
|
||||
DynamicKey EscapedNewline -> pure $ DynamicKey EscapedNewline
|
||||
DynamicKey (Antiquoted e) -> DynamicKey . Antiquoted <$> f e
|
||||
StaticKey key pos -> pure (StaticKey key pos)
|
||||
DynamicKey EscapedNewline -> pure $ DynamicKey EscapedNewline
|
||||
StaticKey key -> pure (StaticKey key)
|
||||
|
||||
-- | A selector (for example in a @let@ or an attribute set) is made up
|
||||
-- of strung-together key names.
|
||||
|
@ -296,8 +396,12 @@ type NAttrPath r = NonEmpty (NKeyName r)
|
|||
|
||||
-- | There are two unary operations: logical not and integer negation.
|
||||
data NUnaryOp = NNeg | NNot
|
||||
deriving (Eq, Ord, Generic, Typeable, Data, Show, Read, NFData,
|
||||
Serialise, Hashable)
|
||||
deriving (Eq, Ord, Enum, Bounded, Generic, Typeable, Data, Show, Read,
|
||||
NFData, Hashable)
|
||||
|
||||
#ifdef MIN_VERSION_serialise
|
||||
instance Serialise NUnaryOp
|
||||
#endif
|
||||
|
||||
-- | Binary operators expressible in the nix language.
|
||||
data NBinaryOp
|
||||
|
@ -317,14 +421,22 @@ data NBinaryOp
|
|||
| NDiv -- ^ Division (/)
|
||||
| NConcat -- ^ List concatenation (++)
|
||||
| NApp -- ^ Apply a function to an argument.
|
||||
deriving (Eq, Ord, Generic, Typeable, Data, Show, Read, NFData,
|
||||
Serialise, Hashable)
|
||||
deriving (Eq, Ord, Enum, Bounded, Generic, Typeable, Data, Show, Read,
|
||||
NFData, Hashable)
|
||||
|
||||
#ifdef MIN_VERSION_serialise
|
||||
instance Serialise NBinaryOp
|
||||
#endif
|
||||
|
||||
-- | Get the name out of the parameter (there might be none).
|
||||
paramName :: Params r -> Maybe VarName
|
||||
paramName (Param n) = Just n
|
||||
paramName (ParamSet _ _ n) = n
|
||||
|
||||
#if !MIN_VERSION_deepseq(1, 4, 3)
|
||||
instance NFData NExpr
|
||||
#endif
|
||||
|
||||
$(deriveEq1 ''NExprF)
|
||||
$(deriveEq1 ''NString)
|
||||
$(deriveEq1 ''Binding)
|
||||
|
@ -415,16 +527,17 @@ class NExprAnn ann g | g -> ann where
|
|||
|
||||
ekey :: NExprAnn ann g
|
||||
=> NonEmpty Text
|
||||
-> SourcePos
|
||||
-> Lens' (Fix g) (Maybe (Fix g))
|
||||
ekey keys f e@(Fix x) | (NSet xs, ann) <- fromNExpr x =
|
||||
ekey keys pos f e@(Fix x) | (NSet xs, ann) <- fromNExpr x =
|
||||
case go xs of
|
||||
((v, []):_) -> fromMaybe e <$> f (Just v)
|
||||
((v, r:rest):_) -> ekey (r :| rest) f v
|
||||
((v, r:rest):_) -> ekey (r :| rest) pos f v
|
||||
|
||||
_ -> f Nothing <&> \case
|
||||
Nothing -> e
|
||||
Just v ->
|
||||
let entry = NamedVar (NE.map (StaticKey ?? Nothing) keys) v
|
||||
let entry = NamedVar (NE.map StaticKey keys) v pos
|
||||
in Fix (toNExpr (NSet (entry : xs), ann))
|
||||
where
|
||||
go xs = do
|
||||
|
@ -433,11 +546,11 @@ ekey keys f e@(Fix x) | (NSet xs, ann) <- fromNExpr x =
|
|||
case ks of
|
||||
[] -> empty
|
||||
j:js -> do
|
||||
NamedVar ns v <- xs
|
||||
guard $ (j:js) == (NE.toList ns ^.. traverse._StaticKey._1)
|
||||
NamedVar ns v _p <- xs
|
||||
guard $ (j:js) == (NE.toList ns ^.. traverse._StaticKey)
|
||||
return (v, rest)
|
||||
|
||||
ekey _ f e = fromMaybe e <$> f Nothing
|
||||
ekey _ _ f e = fromMaybe e <$> f Nothing
|
||||
|
||||
stripPositionInfo :: NExpr -> NExpr
|
||||
stripPositionInfo = transport phi
|
||||
|
@ -445,11 +558,10 @@ stripPositionInfo = transport phi
|
|||
phi (NSet binds) = NSet (map go binds)
|
||||
phi (NRecSet binds) = NRecSet (map go binds)
|
||||
phi (NLet binds body) = NLet (map go binds) body
|
||||
phi (NSelect s attr alt) = NSelect s (NE.map clear attr) alt
|
||||
phi x = x
|
||||
|
||||
go (NamedVar path r) = NamedVar (NE.map clear path) r
|
||||
go (Inherit ms names) = Inherit ms (map clear names)
|
||||
go (NamedVar path r _pos) = NamedVar path r nullPos
|
||||
go (Inherit ms names _pos) = Inherit ms names nullPos
|
||||
|
||||
clear (StaticKey name _) = StaticKey name Nothing
|
||||
clear k = k
|
||||
nullPos :: SourcePos
|
||||
nullPos = SourcePos "<string>" (mkPos 1) (mkPos 1)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{-# LANGUAGE DeriveAnyClass #-}
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DeriveAnyClass #-}
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
{-# LANGUAGE DeriveFoldable #-}
|
||||
{-# LANGUAGE DeriveFunctor #-}
|
||||
|
@ -20,7 +21,9 @@ module Nix.Expr.Types.Annotated
|
|||
, SourcePos(..), unPos, mkPos
|
||||
)where
|
||||
|
||||
#ifdef MIN_VERSION_serialise
|
||||
import Codec.Serialise
|
||||
#endif
|
||||
import Control.DeepSeq
|
||||
import Data.Aeson (ToJSON(..), FromJSON(..))
|
||||
import Data.Aeson.TH
|
||||
|
@ -31,7 +34,9 @@ import Data.Fix
|
|||
import Data.Function (on)
|
||||
import Data.Functor.Compose
|
||||
import Data.Hashable
|
||||
#if MIN_VERSION_hashable(1, 2, 5)
|
||||
import Data.Hashable.Lifted
|
||||
#endif
|
||||
import Data.Ord.Deriving
|
||||
import Data.Semigroup
|
||||
import Data.Text (Text, pack)
|
||||
|
@ -48,9 +53,13 @@ data SrcSpan = SrcSpan
|
|||
{ spanBegin :: SourcePos
|
||||
, spanEnd :: SourcePos
|
||||
}
|
||||
deriving (Ord, Eq, Generic, Typeable, Data, Show, NFData, Serialise,
|
||||
deriving (Ord, Eq, Generic, Typeable, Data, Show, NFData,
|
||||
Hashable)
|
||||
|
||||
#ifdef MIN_VERSION_serialise
|
||||
instance Serialise SrcSpan
|
||||
#endif
|
||||
|
||||
-- | A type constructor applied to a type along with an annotation
|
||||
--
|
||||
-- Intended to be used with 'Fix':
|
||||
|
@ -60,8 +69,19 @@ data Ann ann a = Ann
|
|||
, annotated :: a
|
||||
}
|
||||
deriving (Ord, Eq, Data, Generic, Generic1, Typeable, Functor, Foldable,
|
||||
Traversable, Read, Show, NFData, NFData1, Serialise,
|
||||
Hashable, Hashable1)
|
||||
Traversable, Read, Show, NFData, Hashable)
|
||||
|
||||
#if MIN_VERSION_hashable(1, 2, 5)
|
||||
instance Hashable ann => Hashable1 (Ann ann)
|
||||
#endif
|
||||
|
||||
#ifdef MIN_VERSION_serialise
|
||||
instance (Serialise ann, Serialise a) => Serialise (Ann ann a)
|
||||
#endif
|
||||
|
||||
#if MIN_VERSION_deepseq(1, 4, 3)
|
||||
instance NFData ann => NFData1 (Ann ann)
|
||||
#endif
|
||||
|
||||
$(deriveEq1 ''Ann)
|
||||
$(deriveEq2 ''Ann)
|
||||
|
@ -88,9 +108,19 @@ type NExprLocF = AnnF SrcSpan NExprF
|
|||
-- | A nix expression with source location at each subexpression.
|
||||
type NExprLoc = Fix NExprLocF
|
||||
|
||||
#if !MIN_VERSION_deepseq(1, 4, 3)
|
||||
instance (NFData (f (g a)), NFData (g a)) => NFData (Compose f g a)
|
||||
#endif
|
||||
|
||||
instance NFData NExprLoc
|
||||
|
||||
#ifdef MIN_VERSION_serialise
|
||||
instance Serialise NExprLoc
|
||||
#endif
|
||||
|
||||
#if MIN_VERSION_hashable(1, 2, 5)
|
||||
instance Hashable NExprLoc
|
||||
#endif
|
||||
|
||||
instance Binary SrcSpan
|
||||
instance (Binary ann, Binary a) => Binary (Ann ann a)
|
||||
|
@ -100,9 +130,11 @@ instance Binary NExprLoc
|
|||
instance ToJSON SrcSpan
|
||||
instance FromJSON SrcSpan
|
||||
|
||||
#ifdef MIN_VERSION_serialise
|
||||
instance Serialise r => Serialise (Compose (Ann SrcSpan) NExprF r) where
|
||||
encode (Compose (Ann ann a)) = encode ann <> encode a
|
||||
decode = (Compose .) . Ann <$> decode <*> decode
|
||||
#endif
|
||||
|
||||
pattern AnnE :: forall ann (g :: * -> *). ann
|
||||
-> g (Fix (Compose (Ann ann) g)) -> Fix (Compose (Ann ann) g)
|
||||
|
@ -155,9 +187,6 @@ nNull = Fix (Compose (Ann nullSpan (NConstant NNull)))
|
|||
nullSpan :: SrcSpan
|
||||
nullSpan = SrcSpan nullPos nullPos
|
||||
|
||||
nullPos :: SourcePos
|
||||
nullPos = SourcePos "<string>" (mkPos 1) (mkPos 1)
|
||||
|
||||
-- | Pattern systems for matching on NExprLocF constructions.
|
||||
|
||||
pattern NSym_ :: SrcSpan -> VarName -> NExprLocF r
|
||||
|
|
|
@ -76,7 +76,7 @@ valueText :: forall e m. (Framed e m, MonadEffects m, Typeable m)
|
|||
=> Bool -> NValueNF m -> m NixString
|
||||
valueText addPathsToStore = cata phi
|
||||
where
|
||||
--phi :: () -- NValueF m (m ns) -> m ns
|
||||
phi :: NValueF m NixString -> m NixString
|
||||
phi (NVConstantF a) = pure (makeNixStringWithoutContext (atomText a))
|
||||
phi (NVStrF ns) = pure ns
|
||||
phi v@(NVListF _) = coercionFailed v
|
||||
|
|
127
src/Nix/Options/Parser.hs
Normal file
127
src/Nix/Options/Parser.hs
Normal file
|
@ -0,0 +1,127 @@
|
|||
module Nix.Options.Parser where
|
||||
|
||||
import Control.Arrow (second)
|
||||
import Data.Char (isDigit)
|
||||
import Data.Maybe (fromMaybe)
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as Text
|
||||
import Data.Time
|
||||
import Nix.Options
|
||||
import Options.Applicative hiding (ParserResult(..))
|
||||
import Text.PrettyPrint.ANSI.Leijen hiding ((<$>))
|
||||
|
||||
decodeVerbosity :: Int -> Verbosity
|
||||
decodeVerbosity 0 = ErrorsOnly
|
||||
decodeVerbosity 1 = Informational
|
||||
decodeVerbosity 2 = Talkative
|
||||
decodeVerbosity 3 = Chatty
|
||||
decodeVerbosity 4 = DebugInfo
|
||||
decodeVerbosity _ = Vomit
|
||||
|
||||
argPair :: Mod OptionFields (Text, Text) -> Parser (Text, Text)
|
||||
argPair = option $ str >>= \s ->
|
||||
case Text.findIndex (== '=') s of
|
||||
Nothing -> errorWithoutStackTrace
|
||||
"Format of --arg/--argstr in hnix is: name=expr"
|
||||
Just i -> return $ second Text.tail $ Text.splitAt i s
|
||||
|
||||
nixOptions :: UTCTime -> Parser Options
|
||||
nixOptions current = Options
|
||||
<$> (fromMaybe ErrorsOnly <$>
|
||||
optional
|
||||
(option (do a <- str
|
||||
if all isDigit a
|
||||
then pure $ decodeVerbosity (read a)
|
||||
else fail "Argument to -v/--verbose must be a number")
|
||||
( short 'v'
|
||||
<> long "verbose"
|
||||
<> help "Verbose output")))
|
||||
<*> switch
|
||||
( long "trace"
|
||||
<> help "Enable tracing code (even more can be seen if built with --flags=tracing)")
|
||||
<*> switch
|
||||
( long "thunks"
|
||||
<> help "Enable reporting of thunk tracing as well as regular evaluation")
|
||||
<*> switch
|
||||
( long "values"
|
||||
<> help "Enable reporting of value provenance in error messages")
|
||||
<*> optional (strOption
|
||||
( long "reduce"
|
||||
<> help "When done evaluating, output the evaluated part of the expression to FILE"))
|
||||
<*> switch
|
||||
( long "reduce-sets"
|
||||
<> help "Reduce set members that aren't used; breaks if hasAttr is used")
|
||||
<*> switch
|
||||
( long "reduce-lists"
|
||||
<> help "Reduce list members that aren't used; breaks if elemAt is used")
|
||||
<*> switch
|
||||
( long "parse"
|
||||
<> help "Whether to parse the file (also the default right now)")
|
||||
<*> switch
|
||||
( long "parse-only"
|
||||
<> help "Whether to parse only, no pretty printing or checking")
|
||||
<*> switch
|
||||
( long "find"
|
||||
<> help "If selected, find paths within attr trees")
|
||||
<*> optional (strOption
|
||||
( long "find-file"
|
||||
<> help "Look up the given files in Nix's search path"))
|
||||
<*> switch
|
||||
( long "strict"
|
||||
<> help "When used with --eval, recursively evaluate list elements and attributes")
|
||||
<*> switch
|
||||
( long "eval"
|
||||
<> help "Whether to evaluate, or just pretty-print")
|
||||
<*> switch
|
||||
( long "json"
|
||||
<> help "Print the resulting value as an JSON representation")
|
||||
<*> switch
|
||||
( long "xml"
|
||||
<> help "Print the resulting value as an XML representation")
|
||||
<*> optional (strOption
|
||||
( short 'A'
|
||||
<> long "attr"
|
||||
<> help "Select an attribute from the top-level Nix expression being evaluated"))
|
||||
<*> many (strOption
|
||||
( short 'I'
|
||||
<> long "include"
|
||||
<> help "Add a path to the Nix expression search path"))
|
||||
<*> switch
|
||||
( long "check"
|
||||
<> help "Whether to check for syntax errors after parsing")
|
||||
<*> optional (strOption
|
||||
( long "read"
|
||||
<> help "Read in an expression tree from a binary cache"))
|
||||
<*> switch
|
||||
( long "cache"
|
||||
<> help "Write out the parsed expression tree to a binary cache")
|
||||
<*> switch
|
||||
( long "repl"
|
||||
<> help "After performing any indicated actions, enter the REPL")
|
||||
<*> switch
|
||||
( long "ignore-errors"
|
||||
<> help "Continue parsing files, even if there are errors")
|
||||
<*> optional (strOption
|
||||
( short 'E'
|
||||
<> long "expr"
|
||||
<> help "Expression to parse or evaluate"))
|
||||
<*> many (argPair
|
||||
( long "arg"
|
||||
<> help "Argument to pass to an evaluated lambda"))
|
||||
<*> many (argPair
|
||||
( long "argstr"
|
||||
<> help "Argument string to pass to an evaluated lambda"))
|
||||
<*> optional (strOption
|
||||
( short 'f'
|
||||
<> long "file"
|
||||
<> help "Parse all of the files given in FILE; - means stdin"))
|
||||
<*> option (parseTimeOrError True defaultTimeLocale "%Y/%m/%d %H:%M:%S" <$> str)
|
||||
( long "now"
|
||||
<> value current
|
||||
<> help "Set current time for testing purposes")
|
||||
<*> many (strArgument (metavar "FILE" <> help "Path of file to parse"))
|
||||
|
||||
nixOptionsInfo :: UTCTime -> ParserInfo Options
|
||||
nixOptionsInfo current =
|
||||
info (helper <*> nixOptions current)
|
||||
(fullDesc <> progDesc "" <> header "hnix")
|
|
@ -1,3 +1,4 @@
|
|||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE AllowAmbiguousTypes #-}
|
||||
{-# LANGUAGE ConstraintKinds #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
|
@ -29,7 +30,9 @@ import Nix.Value
|
|||
import Text.Megaparsec.Pos
|
||||
import qualified Text.PrettyPrint.ANSI.Leijen as P
|
||||
import Text.PrettyPrint.ANSI.Leijen hiding ((<$>))
|
||||
#ifdef MIN_VERSION_pretty_show
|
||||
import qualified Text.Show.Pretty as PS
|
||||
#endif
|
||||
|
||||
renderFrames :: forall v e m.
|
||||
(MonadReader e m, Has e Options,
|
||||
|
@ -111,7 +114,11 @@ renderExpr _level longLabel shortLabel e@(Fix (Compose (Ann _ x))) = do
|
|||
opts :: Options <- asks (view hasLens)
|
||||
let rendered
|
||||
| verbose opts >= DebugInfo =
|
||||
#ifdef MIN_VERSION_pretty_show
|
||||
text (PS.ppShow (stripAnnotation e))
|
||||
#else
|
||||
text (show (stripAnnotation e))
|
||||
#endif
|
||||
| verbose opts >= Chatty =
|
||||
prettyNix (stripAnnotation e)
|
||||
| otherwise =
|
||||
|
|
|
@ -99,7 +99,7 @@ instance Substitutable Type where
|
|||
apply s (TSet b a) = TSet b (M.map (apply s) a)
|
||||
apply s (TList a) = TList (map (apply s) a)
|
||||
apply (Subst s) t@(TVar a) = Map.findWithDefault t a s
|
||||
apply s (t1 `TArr` t2) = apply s t1 `TArr` apply s t2
|
||||
apply s (t1 :~> t2) = apply s t1 :~> apply s t2
|
||||
apply s (TMany ts) = TMany (map (apply s) ts)
|
||||
|
||||
instance Substitutable Scheme where
|
||||
|
@ -122,12 +122,12 @@ class FreeTypeVars a where
|
|||
ftv :: a -> Set.Set TVar
|
||||
|
||||
instance FreeTypeVars Type where
|
||||
ftv TCon{} = Set.empty
|
||||
ftv (TVar a) = Set.singleton a
|
||||
ftv (TSet _ a) = Set.unions (map ftv (M.elems a))
|
||||
ftv (TList a) = Set.unions (map ftv a)
|
||||
ftv (t1 `TArr` t2) = ftv t1 `Set.union` ftv t2
|
||||
ftv (TMany ts) = Set.unions (map ftv ts)
|
||||
ftv TCon{} = Set.empty
|
||||
ftv (TVar a) = Set.singleton a
|
||||
ftv (TSet _ a) = Set.unions (map ftv (M.elems a))
|
||||
ftv (TList a) = Set.unions (map ftv a)
|
||||
ftv (t1 :~> t2) = ftv t1 `Set.union` ftv t2
|
||||
ftv (TMany ts) = Set.unions (map ftv ts)
|
||||
|
||||
instance FreeTypeVars TVar where
|
||||
ftv = Set.singleton
|
||||
|
@ -359,7 +359,6 @@ instance MonadEval (Judgment s) (Infer s) where
|
|||
NFloat _ -> typeFloat
|
||||
NBool _ -> typeBool
|
||||
NNull -> typeNull
|
||||
NUri _ -> typeUri
|
||||
|
||||
evalString = const $ return $ Judgment As.empty [] typeString
|
||||
evalLiteralPath = const $ return $ Judgment As.empty [] typePath
|
||||
|
@ -367,14 +366,14 @@ instance MonadEval (Judgment s) (Infer s) where
|
|||
|
||||
evalUnary op (Judgment as1 cs1 t1) = do
|
||||
tv <- fresh
|
||||
return $ Judgment as1 (cs1 ++ unops (t1 `TArr` tv) op) tv
|
||||
return $ Judgment as1 (cs1 ++ unops (t1 :~> tv) op) tv
|
||||
|
||||
evalBinary op (Judgment as1 cs1 t1) e2 = do
|
||||
Judgment as2 cs2 t2 <- e2
|
||||
tv <- fresh
|
||||
return $ Judgment
|
||||
(as1 `As.merge` as2)
|
||||
(cs1 ++ cs2 ++ binops (t1 `TArr` (t2 `TArr` tv)) op)
|
||||
(cs1 ++ cs2 ++ binops (t1 :~> t2 :~> tv) op)
|
||||
tv
|
||||
|
||||
evalWith = Eval.evalWithAttrSet
|
||||
|
@ -399,7 +398,7 @@ instance MonadEval (Judgment s) (Infer s) where
|
|||
tv <- fresh
|
||||
return $ Judgment
|
||||
(as1 `As.merge` as2)
|
||||
(cs1 ++ cs2 ++ [EqConst t1 (t2 `TArr` tv)])
|
||||
(cs1 ++ cs2 ++ [EqConst t1 (t2 :~> tv)])
|
||||
tv
|
||||
|
||||
evalAbs (Param x) k = do
|
||||
|
@ -410,7 +409,7 @@ instance MonadEval (Judgment s) (Infer s) where
|
|||
return $ Judgment
|
||||
(as `As.remove` x)
|
||||
(cs ++ [EqConst t' tv | t' <- As.lookup x as])
|
||||
(tv `TArr` t)
|
||||
(tv :~> t)
|
||||
|
||||
evalAbs (ParamSet ps variadic _mname) k = do
|
||||
js <- fmap concat $ forM ps $ \(name, _) -> do
|
||||
|
@ -434,7 +433,7 @@ instance MonadEval (Judgment s) (Infer s) where
|
|||
(cs ++ [ EqConst t' (tys M.! x)
|
||||
| x <- names
|
||||
, t' <- As.lookup x as])
|
||||
(ty `TArr` t)
|
||||
(ty :~> t)
|
||||
|
||||
evalError = throwError . EvaluationError
|
||||
|
||||
|
@ -492,18 +491,18 @@ normalize (Forall _ body) = Forall (map snd ord) (normtype body)
|
|||
ord = zip (nub $ fv body) (map TV letters)
|
||||
|
||||
fv (TVar a) = [a]
|
||||
fv (TArr a b) = fv a ++ fv b
|
||||
fv (a :~> b) = fv a ++ fv b
|
||||
fv (TCon _) = []
|
||||
fv (TSet _ a) = concatMap fv (M.elems a)
|
||||
fv (TList a) = concatMap fv a
|
||||
fv (TMany ts) = concatMap fv ts
|
||||
|
||||
normtype (TArr a b) = TArr (normtype a) (normtype b)
|
||||
normtype (TCon a) = TCon a
|
||||
normtype (TSet b a) = TSet b (M.map normtype a)
|
||||
normtype (TList a) = TList (map normtype a)
|
||||
normtype (TMany ts) = TMany (map normtype ts)
|
||||
normtype (TVar a) =
|
||||
normtype (a :~> b) = normtype a :~> normtype b
|
||||
normtype (TCon a) = TCon a
|
||||
normtype (TSet b a) = TSet b (M.map normtype a)
|
||||
normtype (TList a) = TList (map normtype a)
|
||||
normtype (TMany ts) = TMany (map normtype ts)
|
||||
normtype (TVar a) =
|
||||
case Prelude.lookup a ord of
|
||||
Just x -> TVar x
|
||||
Nothing -> error "type variable not in signature"
|
||||
|
@ -571,7 +570,7 @@ unifies (TSet True s) (TSet False b)
|
|||
| M.keys b `intersect` M.keys s == M.keys b = return emptySubst
|
||||
unifies (TSet False s) (TSet False b)
|
||||
| null (M.keys b \\ M.keys s) = return emptySubst
|
||||
unifies (TArr t1 t2) (TArr t3 t4) = unifyMany [t1, t2] [t3, t4]
|
||||
unifies (t1 :~> t2) (t3 :~> t4) = unifyMany [t1, t2] [t3, t4]
|
||||
unifies (TMany t1s) t2 = considering t1s >>- unifies ?? t2
|
||||
unifies t1 (TMany t2s) = considering t2s >>- unifies t1
|
||||
unifies t1 t2 = throwError $ UnificationFail t1 t2
|
||||
|
|
|
@ -12,7 +12,7 @@ data Type
|
|||
| TCon String -- known type
|
||||
| TSet Bool (AttrSet Type) -- heterogenous map, bool if variadic
|
||||
| TList [Type] -- heterogenous list
|
||||
| TArr Type Type -- type -> type
|
||||
| (:~>) Type Type -- type -> type
|
||||
| TMany [Type] -- variant type
|
||||
deriving (Show, Eq, Ord)
|
||||
|
||||
|
@ -26,16 +26,17 @@ typeSet = TSet True M.empty
|
|||
typeList :: Type
|
||||
typeList = TList []
|
||||
|
||||
typeFun :: [Type] -> Type
|
||||
typeFun = foldr1 TArr
|
||||
infixr 1 :~>
|
||||
|
||||
typeInt, typeFloat, typeBool, typeString, typePath, typeUri, typeNull :: Type
|
||||
typeFun :: [Type] -> Type
|
||||
typeFun = foldr1 (:~>)
|
||||
|
||||
typeInt, typeFloat, typeBool, typeString, typePath, typeNull :: Type
|
||||
typeInt = TCon "integer"
|
||||
typeFloat = TCon "float"
|
||||
typeBool = TCon "boolean"
|
||||
typeString = TCon "string"
|
||||
typePath = TCon "path"
|
||||
typeUri = TCon "uri"
|
||||
typeNull = TCon "null"
|
||||
|
||||
type Name = Text
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
module EvalTests (tests, genEvalCompareTests) where
|
||||
|
||||
import Control.Monad.Catch
|
||||
import Control.Monad (when)
|
||||
import Control.Monad.IO.Class
|
||||
import qualified Data.HashMap.Lazy as M
|
||||
|
@ -30,6 +31,12 @@ case_basic_sum =
|
|||
case_basic_div =
|
||||
constantEqualText "3" "builtins.div 6 2"
|
||||
|
||||
case_zero_div = do
|
||||
assertNixEvalThrows "builtins.div 1 0"
|
||||
assertNixEvalThrows "builtins.div 1.0 0"
|
||||
assertNixEvalThrows "builtins.div 1 0.0"
|
||||
assertNixEvalThrows "builtins.div 1.0 0.0"
|
||||
|
||||
case_basic_function =
|
||||
constantEqualText "2" "(a: a) 2"
|
||||
|
||||
|
@ -52,9 +59,11 @@ case_function_definition_uses_environment =
|
|||
constantEqualText "3" "let f = (let a=1; in x: x+a); in f 2"
|
||||
|
||||
case_function_atpattern =
|
||||
-- jww (2018-05-09): This should be constantEqualText
|
||||
constantEqualText' "2" "(({a}@attrs:attrs) {a=2;}).a"
|
||||
|
||||
case_function_ellipsis =
|
||||
-- jww (2018-05-09): This should be constantEqualText
|
||||
constantEqualText' "2" "(({a, ...}@attrs:attrs) {a=0; b=2;}).b"
|
||||
|
||||
case_function_default_value_not_in_atpattern =
|
||||
|
@ -67,7 +76,7 @@ case_function_recursive_args =
|
|||
constantEqualText "2" "({ x ? 1, y ? x * 3}: y - x) {}"
|
||||
|
||||
case_function_recursive_sets =
|
||||
constantEqualText' "[ [ 6 4 100 ] 4 ]" [i|
|
||||
constantEqualText "[ [ 6 4 100 ] 4 ]" [i|
|
||||
let x = rec {
|
||||
|
||||
y = 2;
|
||||
|
@ -86,6 +95,30 @@ case_nested_with =
|
|||
case_match_failure_null =
|
||||
constantEqualText "null" "builtins.match \"ab\" \"abc\""
|
||||
|
||||
case_find_file_success_no_prefix =
|
||||
constantEqualText "./tests/files/findFile.nix"
|
||||
"builtins.findFile [{ path=\"./tests/files\"; prefix=\"\"; }] \"findFile.nix\""
|
||||
|
||||
case_find_file_success_with_prefix =
|
||||
constantEqualText "./tests/files/findFile.nix"
|
||||
"builtins.findFile [{ path=\"./tests/files\"; prefix=\"nix\"; }] \"nix/findFile.nix\""
|
||||
|
||||
case_find_file_success_folder =
|
||||
constantEqualText "./tests/files"
|
||||
"builtins.findFile [{ path=\"./tests\"; prefix=\"\"; }] \"files\""
|
||||
|
||||
case_find_file_failure_not_found =
|
||||
assertNixEvalThrows "builtins.findFile [{ path=\"./tests/files\"; prefix=\"\"; }] \"not_found.nix\""
|
||||
|
||||
case_find_file_failure_invalid_arg_1 =
|
||||
assertNixEvalThrows "builtins.findFile 1 \"files\""
|
||||
|
||||
case_find_file_failure_invalid_arg_2 =
|
||||
assertNixEvalThrows "builtins.findFile [{ path=\"./tests/files\"; prefix=\"\"; }] 2"
|
||||
|
||||
case_find_file_failure_invalid_arg_no_path =
|
||||
assertNixEvalThrows "builtins.findFile [{ prefix=\"\"; }] \"files\""
|
||||
|
||||
case_inherit_in_rec_set =
|
||||
constantEqualText "1" "let x = 1; in (rec { inherit x; }).x"
|
||||
|
||||
|
@ -109,8 +142,100 @@ case_inherit_from_set_has_no_scope =
|
|||
)).success
|
||||
|]
|
||||
|
||||
case_unsafegetattrpos1 =
|
||||
constantEqualText "[ 6 20 ]" [i|
|
||||
let e = 1;
|
||||
f = 1;
|
||||
t = {};
|
||||
s = {
|
||||
inherit t e f;
|
||||
a = 1;
|
||||
"b" = 2;
|
||||
c.d = 3;
|
||||
};
|
||||
p = builtins.unsafeGetAttrPos "e" s; in
|
||||
[ p.line p.column ]
|
||||
|]
|
||||
|
||||
case_unsafegetattrpos2 =
|
||||
constantEqualText "[ 6 20 ]" [i|
|
||||
let e = 1;
|
||||
f = 1;
|
||||
t = {};
|
||||
s = {
|
||||
inherit t e f;
|
||||
a = 1;
|
||||
"b" = 2;
|
||||
c.d = 3;
|
||||
};
|
||||
p = builtins.unsafeGetAttrPos "f" s; in
|
||||
[ p.line p.column ]
|
||||
|]
|
||||
|
||||
case_unsafegetattrpos3 =
|
||||
constantEqualText "[ 7 13 ]" [i|
|
||||
let e = 1;
|
||||
f = 1;
|
||||
t = {};
|
||||
s = {
|
||||
inherit t e f;
|
||||
a = 1;
|
||||
"b" = 2;
|
||||
c.d = 3;
|
||||
};
|
||||
p = builtins.unsafeGetAttrPos "a" s; in
|
||||
[ p.line p.column ]
|
||||
|]
|
||||
|
||||
case_unsafegetattrpos4 =
|
||||
constantEqualText "[ 8 13 ]" [i|
|
||||
let e = 1;
|
||||
f = 1;
|
||||
t = {};
|
||||
s = {
|
||||
inherit t e f;
|
||||
a = 1;
|
||||
"b" = 2;
|
||||
c.d = 3;
|
||||
};
|
||||
p = builtins.unsafeGetAttrPos "b" s; in
|
||||
[ p.line p.column ]
|
||||
|]
|
||||
|
||||
-- jww (2018-05-09): These two are failing but they shouldn't be
|
||||
|
||||
-- case_unsafegetattrpos5 =
|
||||
-- constantEqualText "[ 7 13 ]" [i|
|
||||
-- let e = 1;
|
||||
-- f = 1;
|
||||
-- t = {};
|
||||
-- s = {
|
||||
-- inherit t e f;
|
||||
-- a = 1;
|
||||
-- "b" = 2;
|
||||
-- c.d = 3;
|
||||
-- };
|
||||
-- p = builtins.unsafeGetAttrPos "c.d" s; in
|
||||
-- [ p.line p.column ]
|
||||
-- |]
|
||||
|
||||
-- case_unsafegetattrpos6 =
|
||||
-- constantEqualText "[ 7 13 ]" [i|
|
||||
-- let e = 1;
|
||||
-- f = 1;
|
||||
-- t = {};
|
||||
-- s = {
|
||||
-- inherit t e f;
|
||||
-- a = 1;
|
||||
-- "b" = 2;
|
||||
-- c.d = 3;
|
||||
-- };
|
||||
-- p = builtins.unsafeGetAttrPos "d" s; in
|
||||
-- [ p.line p.column ]
|
||||
-- |]
|
||||
|
||||
case_fixed_points =
|
||||
constantEqualText' [i|[
|
||||
constantEqualText [i|[
|
||||
{
|
||||
foobar = "foobar";
|
||||
foo = "foo";
|
||||
|
@ -134,7 +259,7 @@ case_fixed_points =
|
|||
|]
|
||||
|
||||
case_fixed_points_and_fold =
|
||||
constantEqualText' [i|[ {} {} ]|] [i|
|
||||
constantEqualText [i|[ {} {} ]|] [i|
|
||||
let
|
||||
extends = f: rattrs: self:
|
||||
let super = rattrs self; in super // f self super;
|
||||
|
@ -145,6 +270,13 @@ let
|
|||
in [ (fix toFixFold) (fix toFix) ]
|
||||
|]
|
||||
|
||||
case_fixed_points_attrsets =
|
||||
constantEqualText "{ x = { y = { z = 100; }; z = { y = 100; }; }; }" [i|
|
||||
let fix = f: let x = f x; in x;
|
||||
f = self: { x.z.y = 100; x.y.z = self.x.z.y; };
|
||||
in fix f
|
||||
|]
|
||||
|
||||
-- jww (2018-05-02): This constantly changes!
|
||||
-- case_placeholder =
|
||||
-- constantEqualText
|
||||
|
@ -170,6 +302,7 @@ instance (Show r, Show (NValueF m r), Eq r) => Eq (NValueF m r) where
|
|||
NVSetF x _ == NVSetF y _ =
|
||||
M.keys x == M.keys y &&
|
||||
and (zipWith (==) (M.elems x) (M.elems y))
|
||||
NVPathF x == NVPathF y = x == y
|
||||
x == y = error $ "Need to add comparison for values: "
|
||||
++ show x ++ " == " ++ show y
|
||||
|
||||
|
@ -195,3 +328,17 @@ constantEqualText a b = do
|
|||
mres <- liftIO $ lookupEnv "MATCHING_TESTS"
|
||||
when (isJust mres) $
|
||||
assertEvalMatchesNix b
|
||||
|
||||
assertNixEvalThrows :: Text -> Assertion
|
||||
assertNixEvalThrows a = do
|
||||
let Success a' = parseNixTextLoc a
|
||||
time <- liftIO getCurrentTime
|
||||
let opts = defaultOptions time
|
||||
errored <- catch ((runLazyM opts $ normalForm =<< nixEvalExprLoc Nothing a') >> pure False) handler
|
||||
if errored then
|
||||
pure ()
|
||||
else
|
||||
assertFailure "Did not catch nix exception"
|
||||
where
|
||||
handler :: NixException -> IO Bool
|
||||
handler _ = pure True
|
||||
|
|
|
@ -7,11 +7,12 @@ module Main where
|
|||
|
||||
import Control.DeepSeq
|
||||
import qualified Control.Exception as Exc
|
||||
import Control.Applicative ((<|>))
|
||||
import Control.Monad
|
||||
import Control.Monad.IO.Class
|
||||
import Data.Fix
|
||||
import Data.List (isInfixOf)
|
||||
import Data.Maybe (isJust, fromMaybe)
|
||||
import Data.Maybe
|
||||
import Data.String.Interpolate.IsString
|
||||
import Data.Text (unpack)
|
||||
import Data.Time
|
||||
|
@ -26,7 +27,9 @@ import Nix.Value
|
|||
import qualified NixLanguageTests
|
||||
import qualified ParserTests
|
||||
import qualified PrettyTests
|
||||
import qualified PrettyParseTests
|
||||
import qualified ReduceExprTests
|
||||
-- import qualified PrettyParseTests
|
||||
import System.Directory
|
||||
import System.Environment
|
||||
import System.FilePath.Glob
|
||||
import System.Posix.Files
|
||||
|
@ -84,17 +87,23 @@ main :: IO ()
|
|||
main = do
|
||||
nixLanguageTests <- NixLanguageTests.genTests
|
||||
evalComparisonTests <- EvalTests.genEvalCompareTests
|
||||
nixpkgsTestsEnv <- lookupEnv "NIXPKGS_TESTS"
|
||||
prettyTestsEnv <- lookupEnv "PRETTY_TESTS"
|
||||
let allOrLookup var = lookupEnv "ALL_TESTS" <|> lookupEnv var
|
||||
nixpkgsTestsEnv <- allOrLookup "NIXPKGS_TESTS"
|
||||
-- prettyTestsEnv <- lookupEnv "PRETTY_TESTS"
|
||||
hpackTestsEnv <- allOrLookup "HPACK_TESTS"
|
||||
|
||||
setEnv "NIX_REMOTE" "local?root=/tmp"
|
||||
pwd <- getCurrentDirectory
|
||||
setEnv "NIX_REMOTE" ("local?root=" ++ pwd ++ "/")
|
||||
|
||||
defaultMain $ testGroup "hnix" $
|
||||
[ testCase "hnix.cabal correctly generated" cabalCorrectlyGenerated ] ++
|
||||
[ testCase "hnix.cabal correctly generated" cabalCorrectlyGenerated
|
||||
| isJust hpackTestsEnv ] ++
|
||||
[ ParserTests.tests
|
||||
, EvalTests.tests
|
||||
, PrettyTests.tests ] ++
|
||||
[ PrettyParseTests.tests (read (fromMaybe "0" prettyTestsEnv)) ] ++
|
||||
, PrettyTests.tests
|
||||
, ReduceExprTests.tests] ++
|
||||
-- [ PrettyParseTests.tests
|
||||
-- (fromIntegral (read (fromMaybe "0" prettyTestsEnv) :: Int)) ] ++
|
||||
[ evalComparisonTests ] ++
|
||||
[ testCase "Nix language tests present" ensureLangTestsPresent
|
||||
, nixLanguageTests ] ++
|
||||
|
|
|
@ -19,6 +19,7 @@ import Data.Time
|
|||
import GHC.Exts
|
||||
import Nix.Lint
|
||||
import Nix.Options
|
||||
import Nix.Options.Parser
|
||||
import Nix.Parser
|
||||
import Nix.Pretty
|
||||
import Nix.Utils
|
||||
|
|
|
@ -59,11 +59,11 @@ case_constant_path = do
|
|||
assertParseText "~/a/b" $ mkPath False "~/a/b"
|
||||
|
||||
case_constant_uri = do
|
||||
assertParseText "a:a" $ mkUri "a:a"
|
||||
assertParseText "http://foo.bar" $ mkUri "http://foo.bar"
|
||||
assertParseText "a+de+.adA+-:%%%ads%5asdk&/" $ mkUri "a+de+.adA+-:%%%ads%5asdk&/"
|
||||
assertParseText "rec+def:c" $ mkUri "rec+def:c"
|
||||
assertParseText "f.foo:bar" $ mkUri "f.foo:bar"
|
||||
assertParseText "a:a" $ mkStr "a:a"
|
||||
assertParseText "http://foo.bar" $ mkStr "http://foo.bar"
|
||||
assertParseText "a+de+.adA+-:%%%ads%5asdk&/" $ mkStr "a+de+.adA+-:%%%ads%5asdk&/"
|
||||
assertParseText "rec+def:c" $ mkStr "rec+def:c"
|
||||
assertParseText "f.foo:bar" $ mkStr "f.foo:bar"
|
||||
assertParseFail "http://foo${\"bar\"}"
|
||||
assertParseFail ":bcdef"
|
||||
assertParseFail "a%20:asda"
|
||||
|
@ -72,51 +72,51 @@ case_constant_uri = do
|
|||
|
||||
case_simple_set = do
|
||||
assertParseText "{ a = 23; b = 4; }" $ Fix $ NSet
|
||||
[ NamedVar (mkSelector "a") $ mkInt 23
|
||||
, NamedVar (mkSelector "b") $ mkInt 4
|
||||
[ NamedVar (mkSelector "a") (mkInt 23) nullPos
|
||||
, NamedVar (mkSelector "b") (mkInt 4) nullPos
|
||||
]
|
||||
assertParseFail "{ a = 23 }"
|
||||
|
||||
case_set_inherit = do
|
||||
assertParseText "{ e = 3; inherit a b; }" $ Fix $ NSet
|
||||
[ NamedVar (mkSelector "e") $ mkInt 3
|
||||
, Inherit Nothing $ flip StaticKey Nothing <$> ["a", "b"]
|
||||
[ NamedVar (mkSelector "e") (mkInt 3) nullPos
|
||||
, Inherit Nothing (StaticKey <$> ["a", "b"]) nullPos
|
||||
]
|
||||
assertParseText "{ inherit; }" $ Fix $ NSet [ Inherit Nothing [] ]
|
||||
assertParseText "{ inherit; }" $ Fix $ NSet [ Inherit Nothing [] nullPos ]
|
||||
|
||||
case_set_scoped_inherit = assertParseText "{ inherit (a) b c; e = 4; inherit(a)b c; }" $ Fix $ NSet
|
||||
[ Inherit (Just (mkSym "a")) $ flip StaticKey Nothing <$> ["b", "c"]
|
||||
, NamedVar (mkSelector "e") $ mkInt 4
|
||||
, Inherit (Just (mkSym "a")) $ flip StaticKey Nothing <$> ["b", "c"]
|
||||
[ Inherit (Just (mkSym "a")) (StaticKey <$> ["b", "c"]) nullPos
|
||||
, NamedVar (mkSelector "e") (mkInt 4) nullPos
|
||||
, Inherit (Just (mkSym "a")) (StaticKey <$> ["b", "c"]) nullPos
|
||||
]
|
||||
|
||||
case_set_rec = assertParseText "rec { a = 3; b = a; }" $ Fix $ NRecSet
|
||||
[ NamedVar (mkSelector "a") $ mkInt 3
|
||||
, NamedVar (mkSelector "b") $ mkSym "a"
|
||||
[ NamedVar (mkSelector "a") (mkInt 3) nullPos
|
||||
, NamedVar (mkSelector "b") (mkSym "a") nullPos
|
||||
]
|
||||
|
||||
case_set_complex_keynames = do
|
||||
assertParseText "{ \"\" = null; }" $ Fix $ NSet
|
||||
[ NamedVar (DynamicKey (Plain "") :| []) mkNull ]
|
||||
[ NamedVar (DynamicKey (Plain (DoubleQuoted [])) :| []) mkNull nullPos ]
|
||||
assertParseText "{ a.b = 3; a.c = 4; }" $ Fix $ NSet
|
||||
[ NamedVar (StaticKey "a" Nothing :| [StaticKey "b" Nothing]) $ mkInt 3
|
||||
, NamedVar (StaticKey "a" Nothing :| [StaticKey "c" Nothing]) $ mkInt 4
|
||||
[ NamedVar (StaticKey "a" :| [StaticKey "b"]) (mkInt 3) nullPos
|
||||
, NamedVar (StaticKey "a" :| [StaticKey "c"]) (mkInt 4) nullPos
|
||||
]
|
||||
assertParseText "{ ${let a = \"b\"; in a} = 4; }" $ Fix $ NSet
|
||||
[ NamedVar (DynamicKey (Antiquoted letExpr) :| []) $ mkInt 4 ]
|
||||
[ NamedVar (DynamicKey (Antiquoted letExpr) :| []) (mkInt 4) nullPos ]
|
||||
assertParseText "{ \"a${let a = \"b\"; in a}c\".e = 4; }" $ Fix $ NSet
|
||||
[ NamedVar (DynamicKey (Plain str) :| [StaticKey "e" Nothing]) $ mkInt 4 ]
|
||||
[ NamedVar (DynamicKey (Plain str) :| [StaticKey "e"]) (mkInt 4) nullPos ]
|
||||
where
|
||||
letExpr = Fix $ NLet [NamedVar (mkSelector "a") (mkStr "b")] (mkSym "a")
|
||||
letExpr = Fix $ NLet [NamedVar (mkSelector "a") (mkStr "b") nullPos] (mkSym "a")
|
||||
str = DoubleQuoted [Plain "a", Antiquoted letExpr, Plain "c"]
|
||||
|
||||
case_set_inherit_direct = assertParseText "{ inherit ({a = 3;}); }" $ Fix $ NSet
|
||||
[ flip Inherit [] $ Just $ Fix $ NSet [NamedVar (mkSelector "a") $ mkInt 3]
|
||||
[ Inherit (Just $ Fix $ NSet [NamedVar (mkSelector "a") (mkInt 3) nullPos]) [] nullPos
|
||||
]
|
||||
|
||||
case_inherit_selector = do
|
||||
assertParseText "{ inherit \"a\"; }" $ Fix $ NSet
|
||||
[Inherit Nothing [DynamicKey (Plain "a")]]
|
||||
[Inherit Nothing [DynamicKey (Plain (DoubleQuoted [Plain "a"]))] nullPos]
|
||||
assertParseFail "{ inherit a.x; }"
|
||||
|
||||
case_int_list = assertParseText "[1 2 3]" $ Fix $ NList
|
||||
|
@ -126,7 +126,8 @@ case_int_null_list = assertParseText "[1 2 3 null 4]" $ Fix (NList (map (Fix . N
|
|||
|
||||
case_mixed_list = do
|
||||
assertParseText "[{a = 3;}.a (if true then null else false) null false 4 [] c.d or null]" $ Fix $ NList
|
||||
[ Fix (NSelect (Fix (NSet [NamedVar (mkSelector "a") (mkInt 3)])) (mkSelector "a") Nothing)
|
||||
[ Fix (NSelect (Fix (NSet [NamedVar (mkSelector "a") (mkInt 3) nullPos]))
|
||||
(mkSelector "a") Nothing)
|
||||
, Fix (NIf (mkBool True) mkNull (mkBool False))
|
||||
, mkNull, mkBool False, mkInt 4, Fix (NList [])
|
||||
, Fix (NSelect (mkSym "c") (mkSelector "d") (Just mkNull))
|
||||
|
@ -140,8 +141,8 @@ case_simple_lambda = assertParseText "a: a" $ Fix $ NAbs (Param "a") (mkSym "a")
|
|||
|
||||
case_lambda_or_uri = do
|
||||
assertParseText "a :b" $ Fix $ NAbs (Param "a") (mkSym "b")
|
||||
assertParseText "a c:def" $ Fix $ NBinary NApp (mkSym "a") (mkUri "c:def")
|
||||
assertParseText "c:def: c" $ Fix $ NBinary NApp (mkUri "c:def:") (mkSym "c")
|
||||
assertParseText "a c:def" $ Fix $ NBinary NApp (mkSym "a") (mkStr "c:def")
|
||||
assertParseText "c:def: c" $ Fix $ NBinary NApp (mkStr "c:def:") (mkSym "c")
|
||||
assertParseText "a:{}" $ Fix $ NAbs (Param "a") $ Fix $ NSet []
|
||||
assertParseText "a:[a]" $ Fix $ NAbs (Param "a") $ Fix $ NList [mkSym "a"]
|
||||
assertParseFail "def:"
|
||||
|
@ -178,23 +179,23 @@ case_simple_let = do
|
|||
assertParseText "let a = 4; in a" $ Fix (NLet binds $ mkSym "a")
|
||||
assertParseFail "let a = 4 in a"
|
||||
where
|
||||
binds = [NamedVar (mkSelector "a") $ mkInt 4]
|
||||
binds = [NamedVar (mkSelector "a") (mkInt 4) nullPos]
|
||||
|
||||
case_let_body = assertParseText "let { body = 1; }" letBody
|
||||
where
|
||||
letBody = Fix $ NSelect aset (mkSelector "body") Nothing
|
||||
aset = Fix $ NRecSet [NamedVar (mkSelector "body") (mkInt 1)]
|
||||
aset = Fix $ NRecSet [NamedVar (mkSelector "body") (mkInt 1) nullPos]
|
||||
|
||||
case_nested_let = do
|
||||
assertParseText "let a = 4; in let b = 5; in a" $ Fix $ NLet
|
||||
[NamedVar (mkSelector "a") (mkInt 4)]
|
||||
(Fix $ NLet [NamedVar (mkSelector "b") (mkInt 5)] $ mkSym "a")
|
||||
[NamedVar (mkSelector "a") (mkInt 4) nullPos]
|
||||
(Fix $ NLet [NamedVar (mkSelector "b") (mkInt 5) nullPos] $ mkSym "a")
|
||||
assertParseFail "let a = 4; let b = 3; in b"
|
||||
|
||||
case_let_scoped_inherit = do
|
||||
assertParseText "let a = null; inherit (b) c; in c" $ Fix $ NLet
|
||||
[ NamedVar (mkSelector "a") mkNull
|
||||
, Inherit (Just $ mkSym "b") [StaticKey "c" Nothing] ]
|
||||
[ NamedVar (mkSelector "a") mkNull nullPos
|
||||
, Inherit (Just $ mkSym "b") [StaticKey "c"] nullPos ]
|
||||
(mkSym "c")
|
||||
assertParseFail "let inherit (b) c in c"
|
||||
|
||||
|
@ -249,18 +250,19 @@ case_string_antiquote = do
|
|||
|
||||
case_select = do
|
||||
assertParseText "a . e .di. f" $ Fix $ NSelect (mkSym "a")
|
||||
(StaticKey "e" Nothing :| [StaticKey "di" Nothing, StaticKey "f" Nothing])
|
||||
(StaticKey "e" :| [StaticKey "di", StaticKey "f"])
|
||||
Nothing
|
||||
assertParseText "a.e . d or null" $ Fix $ NSelect (mkSym "a")
|
||||
(StaticKey "e" Nothing :| [StaticKey "d" Nothing])
|
||||
(StaticKey "e" :| [StaticKey "d"])
|
||||
(Just mkNull)
|
||||
assertParseText "{}.\"\"or null" $ Fix $ NSelect (Fix (NSet []))
|
||||
(DynamicKey (Plain "") :| []) (Just mkNull)
|
||||
(DynamicKey (Plain (DoubleQuoted [])) :| []) (Just mkNull)
|
||||
assertParseText "{ a = [1]; }.a or [2] ++ [3]" $ Fix $ NBinary NConcat
|
||||
(Fix (NSelect
|
||||
(Fix (NSet [NamedVar (StaticKey "a" Nothing :| [])
|
||||
(Fix (NList [Fix (NConstant (NInt 1))]))]))
|
||||
(StaticKey "a" Nothing :| [])
|
||||
(Fix (NSet [NamedVar (StaticKey "a" :| [])
|
||||
(Fix (NList [Fix (NConstant (NInt 1))]))
|
||||
nullPos]))
|
||||
(StaticKey "a" :| [])
|
||||
(Just (Fix (NList [Fix (NConstant (NInt 2))])))))
|
||||
(Fix (NList [Fix (NConstant (NInt 3))]))
|
||||
|
||||
|
@ -269,7 +271,7 @@ case_select_path = do
|
|||
assertParseText "f.b ../a" $ Fix $ NBinary NApp select (mkPath False "../a")
|
||||
assertParseText "{}./def" $ Fix $ NBinary NApp (Fix (NSet [])) (mkPath False "./def")
|
||||
assertParseText "{}.\"\"./def" $ Fix $ NBinary NApp
|
||||
(Fix $ NSelect (Fix (NSet [])) (DynamicKey (Plain "") :| []) Nothing)
|
||||
(Fix $ NSelect (Fix (NSet [])) (DynamicKey (Plain (DoubleQuoted [])) :| []) Nothing)
|
||||
(mkPath False "./def")
|
||||
where select = Fix $ NSelect (mkSym "f") (mkSelector "b") Nothing
|
||||
|
||||
|
@ -308,8 +310,8 @@ case_operators = do
|
|||
assertParseText "1 + (if true then 2 else 3)" $ mkOper2 NPlus (mkInt 1) $ Fix $ NIf
|
||||
(mkBool True) (mkInt 2) (mkInt 3)
|
||||
assertParseText "{ a = 3; } // rec { b = 4; }" $ mkOper2 NUpdate
|
||||
(Fix $ NSet [NamedVar (mkSelector "a") (mkInt 3)])
|
||||
(Fix $ NRecSet [NamedVar (mkSelector "b") (mkInt 4)])
|
||||
(Fix $ NSet [NamedVar (mkSelector "a") (mkInt 3) nullPos])
|
||||
(Fix $ NRecSet [NamedVar (mkSelector "b") (mkInt 4) nullPos])
|
||||
assertParseText "--a" $ mkOper NNeg $ mkOper NNeg $ mkSym "a"
|
||||
assertParseText "a - b - c" $ mkOper2 NMinus
|
||||
(mkOper2 NMinus (mkSym "a") (mkSym "b")) $
|
||||
|
|
|
@ -11,151 +11,137 @@
|
|||
|
||||
module PrettyParseTests where
|
||||
|
||||
import Control.Monad
|
||||
import Data.Algorithm.Diff
|
||||
import Data.Algorithm.DiffOutput
|
||||
import Data.Char
|
||||
import Data.Fix
|
||||
import qualified Data.List.NonEmpty as NE
|
||||
import Data.Text (Text, pack)
|
||||
import qualified Data.Text as Text
|
||||
import Generic.Random
|
||||
import Hedgehog
|
||||
import qualified Hedgehog.Gen as Gen
|
||||
import qualified Hedgehog.Range as Range
|
||||
import Nix.Atoms
|
||||
import Nix.Expr
|
||||
import Nix.Parser
|
||||
import Nix.Pretty
|
||||
import Test.QuickCheck.Instances.Semigroup ()
|
||||
import Test.QuickCheck.Instances.Text ()
|
||||
import qualified Test.QuickCheck.Property as P
|
||||
import Test.Tasty
|
||||
import Test.Tasty.QuickCheck hiding (Success, Failure)
|
||||
import Test.Tasty.Hedgehog
|
||||
import Text.Megaparsec (Pos, SourcePos, mkPos)
|
||||
import Text.PrettyPrint.ANSI.Leijen ((</>), text)
|
||||
import qualified Text.PrettyPrint.ANSI.Leijen as P
|
||||
import qualified Text.Show.Pretty as PS
|
||||
|
||||
-- Instead of using the Generic arbitrary instance (which doesn't exist anyway
|
||||
-- for Text), we use a different generator which just prints sensible looking
|
||||
-- variable names
|
||||
custom :: GenList '[Text]
|
||||
custom = asciiText :@ Nil
|
||||
|
||||
asciiString :: Gen String
|
||||
asciiString = do
|
||||
n <- choose (1, 15)
|
||||
replicateM n (elements ['a'..'z'])
|
||||
asciiString :: MonadGen m => m String
|
||||
asciiString = Gen.list (Range.linear 1 15) Gen.lower
|
||||
|
||||
asciiText :: Gen Text
|
||||
asciiText = pack <$> asciiString
|
||||
|
||||
pcustom :: GenList '[Pos]
|
||||
pcustom = arbitrary :@ Nil
|
||||
|
||||
-- | This generator generates selects one of the constructors uniformly and
|
||||
-- also decreases the size of the generator by dividing by the branching
|
||||
-- factor. This ensures sensible termination.
|
||||
genArb :: (GArbitrary (Options 'Sized '[Text]) a, GUniformWeight a) => Gen a
|
||||
genArb = genericArbitraryWith (setGenerators custom sizedOpts) uniform
|
||||
|
||||
-- Might want to replace this instance with a constant value
|
||||
instance Arbitrary Pos where
|
||||
arbitrary = mkPos <$> (getSmall <$> arbitrary `suchThat` (> 0))
|
||||
genPos :: Gen Pos
|
||||
genPos = mkPos <$> Gen.int (Range.linear 1 256)
|
||||
|
||||
instance Arbitrary (f (Fix f)) => Arbitrary (Fix f) where
|
||||
arbitrary = genArb
|
||||
genSourcePos :: Gen SourcePos
|
||||
genSourcePos = SourcePos <$> asciiString <*> genPos <*> genPos
|
||||
|
||||
instance Arbitrary f => Arbitrary (NString f) where
|
||||
arbitrary = genArb
|
||||
genKeyName :: Gen (NKeyName NExpr)
|
||||
genKeyName = Gen.choice [ DynamicKey <$> genAntiquoted genString
|
||||
, StaticKey <$> asciiText ]
|
||||
|
||||
instance Arbitrary SourcePos where
|
||||
arbitrary = genericArbitraryWith (setGenerators pcustom sizedOpts) uniform
|
||||
genAntiquoted :: Gen a -> Gen (Antiquoted a NExpr)
|
||||
genAntiquoted gen = Gen.choice
|
||||
[ Plain <$> gen
|
||||
, pure EscapedNewline
|
||||
, Antiquoted <$> genExpr
|
||||
]
|
||||
|
||||
instance Arbitrary f => Arbitrary (Binding f) where
|
||||
arbitrary = genArb
|
||||
genBinding :: Gen (Binding NExpr)
|
||||
genBinding = Gen.choice
|
||||
[ NamedVar <$> genAttrPath <*> genExpr <*> genSourcePos
|
||||
, Inherit <$> Gen.maybe genExpr
|
||||
<*> Gen.list (Range.linear 0 5) genKeyName
|
||||
<*> genSourcePos
|
||||
]
|
||||
|
||||
instance Arbitrary f => Arbitrary (NKeyName f) where
|
||||
arbitrary = oneof [ DynamicKey <$> arbitrary
|
||||
, StaticKey <$> asciiText <*> arbitrary ]
|
||||
genString :: Gen (NString NExpr)
|
||||
genString = Gen.choice
|
||||
[ DoubleQuoted <$> Gen.list (Range.linear 0 5) (genAntiquoted asciiText)
|
||||
, Indented <$> Gen.int (Range.linear 0 10)
|
||||
<*> Gen.list (Range.linear 0 5) (genAntiquoted asciiText)
|
||||
]
|
||||
|
||||
instance Arbitrary f => Arbitrary (Params f) where
|
||||
arbitrary =
|
||||
oneof [ Param <$> asciiText
|
||||
, ParamSet <$> listOf ((,) <$> asciiText <*> arbitrary) <*> arbitrary
|
||||
<*> oneof [pure Nothing, Just <$> asciiText]
|
||||
]
|
||||
genAttrPath :: Gen (NAttrPath NExpr)
|
||||
genAttrPath = (NE.:|) <$> genKeyName
|
||||
<*> Gen.list (Range.linear 0 4) genKeyName
|
||||
|
||||
instance Arbitrary NAtom where
|
||||
arbitrary =
|
||||
oneof [ NInt <$> arbitrary `suchThat` (>= 0)
|
||||
, NFloat <$> arbitrary `suchThat` (>= 0)
|
||||
, NBool <$> arbitrary
|
||||
, pure NNull
|
||||
, NUri <$> asciiText `suchThat` (\x -> Text.length x > 0) ]
|
||||
genParams :: Gen (Params NExpr)
|
||||
genParams = Gen.choice
|
||||
[ Param <$> asciiText
|
||||
, ParamSet <$> Gen.list (Range.linear 0 10) ((,) <$> asciiText
|
||||
<*> Gen.maybe genExpr)
|
||||
<*> Gen.bool
|
||||
<*> Gen.choice [pure Nothing, Just <$> asciiText]
|
||||
]
|
||||
|
||||
instance Arbitrary NUnaryOp where
|
||||
arbitrary = genArb
|
||||
|
||||
instance Arbitrary NBinaryOp where
|
||||
arbitrary = genArb
|
||||
|
||||
instance (Arbitrary f) => Arbitrary (Antiquoted Text f) where
|
||||
arbitrary = genArb
|
||||
|
||||
instance (Arbitrary f) => Arbitrary (Antiquoted (NString f) f) where
|
||||
arbitrary = genArb
|
||||
genAtom :: Gen NAtom
|
||||
genAtom = Gen.choice
|
||||
[ NInt <$> Gen.integral (Range.linear 0 1000)
|
||||
, NFloat <$> Gen.float (Range.linearFrac 0.0 1000.0)
|
||||
, NBool <$> Gen.bool
|
||||
, pure NNull ]
|
||||
|
||||
-- This is written by hand so we can use `fairList` rather than the normal
|
||||
-- list Arbitrary instance which makes the generator terminate. The
|
||||
-- distribution is not scientifically chosen.
|
||||
instance Arbitrary f => Arbitrary (NExprF f) where
|
||||
arbitrary =
|
||||
sized $ \n ->
|
||||
if n < 2
|
||||
then oneof [genConstant, genStr, genSym, genLiteralPath, genEnvPath ]
|
||||
else
|
||||
frequency
|
||||
[ ( 1, genConstant)
|
||||
, ( 1, genSym)
|
||||
, ( 4, resize (n `div` 3) genIf)
|
||||
, (10, genRecSet )
|
||||
, (20, genSet )
|
||||
, ( 5, genList )
|
||||
, ( 2, genUnary )
|
||||
, ( 2, resize (n `div` 3) genBinary )
|
||||
, ( 3, resize (n `div` 3) genSelect )
|
||||
, (20, resize (n `div` 2) genAbs )
|
||||
, ( 2, resize (n `div` 2) genHasAttr )
|
||||
, (10, resize (n `div` 2) genLet )
|
||||
, (10, resize (n `div` 2) genWith )
|
||||
, ( 1, resize (n `div` 2) genAssert)
|
||||
]
|
||||
where
|
||||
genConstant = NConstant <$> arbitrary
|
||||
genStr = NStr <$> arbitrary
|
||||
genSym = NSym <$> asciiText
|
||||
genList = NList <$> fairList arbitrary
|
||||
genSet = NSet <$> fairList arbitrary
|
||||
genRecSet = NRecSet <$> fairList arbitrary
|
||||
genLiteralPath = NLiteralPath . ("./" ++) <$> asciiString
|
||||
genEnvPath = NEnvPath <$> asciiString
|
||||
genUnary = NUnary <$> arbitrary <*> arbitrary
|
||||
genBinary = NBinary <$> arbitrary <*> arbitrary <*> arbitrary
|
||||
genSelect = NSelect <$> arbitrary <*> arbitrary <*> arbitrary
|
||||
genHasAttr = NHasAttr <$> arbitrary <*> arbitrary
|
||||
genAbs = NAbs <$> arbitrary <*> arbitrary
|
||||
genLet = NLet <$> fairList arbitrary <*> arbitrary
|
||||
genIf = NIf <$> arbitrary <*> arbitrary <*> arbitrary
|
||||
genWith = NWith <$> arbitrary <*> arbitrary
|
||||
genAssert = NAssert <$> arbitrary <*> arbitrary
|
||||
genExpr :: Gen NExpr
|
||||
genExpr = Gen.sized $ \(Size n) ->
|
||||
Fix <$>
|
||||
if n < 2
|
||||
then Gen.choice
|
||||
[genConstant, genStr, genSym, genLiteralPath, genEnvPath ]
|
||||
else
|
||||
Gen.frequency
|
||||
[ ( 1, genConstant)
|
||||
, ( 1, genSym)
|
||||
, ( 4, Gen.resize (Size (n `div` 3)) genIf)
|
||||
, (10, genRecSet )
|
||||
, (20, genSet )
|
||||
, ( 5, genList )
|
||||
, ( 2, genUnary )
|
||||
, ( 2, Gen.resize (Size (n `div` 3)) genBinary )
|
||||
, ( 3, Gen.resize (Size (n `div` 3)) genSelect )
|
||||
, (20, Gen.resize (Size (n `div` 2)) genAbs )
|
||||
, ( 2, Gen.resize (Size (n `div` 2)) genHasAttr )
|
||||
, (10, Gen.resize (Size (n `div` 2)) genLet )
|
||||
, (10, Gen.resize (Size (n `div` 2)) genWith )
|
||||
, ( 1, Gen.resize (Size (n `div` 2)) genAssert)
|
||||
]
|
||||
where
|
||||
genConstant = NConstant <$> genAtom
|
||||
genStr = NStr <$> genString
|
||||
genSym = NSym <$> asciiText
|
||||
genList = NList <$> fairList genExpr
|
||||
genSet = NSet <$> fairList genBinding
|
||||
genRecSet = NRecSet <$> fairList genBinding
|
||||
genLiteralPath = NLiteralPath . ("./" ++) <$> asciiString
|
||||
genEnvPath = NEnvPath <$> asciiString
|
||||
genUnary = NUnary <$> Gen.enumBounded <*> genExpr
|
||||
genBinary = NBinary <$> Gen.enumBounded <*> genExpr <*> genExpr
|
||||
genSelect = NSelect <$> genExpr <*> genAttrPath <*> Gen.maybe genExpr
|
||||
genHasAttr = NHasAttr <$> genExpr <*> genAttrPath
|
||||
genAbs = NAbs <$> genParams <*> genExpr
|
||||
genLet = NLet <$> fairList genBinding <*> genExpr
|
||||
genIf = NIf <$> genExpr <*> genExpr <*> genExpr
|
||||
genWith = NWith <$> genExpr <*> genExpr
|
||||
genAssert = NAssert <$> genExpr <*> genExpr
|
||||
|
||||
-- | Useful when there are recursive positions at each element of the list as
|
||||
-- it divides the size by the length of the generated list.
|
||||
fairList :: Gen a -> Gen [a]
|
||||
fairList g = do
|
||||
s <- getSize
|
||||
k <- choose (0, s)
|
||||
fairList g = Gen.sized $ \s -> do
|
||||
k <- Gen.int (Range.linear 0 (unSize s))
|
||||
-- Use max here to avoid dividing by zero when there is the empty list
|
||||
resize (s `div` max 1 k) $ vectorOf k g
|
||||
Gen.resize (Size (unSize s `div` max 1 k)) $ Gen.list (Range.singleton k) g
|
||||
|
||||
equivUpToNormalization :: NExpr -> NExpr -> Bool
|
||||
equivUpToNormalization x y = normalize x == normalize y
|
||||
|
@ -174,11 +160,11 @@ normalize = cata $ \case
|
|||
r -> Fix r
|
||||
|
||||
where
|
||||
normBinding (NamedVar path r) = NamedVar (NE.map normKey path) r
|
||||
normBinding (Inherit mr names) = Inherit mr (map normKey names)
|
||||
normBinding (NamedVar path r pos) = NamedVar (NE.map normKey path) r pos
|
||||
normBinding (Inherit mr names pos) = Inherit mr (map normKey names) pos
|
||||
|
||||
normKey (DynamicKey quoted) = DynamicKey (normAntiquotedString quoted)
|
||||
normKey (StaticKey name _) = StaticKey name Nothing
|
||||
normKey (StaticKey name) = StaticKey name
|
||||
|
||||
normAntiquotedString :: Antiquoted (NString NExpr) NExpr
|
||||
-> Antiquoted (NString NExpr) NExpr
|
||||
|
@ -200,38 +186,38 @@ normalize = cata $ \case
|
|||
normParams r = r
|
||||
|
||||
-- | Test that parse . pretty == id up to attribute position information.
|
||||
prop_prettyparse :: NExpr -> P.Result
|
||||
prop_prettyparse p =
|
||||
prop_prettyparse :: Monad m => NExpr -> PropertyT m ()
|
||||
prop_prettyparse p = do
|
||||
let prog = show (pretty p)
|
||||
in case parse (pack prog) of
|
||||
Failure s -> P.rejected
|
||||
{ P.reason = show $
|
||||
case parse (pack prog) of
|
||||
Failure s -> do
|
||||
footnote $ show $
|
||||
text "Parse failed:" </> text (show s)
|
||||
P.<$> P.indent 2 (pretty p) }
|
||||
P.<$> P.indent 2 (pretty p)
|
||||
discard
|
||||
Success v
|
||||
| equivUpToNormalization p v -> P.succeeded
|
||||
| otherwise ->
|
||||
| equivUpToNormalization p v -> success
|
||||
| otherwise -> do
|
||||
let pp = normalise prog
|
||||
pv = normalise (show (pretty v))
|
||||
in (P.liftBool (pp == pv))
|
||||
{ P.reason = show $
|
||||
text "----------------------------------------"
|
||||
P.<$> text "Expr before:" P.<$> P.indent 2 (text (PS.ppShow p))
|
||||
P.<$> text "----------------------------------------"
|
||||
P.<$> text "Expr after:" P.<$> P.indent 2 (text (PS.ppShow v))
|
||||
P.<$> text "----------------------------------------"
|
||||
P.<$> text "Pretty before:" P.<$> P.indent 2 (text prog)
|
||||
P.<$> text "----------------------------------------"
|
||||
P.<$> text "Pretty after:" P.<$> P.indent 2 (pretty v)
|
||||
P.<$> text "----------------------------------------"
|
||||
P.<$> text "Normalised before:" P.<$> P.indent 2 (text pp)
|
||||
P.<$> text "----------------------------------------"
|
||||
P.<$> text "Normalised after:" P.<$> P.indent 2 (text pv)
|
||||
P.<$> text "========================================"
|
||||
P.<$> text "Normalised diff:"
|
||||
P.<$> text (ppDiff (diff pp pv))
|
||||
P.<$> text "========================================"
|
||||
}
|
||||
footnote $ show $
|
||||
text "----------------------------------------"
|
||||
P.<$> text "Expr before:" P.<$> P.indent 2 (text (PS.ppShow p))
|
||||
P.<$> text "----------------------------------------"
|
||||
P.<$> text "Expr after:" P.<$> P.indent 2 (text (PS.ppShow v))
|
||||
P.<$> text "----------------------------------------"
|
||||
P.<$> text "Pretty before:" P.<$> P.indent 2 (text prog)
|
||||
P.<$> text "----------------------------------------"
|
||||
P.<$> text "Pretty after:" P.<$> P.indent 2 (pretty v)
|
||||
P.<$> text "----------------------------------------"
|
||||
P.<$> text "Normalised before:" P.<$> P.indent 2 (text pp)
|
||||
P.<$> text "----------------------------------------"
|
||||
P.<$> text "Normalised after:" P.<$> P.indent 2 (text pv)
|
||||
P.<$> text "========================================"
|
||||
P.<$> text "Normalised diff:"
|
||||
P.<$> text (ppDiff (diff pp pv))
|
||||
P.<$> text "========================================"
|
||||
assert (pp == pv)
|
||||
where
|
||||
pretty = prettyNix
|
||||
parse = parseNixText
|
||||
|
@ -241,6 +227,7 @@ prop_prettyparse p =
|
|||
diff :: String -> String -> [Diff [String]]
|
||||
diff s1 s2 = getDiff (map (:[]) (lines s1)) (map (:[]) (lines s2))
|
||||
|
||||
tests :: Int -> TestTree
|
||||
tests n = testProperty "Pretty/Parse Property" $
|
||||
withMaxSuccess n prop_prettyparse
|
||||
tests :: TestLimit -> TestTree
|
||||
tests n = testProperty "Pretty/Parse Property" $ withTests n $ property $ do
|
||||
x <- forAll genExpr
|
||||
prop_prettyparse x
|
||||
|
|
59
tests/ReduceExprTests.hs
Normal file
59
tests/ReduceExprTests.hs
Normal file
|
@ -0,0 +1,59 @@
|
|||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
|
||||
module ReduceExprTests (tests) where
|
||||
import Data.Fix
|
||||
import Test.Tasty
|
||||
import Test.Tasty.HUnit
|
||||
|
||||
import Nix.Atoms
|
||||
import Nix.Expr.Types
|
||||
import Nix.Expr.Types.Annotated
|
||||
import Nix.Parser
|
||||
import Nix.Reduce (reduceExpr)
|
||||
|
||||
|
||||
tests :: TestTree
|
||||
tests = testGroup "Expr Reductions"
|
||||
[ testCase "Non nested NSelect on set should be reduced" $
|
||||
cmpReduceResult selectBasic selectBasicExpect,
|
||||
testCase "Nested NSelect on set should be reduced" $
|
||||
cmpReduceResult selectNested selectNestedExpect,
|
||||
testCase "Non nested NSelect with incorrect attrpath shouldn't be reduced" $
|
||||
shouldntReduce selectIncorrectAttrPath,
|
||||
testCase "Nested NSelect with incorrect attrpath shouldn't be reduced" $
|
||||
shouldntReduce selectNestedIncorrectAttrPath
|
||||
]
|
||||
|
||||
assertSucc :: Result a -> IO a
|
||||
assertSucc (Success a) = pure a
|
||||
assertSucc (Failure d) = assertFailure $ show d
|
||||
|
||||
cmpReduceResult :: Result NExprLoc -> NExpr -> Assertion
|
||||
cmpReduceResult r e = do
|
||||
r <- assertSucc r
|
||||
r <- stripAnnotation <$> reduceExpr Nothing r
|
||||
r @?= e
|
||||
|
||||
shouldntReduce :: Result NExprLoc -> Assertion
|
||||
shouldntReduce r = do
|
||||
r <- assertSucc r
|
||||
rReduced <- reduceExpr Nothing r
|
||||
r @?= rReduced
|
||||
|
||||
selectBasic :: Result NExprLoc
|
||||
selectBasic = parseNixTextLoc "{b=2;a=42;}.a"
|
||||
|
||||
selectBasicExpect :: NExpr
|
||||
selectBasicExpect = Fix . NConstant $ NInt 42
|
||||
|
||||
selectNested :: Result NExprLoc
|
||||
selectNested = parseNixTextLoc "{a={b=2;a=42;};b={a=2;};}.a.a"
|
||||
|
||||
selectNestedExpect :: NExpr
|
||||
selectNestedExpect = Fix . NConstant $ NInt 42
|
||||
|
||||
selectIncorrectAttrPath :: Result NExprLoc
|
||||
selectIncorrectAttrPath = parseNixTextLoc "{a=42;}.b"
|
||||
|
||||
selectNestedIncorrectAttrPath :: Result NExprLoc
|
||||
selectNestedIncorrectAttrPath = parseNixTextLoc "{a={a=42;};}.a.b"
|
|
@ -48,8 +48,7 @@ nixEvalString expr = do
|
|||
return res
|
||||
|
||||
nixEvalFile :: FilePath -> IO String
|
||||
nixEvalFile fp = readProcess "nix-instantiate"
|
||||
["--store", "local?root=/tmp", "--eval", fp] ""
|
||||
nixEvalFile fp = readProcess "nix-instantiate" ["--eval", "--strict", fp] ""
|
||||
|
||||
assertEvalFileMatchesNix :: FilePath -> Assertion
|
||||
assertEvalFileMatchesNix fp = do
|
||||
|
|
0
tests/files/findFile.nix
Normal file
0
tests/files/findFile.nix
Normal file
Loading…
Reference in a new issue