packages feed

hnix 0.5.2 → 0.17.0

raw patch · 298 files changed

Files

+ ChangeLog.md view
@@ -0,0 +1,485 @@++# ChangeLog++## [(diff)](https://github.com/haskell-nix/hnix/compare/0.16.0...0.17.0#files_bucket) 0.17.0++* Additional+  * `Nix.Effect`+    * [(link)](https://github.com/haskell-nix/hnix/pull/1051) Introduction of new type NarContent, a tagged union type of `byteString` and `FilePath`.+    * [(link)](https://github.com/haskell-nix/hnix/pull/1051) getURL of instance MonadHttp IO is finally working through hnix-store. Which also means+      builtins.fetchurl is working through it.+* Breaking:+  * `Nix.Effect`+    * [(link)](https://github.com/haskell-nix/hnix/pull/1051) MonadStore's addToStore signature changed to `StorePathName -> NarContent -> RecursiveFlag -> RepairFlag -> m (Either ErrorCall StorePath)` with new introduction of NarContent. Which enable us to add byteString as file to Store. It is corresponding to the hnix-store api change.+  * `Nix.Expr.Types`+    * [(link)](https://github.com/haskell-nix/hnix/pull/1042/files) The central HNix type `NExprF` changed, the `NApp` was moved out of `NBinary` & now a `NExprF` constructor of its own, the type signatures were changed accordingly.+    * [(link)](https://github.com/haskell-nix/hnix/pull/1038/files) project was using `megaparsec` `{,Source}Pos` and to use it shipped a lot of orphan instances. To improve the situation & performance (reports [#1026](https://github.com/haskell-nix/hnix/issues/1026), [#746](https://github.com/haskell-nix/hnix/issues/746)) project uses `N{,Source}Pos` types, related type signatures were changed accordingly.+  * `Nix.Value`+    * [(link)](https://github.com/haskell-nix/hnix/pull/1046/files) Unify builder `mkNV*` and `NV*` patterns by bidirectional synonyms, a lot of builders `mkNV*` are removed, and merged to `NV*`. e.g. instead of builder `mkNVList`, `NVList` should be used.+    * [(link)](https://github.com/haskell-nix/hnix/pull/1046/files) Constraint `NVConstraint f = (Comonad f, Applicative f)` was introduced, in order to unify builder `mkNV*` and `NV*` patterns.++  * `Nix.Parser`:+    * [(link)](https://github.com/haskell-nix/hnix/pull/1047/files) rm `OperatorInfo`, using `NOperatorDef`. Number of functions changed signatures accordingly:+    * In `Nix.Pretty`:+      * `NixDoc ann`+      * `mkNixDoc`+      * `selectOp`+      * `hasAttrOp`+      * `precedenceWrap`+      * `wrapPath`+    * In `Nix.Parser`:+      * rm `get{App,Unary,Binary,Special}Operator`, currely `NOp` class instances are used instead.+    +  * `Nix.Pretty`:+    * [(link)](https://github.com/haskell-nix/hnix/pull/1047/files) rm `appOp`, instead use `appOpDef`.+    * [(link)](https://github.com/haskell-nix/hnix/pull/1047/files) `precedenceWrap` behaviour is changed (to be literal to the name), the old behaviour is now a `wrap` function.++## [(diff)](https://github.com/haskell-nix/hnix/compare/0.15.0...0.16.0#files_bucket) 0.16.0++On update problems, please reach out to us. For support refere to: https://github.com/haskell-nix/hnix/issues/984++Partial log (for now):++* Breaking:+  * Where `coerce` should work, removed `newtype` accessors.+  * [(link)](https://github.com/haskell-nix/hnix/pull/1006/files), [(link)](https://github.com/haskell-nix/hnix/pull/1009/files) Incomprehensible record accessors zoo like: `arg`, `options`, `unStore`, `scFlavor`, `nsContext` `_provenance` - was organized, now all record accessors start with `get*`, and their names tend to have according unique sematic meaning of data action they do.+  * Builder names got unified. Now they all start with `mk*`. So a lof of `nvSet` became `mkNVSet`.+  * `Nix.String` builders/destructors instead of `make` use `mk`, & where mentioning of `string` is superflous - dropped it from the name, so `stringIgnoreContext`, became `ignoreContext`.+  * Type system:+    * Things that are paths are now `newtype Path = Path String`.+    * Things that are indentifier names are now `newtype VarName = VarName Text`.+    * Function signatures changed accordingly.++* Additional:+  * [(link)](https://github.com/haskell-nix/hnix/pull/1019) Matched expression escaping & its representation to breaking changes in Nix `2.4`.+  * `Builtins` (`builtins` function set) gained functions:+    * [(link)](https://github.com/haskell-nix/hnix/pull/1032) `path`+    * [(link)](https://github.com/haskell-nix/hnix/pull/1020) `isPathNix`+    * [(link)](https://github.com/haskell-nix/hnix/pull/1032) `unsafeDiscardOutputDependency`+    * [(link)](https://github.com/haskell-nix/hnix/pull/1031) `ceil`+    * [(link)](https://github.com/haskell-nix/hnix/pull/1031) `floor`+    * [(link)](https://github.com/haskell-nix/hnix/pull/1021) `hashFile`+    * [(link)](https://github.com/haskell-nix/hnix/pull/1033) `groupBy`+  * [(link)](https://github.com/haskell-nix/hnix/pull/1029) `data/nix` submodule (& its tests) updated to 2022-01-17.++* Other notes:+  * `Shorthands` was kept untouched.++## [(diff)](https://github.com/haskell-nix/hnix/compare/0.14.0...0.15.0#files_bucket) 0.15.0++For support refere to: https://github.com/haskell-nix/hnix/issues/984++Partial log (for now):++* Breaking:++  * `Nix.Expr.Shorthands`:+    * `inherit{,From}`:+      * dropped second(/third) argument as irrelevant ([report](https://github.com/haskell-nix/hnix/issues/326))+      * bindings to inherit changed type from complex `[NKeyName]` (which is for static & dynamic keys) to `[VarName]` (`VarName` is newtype of `Text`).+      * So examples of use now are: `inherit ["a", "b"]`, `inheritFrom (var "a") ["b", "c"]`+    * `mkAssert`: fixed ([report](https://github.com/haskell-nix/hnix/issues/969)).+    * fx presedence between the operators:+        +        ```haskell+        (@@), (@.), (@./), ($==), ($!=), ($<), ($<=), ($>), ($>=), ($&&), ($||), ($->), ($//), ($+), ($-), ($*), ($/), ($++), (==>)+        ```+        +        Now these shorthands can be used without sectioning & so represent the Nix expressions one to one.+        +        ```haskell+        nix = "           a/b   //            c/def   //           <g>  <             def/d"+        hask = mkRelPath "a/b" $// mkRelPath "c/def" $// mkEnvPath "g" $<  mkRelPath "def/d"+        ```++* Additional+  * `Nix.Expr.Shorthands`:+    * added:+      * `emptySet`+      * `emptyList`+      * `mkOp{,2}`+      * `mk{,Named,Variadic,General}ParamSet`+      * `mkNeg` - number negation.+      * `@.<|>` for Nix language `s.x or y` expession.+    * entered deprecation:+      * `mkOper{,2}` bacame `mkOp{,2}`.+      * `mkBinop` became `mkOp2`.+      * `mkParaset` supeceeded by `mk{,Named{,Variadic},Variadic,General}ParamSet`.+    * fixed:+      * `mkAssert` was creating `with`, now properly creates `assert`.++## [(diff)](https://github.com/haskell-nix/hnix/compare/0.13.1...0.14.0#files_bucket) 0.14.0 (2021-07-08)++* GHC 9.0 support.++* HNix switched to pre-0.9 style of log (aka "no log"). We temporarily stopped producing log, choosing effectiveness over writing about it.++* All changes seem trivial (from the inside). There is no changes in `Nix.Expr.Shorthands` module. Would there be difficulties in migration - please write to us - we would tackle & solve it togather.++A partial log:++* Breaking:++  * `Nix.Effects`:+    * rm `pathExits` in favour of `doesPathExist` (in `Nix.Render`: `class MonadFile`: `doesPathExist`)++  * `Nix.Var`: was found being superflous ([report](https://github.com/haskell-nix/hnix/issues/946)), so reduced. use `Control.Monad.Ref` instead.++  * `Nix.Normal`+    * rename `opaque(,->Val)`, indicate that it is a literal.+  +  * `Nix.Thunk`:+    * `class MonadThunkId m => MonadThunk{,F} t m a`:+      * rename `query(M->){,F}`++* Additional:++  * `Nix.Utils`:+    * added type `TransformF`++  * `Nix.Eval`:+    * added fun:+      * `evalContent`+      * `addMetaInfo`+      +  * `Nix.Types.Assumption`:+    * added instances:+      * `Assumption`: `{Semigroup,Monoid,One}`++  * `Nix.Type.Env`:+    * added instances:+      * `Env`: `{Semigroup,Monoid,One}`+  +  * `Nix`:+    * changed argument order:+      * `nixEval`:+        +        ```haskell+        -- was:+          => Maybe FilePath -> Transform g (m a) -> Alg g (m a) -> Fix g -> m a+        -- became:+          => Transform g (m a) -> Alg g (m a) -> Maybe FilePath -> Fix g -> m a+        ```+        +  * `Nix.Normal`+    * add `thunkVal` literal & use it where appropriate `{deThunk, removeEffects}`+      +  * `Nix.Thunk.Basic`:+    * export `deferred`+++### [(diff)](https://github.com/haskell-nix/hnix/compare/0.13.0.1...0.13.1#files_bucket) 0.13.1 (2021-05-22)+  * [(link)](https://github.com/haskell-nix/hnix/pull/936/files) `Nix.Parser`: `annotateLocation`: Fix source location preservation.+  * [(link)](https://github.com/haskell-nix/hnix/pull/934/files) Require Cabal dependency `relude` `>= 1.0`: since imports & Cabal file got cleaned-up & that clean-up depends on `relude` reimports introduced in aforementioned version.+  * Refactors, reorganization in some modules, docs, clean-ups.++#### [(diff)](https://github.com/haskell-nix/hnix/compare/0.13.0...0.13.0.1#files_bucket) 0.13.0.1 (2021-05-11)+  * [(link)](https://github.com/haskell-nix/hnix/pull/931/files) `Nix.Expr.Types`: Fix CPP on `Instances.TH.Lift` import.++## [(diff)](https://github.com/haskell-nix/hnix/compare/0.12.0...0.13.0#files_bucket) 0.13.0 (2021-05-10)++* Breaking:++  * [(link)](https://github.com/haskell-nix/hnix/pull/859/files) [(link)](https://github.com/haskell-nix/hnix/pull/863/files) [(link)](https://github.com/haskell-nix/hnix/pull/866/files) `Nix.Thunk`: `class MonadThunk t m a | t -> m, t -> a`. Class was initially designed with Kleisli arrows (`v -> m a`) in mind, which where put to have the design open and inviting customization & integration. Those functional arguments are for custom implementation, so  which in reality of the project were never used and HNax just "essentially" (simplifying, because `pure` was mixed with monadic binds to `f`) was passing `pure` into them (actually, `f <=< pure`). These Kliesli functors got arguments sorted properly and were moved to a `MonadThunkF` class and names gained `*F`. And `MonadThunk` now does only what is needed, for example `force` gets the thunk and computes it. All `MonadThunk{,F}` functions become with a classic Haskell arguments order, specialized, and got more straigh-forward to understand and use, and so now they tail recurse also.+      +      Now, for example, instead of `force t f` use it as `v <- force t` `f =<< force t`, or `f <=< force`.+      +      tl;dr: results:+      +      ```haskell+      class MonadThunkId m => MonadThunk t m a | t -> m, t -> a where+      +        thunkId  :: t -> ThunkId m+      +        thunk    :: m a -> m t+      +        queryM   :: m a -> t -> m a+        -- old became `queryMF`+      +        force    :: t -> m a+        -- old became `forceF`+      +        forceEff :: t -> m a+        -- old became `forceEffF`+      +        further  :: t -> m t+        -- old became `furtherF`+      +      +      -- | Class of Kleisli functors for easiness of customized implementation developlemnt.+      class MonadThunkF t m a | t -> m, t -> a where++        queryMF   :: (a   -> m r) -> m r -> t -> m r+        -- was :: t -> m r -> (a   -> m r) -> m r++        forceF    :: (a   -> m r) -> t   -> m r+        -- was :: t   -> (a   -> m r) -> m r++        forceEffF :: (a   -> m r) -> t   -> m r+        -- was :: t   -> (a   -> m r) -> m r++        furtherF  :: (m a -> m a) -> t   -> m t+        -- was :: t   -> (m a -> m a) -> m t++      ```+      +  * [(link)](https://github.com/haskell-nix/hnix/pull/862/files) [(link)](https://github.com/haskell-nix/hnix/pull/870/files) [(link)](https://github.com/haskell-nix/hnix/pull/871/files)  [(link)](https://github.com/haskell-nix/hnix/pull/872/files) [(link)](https://github.com/haskell-nix/hnix/pull/873/files) `Nix.Value.Monad`: `class MonadValue v m`: instances became specialized, Kleisli versions unflipped the arguments of methods into a classical order and moved to the `class MonadValueF`. As a result, `demand` now gets optimized by GHC and also tail recurse. Please, use `f =<< demand t`, or just use `demandF`, while `demandF` in fact just `kleisli =<< demand t`.+      +      ```haskell+      class MonadValue v m where+      +        demand :: v       ->         m v+        -- old became `demandF`++        inform :: v -> m v+        -- old became `informF`+      ++      class MonadValueF v m where++        demandF :: (v -> m r) -> v -> m r+        -- was :: v -> (v -> m r) -> m r++        informF :: (m v -> m v) -> v -> m v+        -- was :: v -> (m v -> m v) -> m v+      ```+      +  * [(link)](https://github.com/haskell-nix/hnix/pull/863/files) `Nix.Normal`: `normalizeValue` removed first functional argument that was passing the function that did the thunk forcing. Now function provides the thunk forcing. Now to normalize simply use `normalizeValue v`. Old implementation now is `normalizeValueF`.++  * [(link)](https://github.com/haskell-nix/hnix/pull/859/commits/8e043bcbda13ea4fd66d3eefd6da690bb3923edd) `Nix.Value.Equal`: `valueEqM`: freed from `RankNTypes: forall t f m .`.++  * [(link)](https://github.com/haskell-nix/hnix/pull/802/commits/529095deaf6bc6b102fe5a3ac7baccfbb8852e49#) `Nix.Strings`: all `hacky*` functions replaced with lawful implemetations, because of that all functions become lawful - dropped the `principled` suffix from functions:+    * `Nix.String`:+        ```haskell+        hackyGetStringNoContext          ->+             getStringNoContext+        hackyStringIgnoreContext         ->+             stringIgnoreContext+        hackyMakeNixStringWithoutContext ->+             makeNixStringWithoutContext++        principledMempty        -> mempty+        principledStringMempty  -> mempty+        principledStringMConcat -> mconcat+        principledStringMappend -> mappend++        principledGetContext                        ->+                  getContext+        principledMakeNixString                     ->+                  makeNixString+        principledIntercalateNixStrin               ->+                  intercalateNixString+        principledGetStringNoContext                ->+                  getStringNoContext+        principledStringIgnoreContext               ->+                  stringIgnoreContext+        principledMakeNixStringWithoutContext       ->+                  makeNixStringWithoutContext+        principledMakeNixStringWithSingletonContext ->+                  makeNixStringWithSingletonContext+        principledModifyNixContents                 ->+                  modifyNixContents+        ```++  * [(link)](https://github.com/haskell-nix/hnix/pull/805/files):+    * Data type: `MonadFix1T t m`: `Nix.Standard` -> `Nix.Utils.Fix1`+    * Children found their parents:+        +        ```haskell+        Binary   NAtom :: Nix.Expr.Types -> Nix.Atoms+        FromJSON NAtom :: Nix.Expr.Types -> Nix.Atoms+        ToJSON   NAtom :: Nix.Expr.Types -> Nix.Atoms++        Eq1 (NValueF p m)     :: Nix.Value.Equal -> Nix.Value++        Eq1 (NValue' t f m a) :: Nix.Value.Equal -> Nix.Value ++        HasCitations m v (NValue' t f m a) :: Nix.Pretty -> Nix.Cited+        HasCitations m v (NValue  t f m)   :: Nix.Pretty -> Nix.Cited++        when+          (package hashable >= 1.3.1) -- gained instance+          $ Hashable1 NonEmpty:: Nix.Expr.Types -> Void -- please use upstreamed instance++        -- | Was upstreamed, released in `ref-tf >= 0.5`.+        MonadAtomicRef   (ST s) :: Nix.Standard -> Void++        MonadAtomicRef   (Fix1T t m) :: Nix.Standard -> Nix.Utils.Fix1+        MonadRef         (Fix1T t m) :: Nix.Standard -> Nix.Utils.Fix1+        MonadEnv         (Fix1T t m) :: Nix.Standard -> Nix.Effects+        MonadExec        (Fix1T t m) :: Nix.Standard -> Nix.Effects+        MonadHttp        (Fix1T t m) :: Nix.Standard -> Nix.Effects+        MonadInstantiate (Fix1T t m) :: Nix.Standard -> Nix.Effects+        MonadIntrospect  (Fix1T t m) :: Nix.Standard -> Nix.Effects+        MonadPaths       (Fix1T t m) :: Nix.Standard -> Nix.Effects+        MonadPutStr      (Fix1T t m) :: Nix.Standard -> Nix.Effects+        MonadStore       (Fix1T t m) :: Nix.Standard -> Nix.Effects+        MonadFile        (Fix1T t m) :: Nix.Standard -> Nix.Render++        MonadEnv         (Fix1 t)    :: Nix.Standard -> Nix.Effects+        MonadExec        (Fix1 t)    :: Nix.Standard -> Nix.Effects+        MonadHttp        (Fix1 t)    :: Nix.Standard -> Nix.Effects+        MonadInstantiate (Fix1 t)    :: Nix.Standard -> Nix.Effects+        MonadIntrospect  (Fix1 t)    :: Nix.Standard -> Nix.Effects+        MonadPaths       (Fix1 t)    :: Nix.Standard -> Nix.Effects+        MonadPutStr      (Fix1 t)    :: Nix.Standard -> Nix.Effects+        ```+  * [(link)](https://github.com/haskell-nix/hnix/pull/878/files) `Nix.Value`: `nvSet{,',P}`: got unflipped, now accept source position argument before the value.+  +  * [(link)](https://github.com/haskell-nix/hnix/pull/878/files) `Nix.Pretty`: `mkNixDoc`: got unflipped.+  +  * [(link)](https://github.com/haskell-nix/hnix/pull/886/commits/381b0e5df9cc620a25533ff1c84045a4ea37a833) `Nix.Value`: Data constructor for `NValue' t f m a` changed (`NValue -> NValue'`).+  +  * [(link)](https://github.com/haskell-nix/hnix/pull/884/files) `Nix.Parser`: `Parser`: Data type was equivalent to `Either`, so became a type synonim for `Either`.++  * [(link)](https://github.com/haskell-nix/hnix/pull/884/files) `Nix.Thunk.Basic`: `instance MonadThunk (NThunkF m v) m v`: `queryM`: implementation no longer blocks the thunk resource it only reads from.+  +  * [(link)](https://github.com/haskell-nix/hnix/pull/908/files): Migrated `(String -> Text)`:+    * `Nix.Value`: `{NValueF, nvBuiltin{,'}, builtin{,2,3}, describeValue}`+    * `Nix.Eval`: `MonadNixEval`+    * `Nix.Render.Frame`: `render{Expr,Value}`+    * `Nix.Type`: `TVar`+    * `Nix.Thunk`: `ThunkLoop`+    * `Nix.Exec`: `{nvBuiltinP, nixInstantiateExpr, exec}`+    * `Nix.Effects`:+      * `class`:+        * `MonadExec: exec'`+        * `MonadEnv: getEnvVar`+        * `MonadInstantiate: instatiateExpr`+      * `parseStoreResult`+    * `Nix.Effects.Derivation`: `renderSymbolic`+    * `Nix.Lint`: `{NTypeF, symerr}`++* Additional:+  * [(link)](https://github.com/haskell-nix/hnix/commit/7e6cd97bf3288cb584241611fdb25bf85d7e0ba7) `cabal.project`: freed from the `cryptohash-sha512` override, Hackage trustees made a revision.+  * [(link)](https://github.com/haskell-nix/hnix/pull/824/commits/4422eb10959115f21045f39e302314a77df4b775) To be more approachable for user understanding, the thunk representation in outputs changed from `"<CYCLE>" -> "<expr>"`.+  * [(link)](https://github.com/haskell-nix/hnix/pull/925/commits/37e81c96996b07cbbdf9fa4bf380265e8c008482) The Nix evaluation cycle representation changed `"<CYCLE>" -> "<cycle>"`.+  * [(link)](https://github.com/haskell-nix/hnix/commit/51a3ff9e0065d50e5c625738696526c4a232b0cf) `Nix.Expr.Types`: added hacky implementation of `liftTyped` for `instance Lift (Fix NExprF)`.+  * [(link)](https://github.com/haskell-nix/hnix/commit/51a3ff9e0065d50e5c625738696526c4a232b0cf) `Nix.Builtins`: `derivation` primOp internal code always fully evaluated, so GHC now always ships only fully compiled version in the bytecode.+  * [(link)](https://github.com/haskell-nix/hnix/pull/890): Project switched to prelude `relude`.+  * A bunch of other stuff that is not user-facing.+++## [(diff)](https://github.com/haskell-nix/hnix/compare/0.11.1...0.12.0#files_bucket) 0.12.0 (2021-01-05)++* *Disclaimer*: Current `derivationStrict` primOp implementation and so every evaluation of a derivation into a store path currently relies on the `hnix-store-remote`, which for those operations relies on the running `nix-daemon`, and so operations use/produce effects into the `/nix/store`. Be cautious - it is effectful.++* Introduction:+  * New module `Nix.Effects.Derivation`.+  * Operations on derivations:+    * old got principled implementations.+    * also new operations got introduced.+  * Implementation of the `derivationStrict` primOp.++* Breaking:+  * [(link)](https://github.com/haskell-nix/hnix/pull/554/commits/3bba5549273c892c60aad5dd6d5058a8db40efbf) `Nix.Effects`: **class** `MonadStore` got principled implementation.+    * `addPath'` got principled into `addToStore`.+    * `toFile_` got principled into `addTextToStore'`.+    * For help & easy migration you may use `addPath` & `toFile_` `addTextToStore` standalone functions in the module.+  * [(link)](https://github.com/haskell-nix/hnix/pull/554/commits/3bba5549273c892c60aad5dd6d5058a8db40efbf) `Nix.Effects.Basic`: `defaultDerivationStrict` got reimplemented & moved into `Nix.Effects.Derivation`.+  * [(link)](https://github.com/haskell-nix/hnix/pull/554/commits/3bba5549273c892c60aad5dd6d5058a8db40efbf) `Nix.Standard`: instance for `MonadStore (Fix1T t m)` got principled accoding to class `MonadStore` changes.+  * [(link)](https://github.com/haskell-nix/hnix/pull/554/commits/3bba5549273c892c60aad5dd6d5058a8db40efbf) `Nix.Fresh.Basic`: instance for `MonadStore (StdIdT m)` got principled.++* Additional:+  * [(link)](https://github.com/haskell-nix/hnix/pull/554/commits/3bba5549273c892c60aad5dd6d5058a8db40efbf) **New module `Nix.Effects.Derivation`**: [HNix(0.12.0):Nix.Effects.Derivation documentation](https://hackage.haskell.org/package/hnix-0.12.0/docs/Nix-Effects-Derivation.html).+  * [(link)](https://github.com/haskell-nix/hnix/pull/554/commits/9bcfbbe88ff0bd8d803296193ee1d8603dc5289e) `Nix.Convert`: Principled `NVPath -> NixString` coercion.+    * In a form of principled `instance FromValue NixString m (NValue' t f m (NValue t f m))`.+  * [(link)](https://github.com/haskell-nix/hnix/pull/554/commits/a8e6d28fdb98a1c34f425c8395338fdabe96becc) `Nix.String`: Allow custom computations inside string contexts.+    * By providing `runWithStringContext{T,}'` methods into the API.+  * [(link)](https://github.com/haskell-nix/hnix/pull/554/commits/e45f7632c51a9657f6e8d54c39fd4d21c466d85f) Includded support for new `base16-bytestring`, which advertices 2x-4x speed increase of its operations.+  * [(link)](https://github.com/haskell-nix/hnix/pull/554/commits/3bba5549273c892c60aad5dd6d5058a8db40efbf) `Nix.Effects`: `addPath` & `toFile_` standalone functions got principled implementation through the internal use of the new `MonadStore` type class implementation.+  * [(link)](https://github.com/haskell-nix/hnix/pull/554/commits/3bba5549273c892c60aad5dd6d5058a8db40efbf) `Nix.Effects`: added `addTextToStore`, `parseStoreResult` implementations.+  * [(link)](https://github.com/haskell-nix/hnix/pull/554/commits/3bba5549273c892c60aad5dd6d5058a8db40efbf) `Nix.Effects`: added type synonyms `{RecursiveFlag, RepairFlag, StorePathName, FilePathFilter, StorePathSet}`.+  * [(link)](https://github.com/haskell-nix/hnix/pull/760) `Nix.Exec`: Fixed the rendering of internal `Frames`.+    * Which is an internal mechanism of a project to passing around messages with their context, still to be used internally).+  * [(link)](https://github.com/haskell-nix/hnix/pull/554/commits/3bba5549273c892c60aad5dd6d5058a8db40efbf) `HNix / Nix`: The library now also uses `hnix-store-remote`.+  * [(link)](https://github.com/haskell-nix/hnix/pull/554/commits/06b0fca9fd607eb2e995f003424e797a41ffa5b7) `cabal.project`: project uses `cryptohash-sha512` override, the `hnix-store-core` requires it from `hnix` and uses that override also. [Detailed info](https://github.com/haskell-hvr/cryptohash-sha512/pull/5#issuecomment-752796913). We promise to attend to this issue, probably by migrating to `cryptonite` in the nearest releases.++Future note: The HNix is a big project. During the initial development and currently the API for simplicity exposes allmost all functions, types, etc. Big open API means a big effort to create/maintain a quite noisy changelog and you parsing through it, and also creates a frequent requirements to mark releases as major and bother you due to some type changes in some parts that may not be used or applicable to be public API.++This year the most gracious API clean-up would happen, we would check and keep open what Hackage projects are using from the API, and the other parts would be open on the request by a way of rapid minor releases. That clean-up is also a work toward splitting the project into several packages some time in the future (split would be into something like Expressions, Evaluation, Executable, Extra), which migration also would be done most thoughful and graceful as possible, with as much easiness and automation provided for migration downstream as possible. If all goes as planned - all downstream would need to do is to get and run our script that would migrate our old map of module imports to new ones, and maybe manually add those newly formed packages into `.cabal` description.++If it is possible, please, try to switch & use the higher-level API functions where it is applicable. Thank you.+++### [(diff)](https://github.com/haskell-nix/hnix/compare/0.11.0...0.11.1#files_bucket) 0.11.1 (2020-12-09)++* Additional:+  * [(link)](https://github.com/haskell-nix/hnix/commit/d32a6fbaf3df1c8879d1b19a18f21c031a73e56c) `Nix.Builtins`: `isString` fixed - It used to return `True` for values coercible to string like derivations and paths. It only accepts string values now.+  * [(link)](https://github.com/haskell-nix/hnix/commit/53b4db2525a8f074d8c262fa7b66ce97e5820890) `Nix.Builtins`: `substring` fixed - Negative lengths used to capture an empty string. Now they capture the whole rmeainder of the string.+  * [(link)](https://github.com/haskell-nix/hnix/commit/dc31c5e64f8c7aaaea14cac0134bd47544533e67) `Nix.Effects`: `pathExists` fixed - Now also works with directories.+  * [(link)](https://github.com/haskell-nix/hnix/commit/e2ad934492eeac9881527610e4a1c1cf31ea1115) `Nix.Parser`: `->` is now properly right-associative (was non-associative).+  * [(link)](https://github.com/haskell-nix/hnix/commit/50baea5e1e482be3c4fcc13c9a45b1083243f681) `Nix.Parser`: Nix `assert` parser (`nixAssert` function) now accepts top-level Nix format also (which means also accepts all kinds of statements), before that it accepted only regular Nix expressions.+  * [(link)](https://github.com/haskell-nix/hnix/commit/59698de7185dfae508e5ccea4377a82023c4a0d5) `Nix.Render`: `renderLocation` now also shows/handles location of errors in raw strings.+++## [(diff)](https://github.com/haskell-nix/hnix/compare/0.10.1...0.11.0#files_bucket) 0.11.0 (2020-11-02)++* Breaking:+  * [(link)](https://github.com/haskell-nix/hnix/pull/740) Deleted incorrect `instance Generic1 NKeyName` from `module Nix.Expr.Types`.+  * [(link)](https://github.com/haskell-nix/hnix/pull/739) Parentheses now are properly included in the location annotation for Nix expressions, change of `nixParens` in `module Nix.Parser` essentially results in the change of all module `nix*` function results, essentially making results of the whole module more proper.++* Additional:+  * [(link)](https://github.com/haskell-nix/hnix/pull/741) Fix QQ Text lifting error: work around of [GHC#12596 "can't find interface-file declaration"](https://gitlab.haskell.org/ghc/ghc/-/issues/12596).+  * [(link)](https://github.com/haskell-nix/hnix/pull/744) Fix comments inclusion into location annotations, by using pre-whitespace position for source end locations.+++### [(diff)](https://github.com/haskell-nix/hnix/compare/0.10.0...0.10.1#files_bucket) 0.10.1 (2020-09-13)++* Additional:+  * [(link)](https://github.com/haskell-nix/hnix/pull/715) `{Binding, NExpr, NExprF, NKeyName}` gained `Ord1` instances.+    * These instances were required by downstream projects to be able to use newer HNix.+  * [(link)](https://github.com/haskell-nix/hnix/pull/712) CLI gained `--long-version` option for gathering a detailed debug information.+    * Currently, reports Git commit and its date.+    * [(link)](https://github.com/haskell-nix/hnix/issues/718) Currently does not work in case of use of the `nix-build`, in which case simply returns `UNKNOWN` placeholder.+++## [(diff)](https://github.com/haskell-nix/hnix/compare/0.9.1...0.10.0#files_bucket) 0.10.0 (2020-09-12)++* Breaking:+  * [(link)](https://github.com/haskell-nix/hnix/pull/699) Removed `NExpr` `{FromJSON, ToJSON}` instances.+    * This also removed the JSON output feature for unevaluated expression trees.++* Additional:+  * [(link)](https://github.com/haskell-nix/hnix/pull/703) CLI gained `--version` option.+  * Dependencies:+    * [(link)](https://github.com/haskell-nix/hnix/pull/686) Requires last major `data-fix` (`0.3`).+    * [(link)](https://github.com/haskell-nix/hnix/pull/679) Requires last major `prettyprinter` (`1.7`).+++### [(diff)](https://github.com/haskell-nix/hnix/compare/0.9.0...0.9.1#files_bucket) 0.9.1 (2020-07-13)++* Additional:+  * REPL:+    * Better tab completion.+    * Accepting multi-line input.+    * Support for passing evaluated expression result of `hnix --eval -E`.+      to REPL as an `input` variable.+    * Support for loading `.hnixrc` from the current directory.+  * Reporting of `builtins.nixVersion` bumped from 2.0 to 2.3.+  * Dependencies:+    * Freed from: `{interpolate, contravariant, semigroups, generic-random, tasty-quickcheck}`.+    * Requires last major `repline` (`0.4`).+++## [(diff)](https://github.com/haskell-nix/hnix/compare/0.8.0...0.9.0#files_bucket) 0.9.0 (2020-06-15)++* Breaking:+  * Removed instances due to migration to `haskeline 0.8`:+    * `instance MonadException m => MonadException(StateT(HashMap FilePath NExprLoc) m)`.+    * `instance MonadException m => MonadException(Fix1T StandardTF m)`.+  * Dependencies:+    * Requires last major `haskeline` (`0.8`).++* Additional:+  * Library: Official support for `GHC 8.4 - 8.10`.+  * Executable complies only under `GHC 8.10`.++* Changelog started. Previous release was `0.8.0`.+++---++HNix uses [PVP Versioning][1].++[1]: https://pvp.haskell.org
− LICENSE
@@ -1,26 +0,0 @@-Copyright (c) 2014, John Wiegley All rights reserved.--Redistribution and use in source and binary forms, with or without-modification, are permitted provided that the following conditions are met:--1. Redistributions of source code must retain the above copyright notice, this-list of conditions and the following disclaimer.--2. Redistributions in binary form must reproduce the above copyright notice,-this list of conditions and the following disclaimer in the documentation-and/or other materials provided with the distribution.--3. Neither the name of the copyright holder nor the names of its contributors-may be used to endorse or promote products derived from this software without-specific prior written permission.--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ License view
@@ -0,0 +1,26 @@+Copyright (c) 2014, John Wiegley All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++1. Redistributions of source code must retain the above copyright notice, this+list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright notice,+this list of conditions and the following disclaimer in the documentation+and/or other materials provided with the distribution.++3. Neither the name of the copyright holder nor the names of its contributors+may be used to endorse or promote products derived from this software without+specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
− README.md
@@ -1,108 +0,0 @@-# hnix--[![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.--## Prerequisites--Nix is installed and in your `$PATH`. This is so that `nix-store` can be used-for interacting with store paths, until `hnix-store` is ready.--## Getting Started--```bash-$ git clone --recursive https://github.com/haskell-nix/hnix.git-...-$ cd hnix-$ nix-shell-$ cabal configure --enable-tests-$ cabal build-$ cabal test-# To run all of the tests, which takes up to a minute:-$ 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-```--## Building a Docker container--If you don't have Nix installed, or you'd just like to play around with `hnix`-completely separately from your main system, you can build a Docker container:--```bash-$ docker build -t hnix .-$ docker run hnix hnix --eval --expr '1 + 2'--# In order to refer to files under the current directory:-$ docker run -v $PWD/:/tmp/build run hnix hnix default.nix-```--## Building with full debug info--To build `hnix` for debugging, and with full tracing output and stack traces,-use:--```-$ nix-shell-$ cabal configure --enable-tests --enable-profiling --flags=profiling --flags=tracing-$ cabal build-$ ./dist/build/hnix/hnix -v5 --trace <args> +RTS -xc-```--Note that this will run quite slowly, but will give the most information as to-what might potentially be going wrong during parsing or evaluation.--## Building with benchmarks enabled--To build `hnix` with benchmarks enabled:--```-$ nix-shell --arg doBenchmarks true-$ cabal configure --enable-tests --enable-benchmarks-$ cabal build-$ cabal bench-```--## Building with profiling enabled--To build `hnix` with profiling enabled:--```-$ 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-[here](https://github.com/haskell-nix/hnix/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22+no%3Aassignee).-When you find an issue that looks interesting to you, comment on the ticket to-let others know you're working on it; look for others who might have done the-same. You can talk with everyone live on-[Gitter](https://gitter.im/haskell-nix/Lobby).--When you're ready to submit a pull request, test it with:-```-git submodule update --init --recursive-nix-shell --run "LANGUAGE_TESTS=yes cabal test"-```--Make sure that all the tests that were passing prior to your PR are still-passing afterwards; it's OK if no new tests are passing.
+ ReadMe.md view
@@ -0,0 +1,330 @@+[![Chatroom Gitter](https://img.shields.io/badge/Chatroom-Gitter-%23753a88)](https://gitter.im/haskell-nix/Lobby)+[![Hackage](https://img.shields.io/hackage/v/hnix?color=%235e5086&label=Latest%20release%20on%20Hackage)](https://hackage.haskell.org/package/hnix)+[![Hackage Matrix Builder](https://img.shields.io/badge/Hackage%20Matrix-Builder-%235e5086)](https://matrix.hackage.haskell.org/package/hnix)+[![Bounds](https://img.shields.io/hackage-deps/v/hnix?label=Released%20dep%20bounds)](https://packdeps.haskellers.com/feed?needle=hnix)+[![Hydra CI](https://img.shields.io/badge/Nixpkgs%20Hydra-CI-%234f72bb)](https://hydra.nixos.org/job/nixpkgs/trunk/haskellPackages.hnix.x86_64-linux#tabs-status)+[![Repology page](https://img.shields.io/badge/Repology-page-%23005500)](https://repology.org/project/haskell:hnix/versions)+++# HNix++Parser, evaluator and type checker for the Nix language written in Haskell.+++## Prerequisites+Tooling is WIP, `nix-shell` and `nix-store` are still used for their purpose, so, to access them Nix is required to be installed.++*Disclaimer*: Since still using Nix for some operations, current `derivationStrict` primOp implementation and so evaluations of a derivation into a store path currently rely on the `hnix-store-remote`, which for those operations relies on the running `nix-daemon`, and so operations use/produce effects into the `/nix/store`. Be cautious - it is effectful (produces `/nix/store` entries).++## Building the project++### Git clone++```shell+git clone --recursive 'https://github.com/haskell-nix/hnix.git' && cd hnix+```+++### (optional) Cachix prebuild binary caches++If you would use our Nix-shell environment for development, you can connect to our Cachix HNix build caches:++1. Run:+    ```shell+    nix-env -iA cachix -f https://cachix.org/api/v1/install+    ```+++2. Run: `cachix use hnix`+++### Building with Cabal++Cabal [Quickstart](https://cabal.readthedocs.io/en/3.4/nix-local-build.html).++1. (Optional), to enter the projects reproducible Nix environment:+    ```shell+    nix-shell+    ```+    +2. Building:+    ```shell+    cabal v2-configure+    cabal v2-build+    ```+  +3. Loading the project into `ghci` REPL:+    ```shell+    cabal v2-repl+    ```+    +4. Testing:++  * Default suite:+    ```shell+    cabal v2-test+    ```+  +  * All available tests:+    ```shell+    env ALL_TESTS=yes cabal v2-test+    ```+    +  * Selected (list of tests is in `tests/Main.hs`):+    ```shell+    env NIXPKGS_TESTS=yes PRETTY_TESTS=1 cabal v2-test+    ```++#### Checking the project++##### Benchmarks++To run benchmarks:++```shell+cabal v2-bench+```++##### Profiling++GHC User Manual has a full ["Profiling"](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/profiling.html) section of relevant info.++To build `hnix` with profiling enabled:++```shell+cabal v2-run hnix --enable-profiling --flags=profiling -- <args> +RTS -p+```++Or to put simply:+```shell+# Run profiling for evaluation of a Firefox package.+# Generate:+#  * for all functions+#  * time profiling data+#  * memory allocation profiling data+#  * in the JSON profiling format+cabal v2-run --enable-profiling --flags=profiling --enable-library-profiling --profiling-detail='all-functions' hnix -- --eval --expr '(import <nixpkgs> {}).firefox.outPath' +RTS -Pj++# Then, upload the `hnix.prof` to the https://www.speedscope.app/ to analyze it.+```++"RTS" stands for "RunTime System" and has a lot of options, GHC User Manual has ["Running a compiled program"/"Setting RTS options"](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/runtime_control.html) sections describing them.++##### Full debug info++To run stack traces & full tracing output on `hnix`:++```shell+cabal v2-configure --enable-tests --enable-profiling --flags=profiling --flags=tracing+cabal v2-run hnix -- -v5 --trace <args> +RTS -xc+```++This would give the most information as to what happens during parsing & evaluation.+++#### Runing executable++```shell+cabal v2-run hnix -- --help+```+(`--` is for separation between `cabal` & `hnix` args)+++### Building with Nix-build++There is a number of build options to use with `nix-build`, documentation of them is in: `./default.nix`, keys essentially pass-through the [Nixpkgs Haskell Lib API](https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/haskell-modules/lib.nix).++Options can be used as:+```shell+nix-build \+  --arg <option1> <argument1> \+  --arg <option2> <argument2> \+  --argstr <option3> "<strinTypeArg>"+```++#### Checking the project+##### Benchmarks++```shell+nix-build \+  --arg disableOptimization false \+  --arg enableDeadCodeElimination true \+  --arg doStrip true \+  --arg doBenchmark true+```++##### Profiling++```shell+nix-build \+  --arg disableOptimization false \+  --arg enableDeadCodeElimination true \+  --arg enableLibraryProfiling true \+  --arg enableExecutableProfiling true++./result/bin/hnix <args> +RTS -p+```++##### Full debug info++```shell+nix-build \+  --arg disableOptimization false \+  --arg enableDeadCodeElimination true \+  --arg doBenchmark true \+  --arg doStrip false \+  --arg enableLibraryProfiling true \+  --arg enableExecutableProfiling true \+  --arg doTracing true \+  --arg enableDWARFDebugging true++./result/bin/hnix -v5 --trace <args> +RTS -xc+```++#### Runing executable++```shell+./result/bin/hnix+```++## Using HNix++See:+```+hnix --help+```++It has a pretty full/good description of the current options.+++### Parse & print++To parse a file with `hnix` and pretty print the result:++```shell+hnix file.nix+```++### Evaluating and printing the resulting value++Expression from a file:++```shell+hnix --eval file.nix+```++Expression:++```shell+hnix --eval --expr 'import <nixpkgs> {}'+```++### Evaluating Nixpkgs++Currently, the main high-level goal is to be able to evaluate all of Nixpkgs:++```shell+hnix --eval --expr "import <nixpkgs> {}" --find+```++### Options supported only by HNix++To see value provenance and thunk context:++```shell+hnix -v2 --values --thunk --eval --expr 'import <nixpkgs> {}'+```++To see tracing as the evaluator runs (note that building with `cabal configure --flags=tracing` will produce much more output than this):++```shell+hnix --trace --eval --expr 'import <nixpkgs> {}'+```++To attempt to generate a reduced test case demonstrating an error:++```shell+hnix --reduce bug.nix --eval --expr 'import <nixpkgs> {}'+```++### REPL++To enter REPL:+```shell+hnix --repl+```++Evaluate an expression and load it into REPL:+```shell+hnix --eval --expr '(import <nixpkgs> {}).pkgs.hello' --repl+```+This binds the evaluated expression result to the `input` variable, so that variable can be inspected.++Use the `:help` command for a list of all available REPL commands.++#### Language laziness++Nix is a lazy language with the ability of recursion, so by default REPL and eval prints are lazy:++```shell+hnix \+  --eval \+  --expr '{ x = true; }'+  +{ x = "<expr>"; }+```++To disable laziness add the `--strict` to commands or `:set strict` in the REPL.++```shell+hnix \+  --eval \+  --strict \+  --expr '{ x = true; }'+  +{ x = true; }+```+++## Contributing++* The Haskell Language Server (HLS) works great with our project.++* [Design of the HNix code base Wiki article](https://github.com/haskell-nix/hnix/wiki/Design-of-the-HNix-code-base).++1. If something in the [quests](https://github.com/haskell-nix/hnix/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22+no%3Aassignee) looks interesting, look through the thread and leave a comment taking it, to let others know you're working on it.++2. You are free to chat with everyone on [Gitter](https://gitter.im/haskell-nix/Lobby).++3. When the pull request is ready to be submitted, to save time - please, test it with:+    +    ```shell+    cabal v2-test+    +    # If forgot to clone recursively, run:+    # git submodule update --init --recursive+    ```+    +    Please, check that all default tests that were passing prior are still passing. It's OK if no new tests are passing.+    +    +### (optional) Minimalistic development status loop with amazing [`ghcid`](https://github.com/ndmitchell/ghcid)++If HLS is not your cup of yea:++```shell+ghcid --command="cabal v2-repl --repl-options=-fno-code --repl-options=-fno-break-on-exception --repl-options=-fno-break-on-error --repl-options=-v1 --repl-options=-ferror-spans --repl-options=-j"+```+(optional) To use projects reproducible environment, wrap `ghcid ...` command into a `nix-shell --command ' '`.++For simplicity `alias` the command in your shell.+++## Current status++To understand the project implementation state see:+  * [ChangeLog](https://github.com/haskell-nix/hnix/blob/master/ChangeLog.md)+  * [Opened reports](https://github.com/haskell-nix/hnix/issues)+  * [Project status](https://github.com/haskell-nix/hnix/wiki/Project-status)+  * [Design of the HNix code base](https://github.com/haskell-nix/hnix/wiki/Design-of-the-HNix-code-base)+
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
benchmarks/Main.hs view
@@ -1,10 +1,9 @@ module Main where -import Criterion.Main+import           Nix.Prelude+import           Criterion.Main  import qualified ParserBench  main :: IO ()-main = defaultMain-  [ ParserBench.benchmarks-  ]+main = defaultMain $ one ParserBench.benchmarks
benchmarks/ParserBench.hs view
@@ -1,20 +1,22 @@ module ParserBench (benchmarks) where -import Nix.Parser+import           Nix.Prelude+import           Nix.Parser -import Control.Applicative-import Criterion+import           Criterion -benchFile :: FilePath -> Benchmark-benchFile = bench <*> whnfIO . parseNixFile . ("data/" ++)+benchFile :: Path -> Benchmark+benchFile = bench . coerce <*> whnfIO . parseNixFile . ("data/" <>)  benchmarks :: Benchmark-benchmarks = bgroup "Parser"-  [ benchFile "nixpkgs-all-packages.nix"-  , benchFile "nixpkgs-all-packages-pretty.nix"-  , benchFile "let-comments.nix"-  , benchFile "let-comments-multiline.nix"-  , benchFile "let.nix"-  , benchFile "simple.nix"-  , benchFile "simple-pretty.nix"-  ]+benchmarks = bgroup+  "Parser" $+    fmap benchFile+      [ "nixpkgs-all-packages.nix"+      , "nixpkgs-all-packages-pretty.nix"+      , "let-comments.nix"+      , "let-comments-multiline.nix"+      , "let.nix"+      , "simple.nix"+      , "simple-pretty.nix"+      ]
− data/nix/COPYING
@@ -1,504 +0,0 @@-		  GNU LESSER GENERAL PUBLIC LICENSE-		       Version 2.1, February 1999-- Copyright (C) 1991, 1999 Free Software Foundation, Inc.- 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA- Everyone is permitted to copy and distribute verbatim copies- of this license document, but changing it is not allowed.--[This is the first released version of the Lesser GPL.  It also counts- as the successor of the GNU Library Public License, version 2, hence- the version number 2.1.]--			    Preamble--  The licenses for most software are designed to take away your-freedom to share and change it.  By contrast, the GNU General Public-Licenses are intended to guarantee your freedom to share and change-free software--to make sure the software is free for all its users.--  This license, the Lesser General Public License, applies to some-specially designated software packages--typically libraries--of the-Free Software Foundation and other authors who decide to use it.  You-can use it too, but we suggest you first think carefully about whether-this license or the ordinary General Public License is the better-strategy to use in any particular case, based on the explanations below.--  When we speak of free software, we are referring to freedom of use,-not price.  Our General Public Licenses are designed to make sure that-you have the freedom to distribute copies of free software (and charge-for this service if you wish); that you receive source code or can get-it if you want it; that you can change the software and use pieces of-it in new free programs; and that you are informed that you can do-these things.--  To protect your rights, we need to make restrictions that forbid-distributors to deny you these rights or to ask you to surrender these-rights.  These restrictions translate to certain responsibilities for-you if you distribute copies of the library or if you modify it.--  For example, if you distribute copies of the library, whether gratis-or for a fee, you must give the recipients all the rights that we gave-you.  You must make sure that they, too, receive or can get the source-code.  If you link other code with the library, you must provide-complete object files to the recipients, so that they can relink them-with the library after making changes to the library and recompiling-it.  And you must show them these terms so they know their rights.--  We protect your rights with a two-step method: (1) we copyright the-library, and (2) we offer you this license, which gives you legal-permission to copy, distribute and/or modify the library.--  To protect each distributor, we want to make it very clear that-there is no warranty for the free library.  Also, if the library is-modified by someone else and passed on, the recipients should know-that what they have is not the original version, so that the original-author's reputation will not be affected by problems that might be-introduced by others.--  Finally, software patents pose a constant threat to the existence of-any free program.  We wish to make sure that a company cannot-effectively restrict the users of a free program by obtaining a-restrictive license from a patent holder.  Therefore, we insist that-any patent license obtained for a version of the library must be-consistent with the full freedom of use specified in this license.--  Most GNU software, including some libraries, is covered by the-ordinary GNU General Public License.  This license, the GNU Lesser-General Public License, applies to certain designated libraries, and-is quite different from the ordinary General Public License.  We use-this license for certain libraries in order to permit linking those-libraries into non-free programs.--  When a program is linked with a library, whether statically or using-a shared library, the combination of the two is legally speaking a-combined work, a derivative of the original library.  The ordinary-General Public License therefore permits such linking only if the-entire combination fits its criteria of freedom.  The Lesser General-Public License permits more lax criteria for linking other code with-the library.--  We call this license the "Lesser" General Public License because it-does Less to protect the user's freedom than the ordinary General-Public License.  It also provides other free software developers Less-of an advantage over competing non-free programs.  These disadvantages-are the reason we use the ordinary General Public License for many-libraries.  However, the Lesser license provides advantages in certain-special circumstances.--  For example, on rare occasions, there may be a special need to-encourage the widest possible use of a certain library, so that it becomes-a de-facto standard.  To achieve this, non-free programs must be-allowed to use the library.  A more frequent case is that a free-library does the same job as widely used non-free libraries.  In this-case, there is little to gain by limiting the free library to free-software only, so we use the Lesser General Public License.--  In other cases, permission to use a particular library in non-free-programs enables a greater number of people to use a large body of-free software.  For example, permission to use the GNU C Library in-non-free programs enables many more people to use the whole GNU-operating system, as well as its variant, the GNU/Linux operating-system.--  Although the Lesser General Public License is Less protective of the-users' freedom, it does ensure that the user of a program that is-linked with the Library has the freedom and the wherewithal to run-that program using a modified version of the Library.--  The precise terms and conditions for copying, distribution and-modification follow.  Pay close attention to the difference between a-"work based on the library" and a "work that uses the library".  The-former contains code derived from the library, whereas the latter must-be combined with the library in order to run.--		  GNU LESSER GENERAL PUBLIC LICENSE-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION--  0. This License Agreement applies to any software library or other-program which contains a notice placed by the copyright holder or-other authorized party saying it may be distributed under the terms of-this Lesser General Public License (also called "this License").-Each licensee is addressed as "you".--  A "library" means a collection of software functions and/or data-prepared so as to be conveniently linked with application programs-(which use some of those functions and data) to form executables.--  The "Library", below, refers to any such software library or work-which has been distributed under these terms.  A "work based on the-Library" means either the Library or any derivative work under-copyright law: that is to say, a work containing the Library or a-portion of it, either verbatim or with modifications and/or translated-straightforwardly into another language.  (Hereinafter, translation is-included without limitation in the term "modification".)--  "Source code" for a work means the preferred form of the work for-making modifications to it.  For a library, complete source code means-all the source code for all modules it contains, plus any associated-interface definition files, plus the scripts used to control compilation-and installation of the library.--  Activities other than copying, distribution and modification are not-covered by this License; they are outside its scope.  The act of-running a program using the Library is not restricted, and output from-such a program is covered only if its contents constitute a work based-on the Library (independent of the use of the Library in a tool for-writing it).  Whether that is true depends on what the Library does-and what the program that uses the Library does.-  -  1. You may copy and distribute verbatim copies of the Library's-complete source code as you receive it, in any medium, provided that-you conspicuously and appropriately publish on each copy an-appropriate copyright notice and disclaimer of warranty; keep intact-all the notices that refer to this License and to the absence of any-warranty; and distribute a copy of this License along with the-Library.--  You may charge a fee for the physical act of transferring a copy,-and you may at your option offer warranty protection in exchange for a-fee.--  2. You may modify your copy or copies of the Library or any portion-of it, thus forming a work based on the Library, and copy and-distribute such modifications or work under the terms of Section 1-above, provided that you also meet all of these conditions:--    a) The modified work must itself be a software library.--    b) You must cause the files modified to carry prominent notices-    stating that you changed the files and the date of any change.--    c) You must cause the whole of the work to be licensed at no-    charge to all third parties under the terms of this License.--    d) If a facility in the modified Library refers to a function or a-    table of data to be supplied by an application program that uses-    the facility, other than as an argument passed when the facility-    is invoked, then you must make a good faith effort to ensure that,-    in the event an application does not supply such function or-    table, the facility still operates, and performs whatever part of-    its purpose remains meaningful.--    (For example, a function in a library to compute square roots has-    a purpose that is entirely well-defined independent of the-    application.  Therefore, Subsection 2d requires that any-    application-supplied function or table used by this function must-    be optional: if the application does not supply it, the square-    root function must still compute square roots.)--These requirements apply to the modified work as a whole.  If-identifiable sections of that work are not derived from the Library,-and can be reasonably considered independent and separate works in-themselves, then this License, and its terms, do not apply to those-sections when you distribute them as separate works.  But when you-distribute the same sections as part of a whole which is a work based-on the Library, the distribution of the whole must be on the terms of-this License, whose permissions for other licensees extend to the-entire whole, and thus to each and every part regardless of who wrote-it.--Thus, it is not the intent of this section to claim rights or contest-your rights to work written entirely by you; rather, the intent is to-exercise the right to control the distribution of derivative or-collective works based on the Library.--In addition, mere aggregation of another work not based on the Library-with the Library (or with a work based on the Library) on a volume of-a storage or distribution medium does not bring the other work under-the scope of this License.--  3. You may opt to apply the terms of the ordinary GNU General Public-License instead of this License to a given copy of the Library.  To do-this, you must alter all the notices that refer to this License, so-that they refer to the ordinary GNU General Public License, version 2,-instead of to this License.  (If a newer version than version 2 of the-ordinary GNU General Public License has appeared, then you can specify-that version instead if you wish.)  Do not make any other change in-these notices.--  Once this change is made in a given copy, it is irreversible for-that copy, so the ordinary GNU General Public License applies to all-subsequent copies and derivative works made from that copy.--  This option is useful when you wish to copy part of the code of-the Library into a program that is not a library.--  4. You may copy and distribute the Library (or a portion or-derivative of it, under Section 2) in object code or executable form-under the terms of Sections 1 and 2 above provided that you accompany-it with the complete corresponding machine-readable source code, which-must be distributed under the terms of Sections 1 and 2 above on a-medium customarily used for software interchange.--  If distribution of object code is made by offering access to copy-from a designated place, then offering equivalent access to copy the-source code from the same place satisfies the requirement to-distribute the source code, even though third parties are not-compelled to copy the source along with the object code.--  5. A program that contains no derivative of any portion of the-Library, but is designed to work with the Library by being compiled or-linked with it, is called a "work that uses the Library".  Such a-work, in isolation, is not a derivative work of the Library, and-therefore falls outside the scope of this License.--  However, linking a "work that uses the Library" with the Library-creates an executable that is a derivative of the Library (because it-contains portions of the Library), rather than a "work that uses the-library".  The executable is therefore covered by this License.-Section 6 states terms for distribution of such executables.--  When a "work that uses the Library" uses material from a header file-that is part of the Library, the object code for the work may be a-derivative work of the Library even though the source code is not.-Whether this is true is especially significant if the work can be-linked without the Library, or if the work is itself a library.  The-threshold for this to be true is not precisely defined by law.--  If such an object file uses only numerical parameters, data-structure layouts and accessors, and small macros and small inline-functions (ten lines or less in length), then the use of the object-file is unrestricted, regardless of whether it is legally a derivative-work.  (Executables containing this object code plus portions of the-Library will still fall under Section 6.)--  Otherwise, if the work is a derivative of the Library, you may-distribute the object code for the work under the terms of Section 6.-Any executables containing that work also fall under Section 6,-whether or not they are linked directly with the Library itself.--  6. As an exception to the Sections above, you may also combine or-link a "work that uses the Library" with the Library to produce a-work containing portions of the Library, and distribute that work-under terms of your choice, provided that the terms permit-modification of the work for the customer's own use and reverse-engineering for debugging such modifications.--  You must give prominent notice with each copy of the work that the-Library is used in it and that the Library and its use are covered by-this License.  You must supply a copy of this License.  If the work-during execution displays copyright notices, you must include the-copyright notice for the Library among them, as well as a reference-directing the user to the copy of this License.  Also, you must do one-of these things:--    a) Accompany the work with the complete corresponding-    machine-readable source code for the Library including whatever-    changes were used in the work (which must be distributed under-    Sections 1 and 2 above); and, if the work is an executable linked-    with the Library, with the complete machine-readable "work that-    uses the Library", as object code and/or source code, so that the-    user can modify the Library and then relink to produce a modified-    executable containing the modified Library.  (It is understood-    that the user who changes the contents of definitions files in the-    Library will not necessarily be able to recompile the application-    to use the modified definitions.)--    b) Use a suitable shared library mechanism for linking with the-    Library.  A suitable mechanism is one that (1) uses at run time a-    copy of the library already present on the user's computer system,-    rather than copying library functions into the executable, and (2)-    will operate properly with a modified version of the library, if-    the user installs one, as long as the modified version is-    interface-compatible with the version that the work was made with.--    c) Accompany the work with a written offer, valid for at-    least three years, to give the same user the materials-    specified in Subsection 6a, above, for a charge no more-    than the cost of performing this distribution.--    d) If distribution of the work is made by offering access to copy-    from a designated place, offer equivalent access to copy the above-    specified materials from the same place.--    e) Verify that the user has already received a copy of these-    materials or that you have already sent this user a copy.--  For an executable, the required form of the "work that uses the-Library" must include any data and utility programs needed for-reproducing the executable from it.  However, as a special exception,-the materials to be distributed need not include anything that is-normally distributed (in either source or binary form) with the major-components (compiler, kernel, and so on) of the operating system on-which the executable runs, unless that component itself accompanies-the executable.--  It may happen that this requirement contradicts the license-restrictions of other proprietary libraries that do not normally-accompany the operating system.  Such a contradiction means you cannot-use both them and the Library together in an executable that you-distribute.--  7. You may place library facilities that are a work based on the-Library side-by-side in a single library together with other library-facilities not covered by this License, and distribute such a combined-library, provided that the separate distribution of the work based on-the Library and of the other library facilities is otherwise-permitted, and provided that you do these two things:--    a) Accompany the combined library with a copy of the same work-    based on the Library, uncombined with any other library-    facilities.  This must be distributed under the terms of the-    Sections above.--    b) Give prominent notice with the combined library of the fact-    that part of it is a work based on the Library, and explaining-    where to find the accompanying uncombined form of the same work.--  8. You may not copy, modify, sublicense, link with, or distribute-the Library except as expressly provided under this License.  Any-attempt otherwise to copy, modify, sublicense, link with, or-distribute the Library is void, and will automatically terminate your-rights under this License.  However, parties who have received copies,-or rights, from you under this License will not have their licenses-terminated so long as such parties remain in full compliance.--  9. You are not required to accept this License, since you have not-signed it.  However, nothing else grants you permission to modify or-distribute the Library or its derivative works.  These actions are-prohibited by law if you do not accept this License.  Therefore, by-modifying or distributing the Library (or any work based on the-Library), you indicate your acceptance of this License to do so, and-all its terms and conditions for copying, distributing or modifying-the Library or works based on it.--  10. Each time you redistribute the Library (or any work based on the-Library), the recipient automatically receives a license from the-original licensor to copy, distribute, link with or modify the Library-subject to these terms and conditions.  You may not impose any further-restrictions on the recipients' exercise of the rights granted herein.-You are not responsible for enforcing compliance by third parties with-this License.--  11. If, as a consequence of a court judgment or allegation of patent-infringement or for any other reason (not limited to patent issues),-conditions are imposed on you (whether by court order, agreement or-otherwise) that contradict the conditions of this License, they do not-excuse you from the conditions of this License.  If you cannot-distribute so as to satisfy simultaneously your obligations under this-License and any other pertinent obligations, then as a consequence you-may not distribute the Library at all.  For example, if a patent-license would not permit royalty-free redistribution of the Library by-all those who receive copies directly or indirectly through you, then-the only way you could satisfy both it and this License would be to-refrain entirely from distribution of the Library.--If any portion of this section is held invalid or unenforceable under any-particular circumstance, the balance of the section is intended to apply,-and the section as a whole is intended to apply in other circumstances.--It is not the purpose of this section to induce you to infringe any-patents or other property right claims or to contest validity of any-such claims; this section has the sole purpose of protecting the-integrity of the free software distribution system which is-implemented by public license practices.  Many people have made-generous contributions to the wide range of software distributed-through that system in reliance on consistent application of that-system; it is up to the author/donor to decide if he or she is willing-to distribute software through any other system and a licensee cannot-impose that choice.--This section is intended to make thoroughly clear what is believed to-be a consequence of the rest of this License.--  12. If the distribution and/or use of the Library is restricted in-certain countries either by patents or by copyrighted interfaces, the-original copyright holder who places the Library under this License may add-an explicit geographical distribution limitation excluding those countries,-so that distribution is permitted only in or among countries not thus-excluded.  In such case, this License incorporates the limitation as if-written in the body of this License.--  13. The Free Software Foundation may publish revised and/or new-versions of the Lesser General Public License from time to time.-Such new versions will be similar in spirit to the present version,-but may differ in detail to address new problems or concerns.--Each version is given a distinguishing version number.  If the Library-specifies a version number of this License which applies to it and-"any later version", you have the option of following the terms and-conditions either of that version or of any later version published by-the Free Software Foundation.  If the Library does not specify a-license version number, you may choose any version ever published by-the Free Software Foundation.--  14. If you wish to incorporate parts of the Library into other free-programs whose distribution conditions are incompatible with these,-write to the author to ask for permission.  For software which is-copyrighted by the Free Software Foundation, write to the Free-Software Foundation; we sometimes make exceptions for this.  Our-decision will be guided by the two goals of preserving the free status-of all derivatives of our free software and of promoting the sharing-and reuse of software generally.--			    NO WARRANTY--  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE-LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.--  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH-DAMAGES.--		     END OF TERMS AND CONDITIONS--           How to Apply These Terms to Your New Libraries--  If you develop a new library, and you want it to be of the greatest-possible use to the public, we recommend making it free software that-everyone can redistribute and change.  You can do so by permitting-redistribution under these terms (or, alternatively, under the terms of the-ordinary General Public License).--  To apply these terms, attach the following notices to the library.  It is-safest to attach them to the start of each source file to most effectively-convey the exclusion of warranty; and each file should have at least the-"copyright" line and a pointer to where the full notice is found.--    <one line to give the library's name and a brief idea of what it does.>-    Copyright (C) <year>  <name of author>--    This library is free software; you can redistribute it and/or-    modify it under the terms of the GNU Lesser General Public-    License as published by the Free Software Foundation; either-    version 2.1 of the License, or (at your option) any later version.--    This library is distributed in the hope that it will be useful,-    but WITHOUT ANY WARRANTY; without even the implied warranty of-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU-    Lesser General Public License for more details.--    You should have received a copy of the GNU Lesser General Public-    License along with this library; if not, write to the Free Software-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA--Also add information on how to contact you by electronic and paper mail.--You should also get your employer (if you work as a programmer) or your-school, if any, to sign a "copyright disclaimer" for the library, if-necessary.  Here is a sample; alter the names:--  Yoyodyne, Inc., hereby disclaims all copyright interest in the-  library `Frob' (a library for tweaking knobs) written by James Random Hacker.--  <signature of Ty Coon>, 1 April 1990-  Ty Coon, President of Vice--That's all there is to it!--
− data/nix/Makefile
@@ -1,39 +0,0 @@-makefiles = \-  local.mk \-  src/libutil/local.mk \-  src/libstore/local.mk \-  src/libmain/local.mk \-  src/libexpr/local.mk \-  src/nix/local.mk \-  src/nix-store/local.mk \-  src/nix-instantiate/local.mk \-  src/nix-env/local.mk \-  src/nix-daemon/local.mk \-  src/nix-collect-garbage/local.mk \-  src/nix-copy-closure/local.mk \-  src/nix-prefetch-url/local.mk \-  src/resolve-system-dependencies/local.mk \-  src/nix-channel/local.mk \-  src/nix-build/local.mk \-  src/build-remote/local.mk \-  scripts/local.mk \-  corepkgs/local.mk \-  misc/systemd/local.mk \-  misc/launchd/local.mk \-  misc/upstart/local.mk \-  doc/manual/local.mk \-  tests/local.mk \-  tests/plugins/local.mk--GLOBAL_CXXFLAGS += -g -Wall -include config.h---include Makefile.config--OPTIMIZE = 1--ifeq ($(OPTIMIZE), 1)-  GLOBAL_CFLAGS += -O3-  GLOBAL_CXXFLAGS += -O3-endif--include mk/lib.mk
− data/nix/Makefile.config.in
@@ -1,39 +0,0 @@-BDW_GC_LIBS = @BDW_GC_LIBS@-CC = @CC@-CFLAGS = @CFLAGS@-CXX = @CXX@-CXXFLAGS = @CXXFLAGS@-ENABLE_S3 = @ENABLE_S3@-HAVE_SODIUM = @HAVE_SODIUM@-HAVE_READLINE = @HAVE_READLINE@-HAVE_BROTLI = @HAVE_BROTLI@-HAVE_SECCOMP = @HAVE_SECCOMP@-LIBCURL_LIBS = @LIBCURL_LIBS@-OPENSSL_LIBS = @OPENSSL_LIBS@-PACKAGE_NAME = @PACKAGE_NAME@-PACKAGE_VERSION = @PACKAGE_VERSION@-SODIUM_LIBS = @SODIUM_LIBS@-LIBLZMA_LIBS = @LIBLZMA_LIBS@-SQLITE3_LIBS = @SQLITE3_LIBS@-LIBBROTLI_LIBS = @LIBBROTLI_LIBS@-bash = @bash@-bindir = @bindir@-brotli = @brotli@-lsof = @lsof@-datadir = @datadir@-datarootdir = @datarootdir@-docdir = @docdir@-exec_prefix = @exec_prefix@-includedir = @includedir@-libdir = @libdir@-libexecdir = @libexecdir@-localstatedir = @localstatedir@-mandir = @mandir@-pkglibdir = $(libdir)/$(PACKAGE_NAME)-prefix = @prefix@-sandbox_shell = @sandbox_shell@-storedir = @storedir@-sysconfdir = @sysconfdir@-doc_generate = @doc_generate@-xmllint = @xmllint@-xsltproc = @xsltproc@
− data/nix/README.md
@@ -1,22 +0,0 @@-Nix, the purely functional package manager---------------------------------------------Nix is a new take on package management that is fairly unique. Because of its-purity aspects, a lot of issues found in traditional package managers don't-appear with Nix.--To find out more about the tool, usage and installation instructions, please-read the manual, which is available on the Nix website at-<http://nixos.org/nix/manual>.--## Contributing--Take a look at the [Hacking Section](http://nixos.org/nix/manual/#chap-hacking)-of the manual. It helps you to get started with building Nix from source.--## License--Nix is released under the LGPL v2.1--This product includes software developed by the OpenSSL Project for-use in the [OpenSSL Toolkit](http://www.OpenSSL.org/).
− data/nix/bootstrap.sh
@@ -1,4 +0,0 @@-#! /bin/sh -e-rm -f aclocal.m4-mkdir -p config-exec autoreconf -vfi
− data/nix/config/config.guess
@@ -1,1537 +0,0 @@-#! /bin/sh-# Attempt to guess a canonical system name.-#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,-#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,-#   2011, 2012 Free Software Foundation, Inc.--timestamp='2012-08-14'--# This file is free software; you can redistribute it and/or modify it-# under the terms of the GNU General Public License as published by-# the Free Software Foundation; either version 2 of the License, or-# (at your option) any later version.-#-# This program is distributed in the hope that it will be useful, but-# WITHOUT ANY WARRANTY; without even the implied warranty of-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU-# General Public License for more details.-#-# You should have received a copy of the GNU General Public License-# along with this program; if not, see <http://www.gnu.org/licenses/>.-#-# As a special exception to the GNU General Public License, if you-# distribute this file as part of a program that contains a-# configuration script generated by Autoconf, you may include it under-# the same distribution terms that you use for the rest of that program.---# Originally written by Per Bothner.  Please send patches (context-# diff format) to <config-patches@gnu.org> and include a ChangeLog-# entry.-#-# This script attempts to guess a canonical system name similar to-# config.sub.  If it succeeds, it prints the system name on stdout, and-# exits with 0.  Otherwise, it exits with 1.-#-# You can get the latest version of this script from:-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD--me=`echo "$0" | sed -e 's,.*/,,'`--usage="\-Usage: $0 [OPTION]--Output the configuration name of the system \`$me' is run on.--Operation modes:-  -h, --help         print this help, then exit-  -t, --time-stamp   print date of last modification, then exit-  -v, --version      print version number, then exit--Report bugs and patches to <config-patches@gnu.org>."--version="\-GNU config.guess ($timestamp)--Originally written by Per Bothner.-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012-Free Software Foundation, Inc.--This is free software; see the source for copying conditions.  There is NO-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."--help="-Try \`$me --help' for more information."--# Parse command line-while test $# -gt 0 ; do-  case $1 in-    --time-stamp | --time* | -t )-       echo "$timestamp" ; exit ;;-    --version | -v )-       echo "$version" ; exit ;;-    --help | --h* | -h )-       echo "$usage"; exit ;;-    -- )     # Stop option processing-       shift; break ;;-    - )	# Use stdin as input.-       break ;;-    -* )-       echo "$me: invalid option $1$help" >&2-       exit 1 ;;-    * )-       break ;;-  esac-done--if test $# != 0; then-  echo "$me: too many arguments$help" >&2-  exit 1-fi--trap 'exit 1' 1 2 15--# CC_FOR_BUILD -- compiler used by this script. Note that the use of a-# compiler to aid in system detection is discouraged as it requires-# temporary files to be created and, as you can see below, it is a-# headache to deal with in a portable fashion.--# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still-# use `HOST_CC' if defined, but it is deprecated.--# Portable tmp directory creation inspired by the Autoconf team.--set_cc_for_build='-trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;-trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;-: ${TMPDIR=/tmp} ;- { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||- { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||- { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||- { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;-dummy=$tmp/dummy ;-tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;-case $CC_FOR_BUILD,$HOST_CC,$CC in- ,,)    echo "int x;" > $dummy.c ;-	for c in cc gcc c89 c99 ; do-	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then-	     CC_FOR_BUILD="$c"; break ;-	  fi ;-	done ;-	if test x"$CC_FOR_BUILD" = x ; then-	  CC_FOR_BUILD=no_compiler_found ;-	fi-	;;- ,,*)   CC_FOR_BUILD=$CC ;;- ,*,*)  CC_FOR_BUILD=$HOST_CC ;;-esac ; set_cc_for_build= ;'--# This is needed to find uname on a Pyramid OSx when run in the BSD universe.-# (ghazi@noc.rutgers.edu 1994-08-24)-if (test -f /.attbin/uname) >/dev/null 2>&1 ; then-	PATH=$PATH:/.attbin ; export PATH-fi--UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown-UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown-UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown-UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown--# Note: order is significant - the case branches are not exclusive.--case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in-    *:NetBSD:*:*)-	# NetBSD (nbsd) targets should (where applicable) match one or-	# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,-	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently-	# switched to ELF, *-*-netbsd* would select the old-	# object file format.  This provides both forward-	# compatibility and a consistent mechanism for selecting the-	# object file format.-	#-	# Note: NetBSD doesn't particularly care about the vendor-	# portion of the name.  We always set it to "unknown".-	sysctl="sysctl -n hw.machine_arch"-	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \-	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`-	case "${UNAME_MACHINE_ARCH}" in-	    armeb) machine=armeb-unknown ;;-	    arm*) machine=arm-unknown ;;-	    sh3el) machine=shl-unknown ;;-	    sh3eb) machine=sh-unknown ;;-	    sh5el) machine=sh5le-unknown ;;-	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;-	esac-	# The Operating System including object format, if it has switched-	# to ELF recently, or will in the future.-	case "${UNAME_MACHINE_ARCH}" in-	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)-		eval $set_cc_for_build-		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \-			| grep -q __ELF__-		then-		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).-		    # Return netbsd for either.  FIX?-		    os=netbsd-		else-		    os=netbsdelf-		fi-		;;-	    *)-		os=netbsd-		;;-	esac-	# The OS release-	# Debian GNU/NetBSD machines have a different userland, and-	# thus, need a distinct triplet. However, they do not need-	# kernel version information, so it can be replaced with a-	# suitable tag, in the style of linux-gnu.-	case "${UNAME_VERSION}" in-	    Debian*)-		release='-gnu'-		;;-	    *)-		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`-		;;-	esac-	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:-	# contains redundant information, the shorter form:-	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.-	echo "${machine}-${os}${release}"-	exit ;;-    *:Bitrig:*:*)-	UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`-	echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}-	exit ;;-    *:OpenBSD:*:*)-	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`-	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}-	exit ;;-    *:ekkoBSD:*:*)-	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}-	exit ;;-    *:SolidBSD:*:*)-	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}-	exit ;;-    macppc:MirBSD:*:*)-	echo powerpc-unknown-mirbsd${UNAME_RELEASE}-	exit ;;-    *:MirBSD:*:*)-	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}-	exit ;;-    alpha:OSF1:*:*)-	case $UNAME_RELEASE in-	*4.0)-		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`-		;;-	*5.*)-		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`-		;;-	esac-	# According to Compaq, /usr/sbin/psrinfo has been available on-	# OSF/1 and Tru64 systems produced since 1995.  I hope that-	# covers most systems running today.  This code pipes the CPU-	# types through head -n 1, so we only detect the type of CPU 0.-	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`-	case "$ALPHA_CPU_TYPE" in-	    "EV4 (21064)")-		UNAME_MACHINE="alpha" ;;-	    "EV4.5 (21064)")-		UNAME_MACHINE="alpha" ;;-	    "LCA4 (21066/21068)")-		UNAME_MACHINE="alpha" ;;-	    "EV5 (21164)")-		UNAME_MACHINE="alphaev5" ;;-	    "EV5.6 (21164A)")-		UNAME_MACHINE="alphaev56" ;;-	    "EV5.6 (21164PC)")-		UNAME_MACHINE="alphapca56" ;;-	    "EV5.7 (21164PC)")-		UNAME_MACHINE="alphapca57" ;;-	    "EV6 (21264)")-		UNAME_MACHINE="alphaev6" ;;-	    "EV6.7 (21264A)")-		UNAME_MACHINE="alphaev67" ;;-	    "EV6.8CB (21264C)")-		UNAME_MACHINE="alphaev68" ;;-	    "EV6.8AL (21264B)")-		UNAME_MACHINE="alphaev68" ;;-	    "EV6.8CX (21264D)")-		UNAME_MACHINE="alphaev68" ;;-	    "EV6.9A (21264/EV69A)")-		UNAME_MACHINE="alphaev69" ;;-	    "EV7 (21364)")-		UNAME_MACHINE="alphaev7" ;;-	    "EV7.9 (21364A)")-		UNAME_MACHINE="alphaev79" ;;-	esac-	# A Pn.n version is a patched version.-	# A Vn.n version is a released version.-	# A Tn.n version is a released field test version.-	# A Xn.n version is an unreleased experimental baselevel.-	# 1.2 uses "1.2" for uname -r.-	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`-	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.-	exitcode=$?-	trap '' 0-	exit $exitcode ;;-    Alpha\ *:Windows_NT*:*)-	# How do we know it's Interix rather than the generic POSIX subsystem?-	# Should we change UNAME_MACHINE based on the output of uname instead-	# of the specific Alpha model?-	echo alpha-pc-interix-	exit ;;-    21064:Windows_NT:50:3)-	echo alpha-dec-winnt3.5-	exit ;;-    Amiga*:UNIX_System_V:4.0:*)-	echo m68k-unknown-sysv4-	exit ;;-    *:[Aa]miga[Oo][Ss]:*:*)-	echo ${UNAME_MACHINE}-unknown-amigaos-	exit ;;-    *:[Mm]orph[Oo][Ss]:*:*)-	echo ${UNAME_MACHINE}-unknown-morphos-	exit ;;-    *:OS/390:*:*)-	echo i370-ibm-openedition-	exit ;;-    *:z/VM:*:*)-	echo s390-ibm-zvmoe-	exit ;;-    *:OS400:*:*)-	echo powerpc-ibm-os400-	exit ;;-    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)-	echo arm-acorn-riscix${UNAME_RELEASE}-	exit ;;-    arm:riscos:*:*|arm:RISCOS:*:*)-	echo arm-unknown-riscos-	exit ;;-    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)-	echo hppa1.1-hitachi-hiuxmpp-	exit ;;-    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)-	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.-	if test "`(/bin/universe) 2>/dev/null`" = att ; then-		echo pyramid-pyramid-sysv3-	else-		echo pyramid-pyramid-bsd-	fi-	exit ;;-    NILE*:*:*:dcosx)-	echo pyramid-pyramid-svr4-	exit ;;-    DRS?6000:unix:4.0:6*)-	echo sparc-icl-nx6-	exit ;;-    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)-	case `/usr/bin/uname -p` in-	    sparc) echo sparc-icl-nx7; exit ;;-	esac ;;-    s390x:SunOS:*:*)-	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`-	exit ;;-    sun4H:SunOS:5.*:*)-	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`-	exit ;;-    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)-	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`-	exit ;;-    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)-	echo i386-pc-auroraux${UNAME_RELEASE}-	exit ;;-    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)-	eval $set_cc_for_build-	SUN_ARCH="i386"-	# If there is a compiler, see if it is configured for 64-bit objects.-	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.-	# This test works for both compilers.-	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then-	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \-		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \-		grep IS_64BIT_ARCH >/dev/null-	    then-		SUN_ARCH="x86_64"-	    fi-	fi-	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`-	exit ;;-    sun4*:SunOS:6*:*)-	# According to config.sub, this is the proper way to canonicalize-	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but-	# it's likely to be more like Solaris than SunOS4.-	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`-	exit ;;-    sun4*:SunOS:*:*)-	case "`/usr/bin/arch -k`" in-	    Series*|S4*)-		UNAME_RELEASE=`uname -v`-		;;-	esac-	# Japanese Language versions have a version number like `4.1.3-JL'.-	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`-	exit ;;-    sun3*:SunOS:*:*)-	echo m68k-sun-sunos${UNAME_RELEASE}-	exit ;;-    sun*:*:4.2BSD:*)-	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`-	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3-	case "`/bin/arch`" in-	    sun3)-		echo m68k-sun-sunos${UNAME_RELEASE}-		;;-	    sun4)-		echo sparc-sun-sunos${UNAME_RELEASE}-		;;-	esac-	exit ;;-    aushp:SunOS:*:*)-	echo sparc-auspex-sunos${UNAME_RELEASE}-	exit ;;-    # The situation for MiNT is a little confusing.  The machine name-    # can be virtually everything (everything which is not-    # "atarist" or "atariste" at least should have a processor-    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"-    # to the lowercase version "mint" (or "freemint").  Finally-    # the system name "TOS" denotes a system which is actually not-    # MiNT.  But MiNT is downward compatible to TOS, so this should-    # be no problem.-    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)-	echo m68k-atari-mint${UNAME_RELEASE}-	exit ;;-    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)-	echo m68k-atari-mint${UNAME_RELEASE}-	exit ;;-    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)-	echo m68k-atari-mint${UNAME_RELEASE}-	exit ;;-    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)-	echo m68k-milan-mint${UNAME_RELEASE}-	exit ;;-    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)-	echo m68k-hades-mint${UNAME_RELEASE}-	exit ;;-    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)-	echo m68k-unknown-mint${UNAME_RELEASE}-	exit ;;-    m68k:machten:*:*)-	echo m68k-apple-machten${UNAME_RELEASE}-	exit ;;-    powerpc:machten:*:*)-	echo powerpc-apple-machten${UNAME_RELEASE}-	exit ;;-    RISC*:Mach:*:*)-	echo mips-dec-mach_bsd4.3-	exit ;;-    RISC*:ULTRIX:*:*)-	echo mips-dec-ultrix${UNAME_RELEASE}-	exit ;;-    VAX*:ULTRIX*:*:*)-	echo vax-dec-ultrix${UNAME_RELEASE}-	exit ;;-    2020:CLIX:*:* | 2430:CLIX:*:*)-	echo clipper-intergraph-clix${UNAME_RELEASE}-	exit ;;-    mips:*:*:UMIPS | mips:*:*:RISCos)-	eval $set_cc_for_build-	sed 's/^	//' << EOF >$dummy.c-#ifdef __cplusplus-#include <stdio.h>  /* for printf() prototype */-	int main (int argc, char *argv[]) {-#else-	int main (argc, argv) int argc; char *argv[]; {-#endif-	#if defined (host_mips) && defined (MIPSEB)-	#if defined (SYSTYPE_SYSV)-	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);-	#endif-	#if defined (SYSTYPE_SVR4)-	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);-	#endif-	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)-	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);-	#endif-	#endif-	  exit (-1);-	}-EOF-	$CC_FOR_BUILD -o $dummy $dummy.c &&-	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&-	  SYSTEM_NAME=`$dummy $dummyarg` &&-	    { echo "$SYSTEM_NAME"; exit; }-	echo mips-mips-riscos${UNAME_RELEASE}-	exit ;;-    Motorola:PowerMAX_OS:*:*)-	echo powerpc-motorola-powermax-	exit ;;-    Motorola:*:4.3:PL8-*)-	echo powerpc-harris-powermax-	exit ;;-    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)-	echo powerpc-harris-powermax-	exit ;;-    Night_Hawk:Power_UNIX:*:*)-	echo powerpc-harris-powerunix-	exit ;;-    m88k:CX/UX:7*:*)-	echo m88k-harris-cxux7-	exit ;;-    m88k:*:4*:R4*)-	echo m88k-motorola-sysv4-	exit ;;-    m88k:*:3*:R3*)-	echo m88k-motorola-sysv3-	exit ;;-    AViiON:dgux:*:*)-	# DG/UX returns AViiON for all architectures-	UNAME_PROCESSOR=`/usr/bin/uname -p`-	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]-	then-	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \-	       [ ${TARGET_BINARY_INTERFACE}x = x ]-	    then-		echo m88k-dg-dgux${UNAME_RELEASE}-	    else-		echo m88k-dg-dguxbcs${UNAME_RELEASE}-	    fi-	else-	    echo i586-dg-dgux${UNAME_RELEASE}-	fi-	exit ;;-    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)-	echo m88k-dolphin-sysv3-	exit ;;-    M88*:*:R3*:*)-	# Delta 88k system running SVR3-	echo m88k-motorola-sysv3-	exit ;;-    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)-	echo m88k-tektronix-sysv3-	exit ;;-    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)-	echo m68k-tektronix-bsd-	exit ;;-    *:IRIX*:*:*)-	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`-	exit ;;-    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.-	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id-	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '-    i*86:AIX:*:*)-	echo i386-ibm-aix-	exit ;;-    ia64:AIX:*:*)-	if [ -x /usr/bin/oslevel ] ; then-		IBM_REV=`/usr/bin/oslevel`-	else-		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}-	fi-	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}-	exit ;;-    *:AIX:2:3)-	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then-		eval $set_cc_for_build-		sed 's/^		//' << EOF >$dummy.c-		#include <sys/systemcfg.h>--		main()-			{-			if (!__power_pc())-				exit(1);-			puts("powerpc-ibm-aix3.2.5");-			exit(0);-			}-EOF-		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`-		then-			echo "$SYSTEM_NAME"-		else-			echo rs6000-ibm-aix3.2.5-		fi-	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then-		echo rs6000-ibm-aix3.2.4-	else-		echo rs6000-ibm-aix3.2-	fi-	exit ;;-    *:AIX:*:[4567])-	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`-	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then-		IBM_ARCH=rs6000-	else-		IBM_ARCH=powerpc-	fi-	if [ -x /usr/bin/oslevel ] ; then-		IBM_REV=`/usr/bin/oslevel`-	else-		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}-	fi-	echo ${IBM_ARCH}-ibm-aix${IBM_REV}-	exit ;;-    *:AIX:*:*)-	echo rs6000-ibm-aix-	exit ;;-    ibmrt:4.4BSD:*|romp-ibm:BSD:*)-	echo romp-ibm-bsd4.4-	exit ;;-    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and-	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to-	exit ;;                             # report: romp-ibm BSD 4.3-    *:BOSX:*:*)-	echo rs6000-bull-bosx-	exit ;;-    DPX/2?00:B.O.S.:*:*)-	echo m68k-bull-sysv3-	exit ;;-    9000/[34]??:4.3bsd:1.*:*)-	echo m68k-hp-bsd-	exit ;;-    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)-	echo m68k-hp-bsd4.4-	exit ;;-    9000/[34678]??:HP-UX:*:*)-	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`-	case "${UNAME_MACHINE}" in-	    9000/31? )            HP_ARCH=m68000 ;;-	    9000/[34]?? )         HP_ARCH=m68k ;;-	    9000/[678][0-9][0-9])-		if [ -x /usr/bin/getconf ]; then-		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`-		    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`-		    case "${sc_cpu_version}" in-		      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0-		      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1-		      532)                      # CPU_PA_RISC2_0-			case "${sc_kernel_bits}" in-			  32) HP_ARCH="hppa2.0n" ;;-			  64) HP_ARCH="hppa2.0w" ;;-			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20-			esac ;;-		    esac-		fi-		if [ "${HP_ARCH}" = "" ]; then-		    eval $set_cc_for_build-		    sed 's/^		//' << EOF >$dummy.c--		#define _HPUX_SOURCE-		#include <stdlib.h>-		#include <unistd.h>--		int main ()-		{-		#if defined(_SC_KERNEL_BITS)-		    long bits = sysconf(_SC_KERNEL_BITS);-		#endif-		    long cpu  = sysconf (_SC_CPU_VERSION);--		    switch (cpu)-			{-			case CPU_PA_RISC1_0: puts ("hppa1.0"); break;-			case CPU_PA_RISC1_1: puts ("hppa1.1"); break;-			case CPU_PA_RISC2_0:-		#if defined(_SC_KERNEL_BITS)-			    switch (bits)-				{-				case 64: puts ("hppa2.0w"); break;-				case 32: puts ("hppa2.0n"); break;-				default: puts ("hppa2.0"); break;-				} break;-		#else  /* !defined(_SC_KERNEL_BITS) */-			    puts ("hppa2.0"); break;-		#endif-			default: puts ("hppa1.0"); break;-			}-		    exit (0);-		}-EOF-		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`-		    test -z "$HP_ARCH" && HP_ARCH=hppa-		fi ;;-	esac-	if [ ${HP_ARCH} = "hppa2.0w" ]-	then-	    eval $set_cc_for_build--	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating-	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler-	    # generating 64-bit code.  GNU and HP use different nomenclature:-	    #-	    # $ CC_FOR_BUILD=cc ./config.guess-	    # => hppa2.0w-hp-hpux11.23-	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess-	    # => hppa64-hp-hpux11.23--	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |-		grep -q __LP64__-	    then-		HP_ARCH="hppa2.0w"-	    else-		HP_ARCH="hppa64"-	    fi-	fi-	echo ${HP_ARCH}-hp-hpux${HPUX_REV}-	exit ;;-    ia64:HP-UX:*:*)-	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`-	echo ia64-hp-hpux${HPUX_REV}-	exit ;;-    3050*:HI-UX:*:*)-	eval $set_cc_for_build-	sed 's/^	//' << EOF >$dummy.c-	#include <unistd.h>-	int-	main ()-	{-	  long cpu = sysconf (_SC_CPU_VERSION);-	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns-	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct-	     results, however.  */-	  if (CPU_IS_PA_RISC (cpu))-	    {-	      switch (cpu)-		{-		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;-		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;-		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;-		  default: puts ("hppa-hitachi-hiuxwe2"); break;-		}-	    }-	  else if (CPU_IS_HP_MC68K (cpu))-	    puts ("m68k-hitachi-hiuxwe2");-	  else puts ("unknown-hitachi-hiuxwe2");-	  exit (0);-	}-EOF-	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&-		{ echo "$SYSTEM_NAME"; exit; }-	echo unknown-hitachi-hiuxwe2-	exit ;;-    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )-	echo hppa1.1-hp-bsd-	exit ;;-    9000/8??:4.3bsd:*:*)-	echo hppa1.0-hp-bsd-	exit ;;-    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)-	echo hppa1.0-hp-mpeix-	exit ;;-    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )-	echo hppa1.1-hp-osf-	exit ;;-    hp8??:OSF1:*:*)-	echo hppa1.0-hp-osf-	exit ;;-    i*86:OSF1:*:*)-	if [ -x /usr/sbin/sysversion ] ; then-	    echo ${UNAME_MACHINE}-unknown-osf1mk-	else-	    echo ${UNAME_MACHINE}-unknown-osf1-	fi-	exit ;;-    parisc*:Lites*:*:*)-	echo hppa1.1-hp-lites-	exit ;;-    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)-	echo c1-convex-bsd-	exit ;;-    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)-	if getsysinfo -f scalar_acc-	then echo c32-convex-bsd-	else echo c2-convex-bsd-	fi-	exit ;;-    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)-	echo c34-convex-bsd-	exit ;;-    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)-	echo c38-convex-bsd-	exit ;;-    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)-	echo c4-convex-bsd-	exit ;;-    CRAY*Y-MP:*:*:*)-	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'-	exit ;;-    CRAY*[A-Z]90:*:*:*)-	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \-	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \-	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \-	      -e 's/\.[^.]*$/.X/'-	exit ;;-    CRAY*TS:*:*:*)-	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'-	exit ;;-    CRAY*T3E:*:*:*)-	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'-	exit ;;-    CRAY*SV1:*:*:*)-	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'-	exit ;;-    *:UNICOS/mp:*:*)-	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'-	exit ;;-    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)-	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`-	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`-	FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`-	echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"-	exit ;;-    5000:UNIX_System_V:4.*:*)-	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`-	FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`-	echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"-	exit ;;-    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)-	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}-	exit ;;-    sparc*:BSD/OS:*:*)-	echo sparc-unknown-bsdi${UNAME_RELEASE}-	exit ;;-    *:BSD/OS:*:*)-	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}-	exit ;;-    *:FreeBSD:*:*)-	UNAME_PROCESSOR=`/usr/bin/uname -p`-	case ${UNAME_PROCESSOR} in-	    amd64)-		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;-	    *)-		echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;-	esac-	exit ;;-    i*:CYGWIN*:*)-	echo ${UNAME_MACHINE}-pc-cygwin-	exit ;;-    *:MINGW64*:*)-	echo ${UNAME_MACHINE}-pc-mingw64-	exit ;;-    *:MINGW*:*)-	echo ${UNAME_MACHINE}-pc-mingw32-	exit ;;-    i*:MSYS*:*)-	echo ${UNAME_MACHINE}-pc-msys-	exit ;;-    i*:windows32*:*)-	# uname -m includes "-pc" on this system.-	echo ${UNAME_MACHINE}-mingw32-	exit ;;-    i*:PW*:*)-	echo ${UNAME_MACHINE}-pc-pw32-	exit ;;-    *:Interix*:*)-	case ${UNAME_MACHINE} in-	    x86)-		echo i586-pc-interix${UNAME_RELEASE}-		exit ;;-	    authenticamd | genuineintel | EM64T)-		echo x86_64-unknown-interix${UNAME_RELEASE}-		exit ;;-	    IA64)-		echo ia64-unknown-interix${UNAME_RELEASE}-		exit ;;-	esac ;;-    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)-	echo i${UNAME_MACHINE}-pc-mks-	exit ;;-    8664:Windows_NT:*)-	echo x86_64-pc-mks-	exit ;;-    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)-	# How do we know it's Interix rather than the generic POSIX subsystem?-	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we-	# UNAME_MACHINE based on the output of uname instead of i386?-	echo i586-pc-interix-	exit ;;-    i*:UWIN*:*)-	echo ${UNAME_MACHINE}-pc-uwin-	exit ;;-    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)-	echo x86_64-unknown-cygwin-	exit ;;-    p*:CYGWIN*:*)-	echo powerpcle-unknown-cygwin-	exit ;;-    prep*:SunOS:5.*:*)-	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`-	exit ;;-    *:GNU:*:*)-	# the GNU system-	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`-	exit ;;-    *:GNU/*:*:*)-	# other systems with GNU libc and userland-	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu-	exit ;;-    i*86:Minix:*:*)-	echo ${UNAME_MACHINE}-pc-minix-	exit ;;-    aarch64:Linux:*:*)-	echo ${UNAME_MACHINE}-unknown-linux-gnu-	exit ;;-    aarch64_be:Linux:*:*)-	UNAME_MACHINE=aarch64_be-	echo ${UNAME_MACHINE}-unknown-linux-gnu-	exit ;;-    alpha:Linux:*:*)-	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in-	  EV5)   UNAME_MACHINE=alphaev5 ;;-	  EV56)  UNAME_MACHINE=alphaev56 ;;-	  PCA56) UNAME_MACHINE=alphapca56 ;;-	  PCA57) UNAME_MACHINE=alphapca56 ;;-	  EV6)   UNAME_MACHINE=alphaev6 ;;-	  EV67)  UNAME_MACHINE=alphaev67 ;;-	  EV68*) UNAME_MACHINE=alphaev68 ;;-	esac-	objdump --private-headers /bin/sh | grep -q ld.so.1-	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi-	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}-	exit ;;-    arm*:Linux:*:*)-	eval $set_cc_for_build-	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \-	    | grep -q __ARM_EABI__-	then-	    echo ${UNAME_MACHINE}-unknown-linux-gnu-	else-	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \-		| grep -q __ARM_PCS_VFP-	    then-		echo ${UNAME_MACHINE}-unknown-linux-gnueabi-	    else-		echo ${UNAME_MACHINE}-unknown-linux-gnueabihf-	    fi-	fi-	exit ;;-    avr32*:Linux:*:*)-	echo ${UNAME_MACHINE}-unknown-linux-gnu-	exit ;;-    cris:Linux:*:*)-	echo ${UNAME_MACHINE}-axis-linux-gnu-	exit ;;-    crisv32:Linux:*:*)-	echo ${UNAME_MACHINE}-axis-linux-gnu-	exit ;;-    frv:Linux:*:*)-	echo ${UNAME_MACHINE}-unknown-linux-gnu-	exit ;;-    hexagon:Linux:*:*)-	echo ${UNAME_MACHINE}-unknown-linux-gnu-	exit ;;-    i*86:Linux:*:*)-	LIBC=gnu-	eval $set_cc_for_build-	sed 's/^	//' << EOF >$dummy.c-	#ifdef __dietlibc__-	LIBC=dietlibc-	#endif-EOF-	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`-	echo "${UNAME_MACHINE}-pc-linux-${LIBC}"-	exit ;;-    ia64:Linux:*:*)-	echo ${UNAME_MACHINE}-unknown-linux-gnu-	exit ;;-    m32r*:Linux:*:*)-	echo ${UNAME_MACHINE}-unknown-linux-gnu-	exit ;;-    m68*:Linux:*:*)-	echo ${UNAME_MACHINE}-unknown-linux-gnu-	exit ;;-    mips:Linux:*:* | mips64:Linux:*:*)-	eval $set_cc_for_build-	sed 's/^	//' << EOF >$dummy.c-	#undef CPU-	#undef ${UNAME_MACHINE}-	#undef ${UNAME_MACHINE}el-	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)-	CPU=${UNAME_MACHINE}el-	#else-	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)-	CPU=${UNAME_MACHINE}-	#else-	CPU=-	#endif-	#endif-EOF-	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`-	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }-	;;-    or32:Linux:*:*)-	echo ${UNAME_MACHINE}-unknown-linux-gnu-	exit ;;-    padre:Linux:*:*)-	echo sparc-unknown-linux-gnu-	exit ;;-    parisc64:Linux:*:* | hppa64:Linux:*:*)-	echo hppa64-unknown-linux-gnu-	exit ;;-    parisc:Linux:*:* | hppa:Linux:*:*)-	# Look for CPU level-	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in-	  PA7*) echo hppa1.1-unknown-linux-gnu ;;-	  PA8*) echo hppa2.0-unknown-linux-gnu ;;-	  *)    echo hppa-unknown-linux-gnu ;;-	esac-	exit ;;-    ppc64:Linux:*:*)-	echo powerpc64-unknown-linux-gnu-	exit ;;-    ppc:Linux:*:*)-	echo powerpc-unknown-linux-gnu-	exit ;;-    s390:Linux:*:* | s390x:Linux:*:*)-	echo ${UNAME_MACHINE}-ibm-linux-	exit ;;-    sh64*:Linux:*:*)-	echo ${UNAME_MACHINE}-unknown-linux-gnu-	exit ;;-    sh*:Linux:*:*)-	echo ${UNAME_MACHINE}-unknown-linux-gnu-	exit ;;-    sparc:Linux:*:* | sparc64:Linux:*:*)-	echo ${UNAME_MACHINE}-unknown-linux-gnu-	exit ;;-    tile*:Linux:*:*)-	echo ${UNAME_MACHINE}-unknown-linux-gnu-	exit ;;-    vax:Linux:*:*)-	echo ${UNAME_MACHINE}-dec-linux-gnu-	exit ;;-    x86_64:Linux:*:*)-	echo ${UNAME_MACHINE}-unknown-linux-gnu-	exit ;;-    xtensa*:Linux:*:*)-	echo ${UNAME_MACHINE}-unknown-linux-gnu-	exit ;;-    i*86:DYNIX/ptx:4*:*)-	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.-	# earlier versions are messed up and put the nodename in both-	# sysname and nodename.-	echo i386-sequent-sysv4-	exit ;;-    i*86:UNIX_SV:4.2MP:2.*)-	# Unixware is an offshoot of SVR4, but it has its own version-	# number series starting with 2...-	# I am not positive that other SVR4 systems won't match this,-	# I just have to hope.  -- rms.-	# Use sysv4.2uw... so that sysv4* matches it.-	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}-	exit ;;-    i*86:OS/2:*:*)-	# If we were able to find `uname', then EMX Unix compatibility-	# is probably installed.-	echo ${UNAME_MACHINE}-pc-os2-emx-	exit ;;-    i*86:XTS-300:*:STOP)-	echo ${UNAME_MACHINE}-unknown-stop-	exit ;;-    i*86:atheos:*:*)-	echo ${UNAME_MACHINE}-unknown-atheos-	exit ;;-    i*86:syllable:*:*)-	echo ${UNAME_MACHINE}-pc-syllable-	exit ;;-    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)-	echo i386-unknown-lynxos${UNAME_RELEASE}-	exit ;;-    i*86:*DOS:*:*)-	echo ${UNAME_MACHINE}-pc-msdosdjgpp-	exit ;;-    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)-	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`-	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then-		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}-	else-		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}-	fi-	exit ;;-    i*86:*:5:[678]*)-	# UnixWare 7.x, OpenUNIX and OpenServer 6.-	case `/bin/uname -X | grep "^Machine"` in-	    *486*)	     UNAME_MACHINE=i486 ;;-	    *Pentium)	     UNAME_MACHINE=i586 ;;-	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;-	esac-	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}-	exit ;;-    i*86:*:3.2:*)-	if test -f /usr/options/cb.name; then-		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`-		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL-	elif /bin/uname -X 2>/dev/null >/dev/null ; then-		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`-		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486-		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \-			&& UNAME_MACHINE=i586-		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \-			&& UNAME_MACHINE=i686-		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \-			&& UNAME_MACHINE=i686-		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL-	else-		echo ${UNAME_MACHINE}-pc-sysv32-	fi-	exit ;;-    pc:*:*:*)-	# Left here for compatibility:-	# uname -m prints for DJGPP always 'pc', but it prints nothing about-	# the processor, so we play safe by assuming i586.-	# Note: whatever this is, it MUST be the same as what config.sub-	# prints for the "djgpp" host, or else GDB configury will decide that-	# this is a cross-build.-	echo i586-pc-msdosdjgpp-	exit ;;-    Intel:Mach:3*:*)-	echo i386-pc-mach3-	exit ;;-    paragon:*:*:*)-	echo i860-intel-osf1-	exit ;;-    i860:*:4.*:*) # i860-SVR4-	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then-	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4-	else # Add other i860-SVR4 vendors below as they are discovered.-	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4-	fi-	exit ;;-    mini*:CTIX:SYS*5:*)-	# "miniframe"-	echo m68010-convergent-sysv-	exit ;;-    mc68k:UNIX:SYSTEM5:3.51m)-	echo m68k-convergent-sysv-	exit ;;-    M680?0:D-NIX:5.3:*)-	echo m68k-diab-dnix-	exit ;;-    M68*:*:R3V[5678]*:*)-	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;-    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)-	OS_REL=''-	test -r /etc/.relid \-	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`-	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \-	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }-	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \-	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;-    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)-	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \-	  && { echo i486-ncr-sysv4; exit; } ;;-    NCR*:*:4.2:* | MPRAS*:*:4.2:*)-	OS_REL='.3'-	test -r /etc/.relid \-	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`-	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \-	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }-	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \-	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }-	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \-	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;-    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)-	echo m68k-unknown-lynxos${UNAME_RELEASE}-	exit ;;-    mc68030:UNIX_System_V:4.*:*)-	echo m68k-atari-sysv4-	exit ;;-    TSUNAMI:LynxOS:2.*:*)-	echo sparc-unknown-lynxos${UNAME_RELEASE}-	exit ;;-    rs6000:LynxOS:2.*:*)-	echo rs6000-unknown-lynxos${UNAME_RELEASE}-	exit ;;-    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)-	echo powerpc-unknown-lynxos${UNAME_RELEASE}-	exit ;;-    SM[BE]S:UNIX_SV:*:*)-	echo mips-dde-sysv${UNAME_RELEASE}-	exit ;;-    RM*:ReliantUNIX-*:*:*)-	echo mips-sni-sysv4-	exit ;;-    RM*:SINIX-*:*:*)-	echo mips-sni-sysv4-	exit ;;-    *:SINIX-*:*:*)-	if uname -p 2>/dev/null >/dev/null ; then-		UNAME_MACHINE=`(uname -p) 2>/dev/null`-		echo ${UNAME_MACHINE}-sni-sysv4-	else-		echo ns32k-sni-sysv-	fi-	exit ;;-    PENTIUM:*:4.0*:*)	# Unisys `ClearPath HMP IX 4000' SVR4/MP effort-			# says <Richard.M.Bartel@ccMail.Census.GOV>-	echo i586-unisys-sysv4-	exit ;;-    *:UNIX_System_V:4*:FTX*)-	# From Gerald Hewes <hewes@openmarket.com>.-	# How about differentiating between stratus architectures? -djm-	echo hppa1.1-stratus-sysv4-	exit ;;-    *:*:*:FTX*)-	# From seanf@swdc.stratus.com.-	echo i860-stratus-sysv4-	exit ;;-    i*86:VOS:*:*)-	# From Paul.Green@stratus.com.-	echo ${UNAME_MACHINE}-stratus-vos-	exit ;;-    *:VOS:*:*)-	# From Paul.Green@stratus.com.-	echo hppa1.1-stratus-vos-	exit ;;-    mc68*:A/UX:*:*)-	echo m68k-apple-aux${UNAME_RELEASE}-	exit ;;-    news*:NEWS-OS:6*:*)-	echo mips-sony-newsos6-	exit ;;-    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)-	if [ -d /usr/nec ]; then-		echo mips-nec-sysv${UNAME_RELEASE}-	else-		echo mips-unknown-sysv${UNAME_RELEASE}-	fi-	exit ;;-    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.-	echo powerpc-be-beos-	exit ;;-    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.-	echo powerpc-apple-beos-	exit ;;-    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.-	echo i586-pc-beos-	exit ;;-    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.-	echo i586-pc-haiku-	exit ;;-    x86_64:Haiku:*:*)-	echo x86_64-unknown-haiku-	exit ;;-    SX-4:SUPER-UX:*:*)-	echo sx4-nec-superux${UNAME_RELEASE}-	exit ;;-    SX-5:SUPER-UX:*:*)-	echo sx5-nec-superux${UNAME_RELEASE}-	exit ;;-    SX-6:SUPER-UX:*:*)-	echo sx6-nec-superux${UNAME_RELEASE}-	exit ;;-    SX-7:SUPER-UX:*:*)-	echo sx7-nec-superux${UNAME_RELEASE}-	exit ;;-    SX-8:SUPER-UX:*:*)-	echo sx8-nec-superux${UNAME_RELEASE}-	exit ;;-    SX-8R:SUPER-UX:*:*)-	echo sx8r-nec-superux${UNAME_RELEASE}-	exit ;;-    Power*:Rhapsody:*:*)-	echo powerpc-apple-rhapsody${UNAME_RELEASE}-	exit ;;-    *:Rhapsody:*:*)-	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}-	exit ;;-    *:Darwin:*:*)-	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown-	case $UNAME_PROCESSOR in-	    i386)-		eval $set_cc_for_build-		if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then-		  if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \-		      (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \-		      grep IS_64BIT_ARCH >/dev/null-		  then-		      UNAME_PROCESSOR="x86_64"-		  fi-		fi ;;-	    unknown) UNAME_PROCESSOR=powerpc ;;-	esac-	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}-	exit ;;-    *:procnto*:*:* | *:QNX:[0123456789]*:*)-	UNAME_PROCESSOR=`uname -p`-	if test "$UNAME_PROCESSOR" = "x86"; then-		UNAME_PROCESSOR=i386-		UNAME_MACHINE=pc-	fi-	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}-	exit ;;-    *:QNX:*:4*)-	echo i386-pc-qnx-	exit ;;-    NEO-?:NONSTOP_KERNEL:*:*)-	echo neo-tandem-nsk${UNAME_RELEASE}-	exit ;;-    NSE-*:NONSTOP_KERNEL:*:*)-	echo nse-tandem-nsk${UNAME_RELEASE}-	exit ;;-    NSR-?:NONSTOP_KERNEL:*:*)-	echo nsr-tandem-nsk${UNAME_RELEASE}-	exit ;;-    *:NonStop-UX:*:*)-	echo mips-compaq-nonstopux-	exit ;;-    BS2000:POSIX*:*:*)-	echo bs2000-siemens-sysv-	exit ;;-    DS/*:UNIX_System_V:*:*)-	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}-	exit ;;-    *:Plan9:*:*)-	# "uname -m" is not consistent, so use $cputype instead. 386-	# is converted to i386 for consistency with other x86-	# operating systems.-	if test "$cputype" = "386"; then-	    UNAME_MACHINE=i386-	else-	    UNAME_MACHINE="$cputype"-	fi-	echo ${UNAME_MACHINE}-unknown-plan9-	exit ;;-    *:TOPS-10:*:*)-	echo pdp10-unknown-tops10-	exit ;;-    *:TENEX:*:*)-	echo pdp10-unknown-tenex-	exit ;;-    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)-	echo pdp10-dec-tops20-	exit ;;-    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)-	echo pdp10-xkl-tops20-	exit ;;-    *:TOPS-20:*:*)-	echo pdp10-unknown-tops20-	exit ;;-    *:ITS:*:*)-	echo pdp10-unknown-its-	exit ;;-    SEI:*:*:SEIUX)-	echo mips-sei-seiux${UNAME_RELEASE}-	exit ;;-    *:DragonFly:*:*)-	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-	exit ;;-    *:*VMS:*:*)-	UNAME_MACHINE=`(uname -p) 2>/dev/null`-	case "${UNAME_MACHINE}" in-	    A*) echo alpha-dec-vms ; exit ;;-	    I*) echo ia64-dec-vms ; exit ;;-	    V*) echo vax-dec-vms ; exit ;;-	esac ;;-    *:XENIX:*:SysV)-	echo i386-pc-xenix-	exit ;;-    i*86:skyos:*:*)-	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'-	exit ;;-    i*86:rdos:*:*)-	echo ${UNAME_MACHINE}-pc-rdos-	exit ;;-    i*86:AROS:*:*)-	echo ${UNAME_MACHINE}-pc-aros-	exit ;;-    x86_64:VMkernel:*:*)-	echo ${UNAME_MACHINE}-unknown-esx-	exit ;;-esac--eval $set_cc_for_build-cat >$dummy.c <<EOF-#ifdef _SEQUENT_-# include <sys/types.h>-# include <sys/utsname.h>-#endif-main ()-{-#if defined (sony)-#if defined (MIPSEB)-  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,-     I don't know....  */-  printf ("mips-sony-bsd\n"); exit (0);-#else-#include <sys/param.h>-  printf ("m68k-sony-newsos%s\n",-#ifdef NEWSOS4-	"4"-#else-	""-#endif-	); exit (0);-#endif-#endif--#if defined (__arm) && defined (__acorn) && defined (__unix)-  printf ("arm-acorn-riscix\n"); exit (0);-#endif--#if defined (hp300) && !defined (hpux)-  printf ("m68k-hp-bsd\n"); exit (0);-#endif--#if defined (NeXT)-#if !defined (__ARCHITECTURE__)-#define __ARCHITECTURE__ "m68k"-#endif-  int version;-  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;-  if (version < 4)-    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);-  else-    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);-  exit (0);-#endif--#if defined (MULTIMAX) || defined (n16)-#if defined (UMAXV)-  printf ("ns32k-encore-sysv\n"); exit (0);-#else-#if defined (CMU)-  printf ("ns32k-encore-mach\n"); exit (0);-#else-  printf ("ns32k-encore-bsd\n"); exit (0);-#endif-#endif-#endif--#if defined (__386BSD__)-  printf ("i386-pc-bsd\n"); exit (0);-#endif--#if defined (sequent)-#if defined (i386)-  printf ("i386-sequent-dynix\n"); exit (0);-#endif-#if defined (ns32000)-  printf ("ns32k-sequent-dynix\n"); exit (0);-#endif-#endif--#if defined (_SEQUENT_)-    struct utsname un;--    uname(&un);--    if (strncmp(un.version, "V2", 2) == 0) {-	printf ("i386-sequent-ptx2\n"); exit (0);-    }-    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */-	printf ("i386-sequent-ptx1\n"); exit (0);-    }-    printf ("i386-sequent-ptx\n"); exit (0);--#endif--#if defined (vax)-# if !defined (ultrix)-#  include <sys/param.h>-#  if defined (BSD)-#   if BSD == 43-      printf ("vax-dec-bsd4.3\n"); exit (0);-#   else-#    if BSD == 199006-      printf ("vax-dec-bsd4.3reno\n"); exit (0);-#    else-      printf ("vax-dec-bsd\n"); exit (0);-#    endif-#   endif-#  else-    printf ("vax-dec-bsd\n"); exit (0);-#  endif-# else-    printf ("vax-dec-ultrix\n"); exit (0);-# endif-#endif--#if defined (alliant) && defined (i860)-  printf ("i860-alliant-bsd\n"); exit (0);-#endif--  exit (1);-}-EOF--$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&-	{ echo "$SYSTEM_NAME"; exit; }--# Apollos put the system type in the environment.--test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }--# Convex versions that predate uname can use getsysinfo(1)--if [ -x /usr/convex/getsysinfo ]-then-    case `getsysinfo -f cpu_type` in-    c1*)-	echo c1-convex-bsd-	exit ;;-    c2*)-	if getsysinfo -f scalar_acc-	then echo c32-convex-bsd-	else echo c2-convex-bsd-	fi-	exit ;;-    c34*)-	echo c34-convex-bsd-	exit ;;-    c38*)-	echo c38-convex-bsd-	exit ;;-    c4*)-	echo c4-convex-bsd-	exit ;;-    esac-fi--cat >&2 <<EOF-$0: unable to guess system type--This script, last modified $timestamp, has failed to recognize-the operating system you are using. It is advised that you-download the most up to date version of the config scripts from--  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD-and-  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD--If the version you run ($0) is already up to date, please-send the following data and any information you think might be-pertinent to <config-patches@gnu.org> in order to provide the needed-information to handle your system.--config.guess timestamp = $timestamp--uname -m = `(uname -m) 2>/dev/null || echo unknown`-uname -r = `(uname -r) 2>/dev/null || echo unknown`-uname -s = `(uname -s) 2>/dev/null || echo unknown`-uname -v = `(uname -v) 2>/dev/null || echo unknown`--/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`-/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`--hostinfo               = `(hostinfo) 2>/dev/null`-/bin/universe          = `(/bin/universe) 2>/dev/null`-/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`-/bin/arch              = `(/bin/arch) 2>/dev/null`-/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`--UNAME_MACHINE = ${UNAME_MACHINE}-UNAME_RELEASE = ${UNAME_RELEASE}-UNAME_SYSTEM  = ${UNAME_SYSTEM}-UNAME_VERSION = ${UNAME_VERSION}-EOF--exit 1--# Local variables:-# eval: (add-hook 'write-file-hooks 'time-stamp)-# time-stamp-start: "timestamp='"-# time-stamp-format: "%:y-%02m-%02d"-# time-stamp-end: "'"-# End:
− data/nix/config/config.sub
@@ -1,1786 +0,0 @@-#! /bin/sh-# Configuration validation subroutine script.-#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,-#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,-#   2011, 2012 Free Software Foundation, Inc.--timestamp='2012-08-18'--# This file is (in principle) common to ALL GNU software.-# The presence of a machine in this file suggests that SOME GNU software-# can handle that machine.  It does not imply ALL GNU software can.-#-# This file is free software; you can redistribute it and/or modify-# it under the terms of the GNU General Public License as published by-# the Free Software Foundation; either version 2 of the License, or-# (at your option) any later version.-#-# This program is distributed in the hope that it will be useful,-# but WITHOUT ANY WARRANTY; without even the implied warranty of-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-# GNU General Public License for more details.-#-# You should have received a copy of the GNU General Public License-# along with this program; if not, see <http://www.gnu.org/licenses/>.-#-# As a special exception to the GNU General Public License, if you-# distribute this file as part of a program that contains a-# configuration script generated by Autoconf, you may include it under-# the same distribution terms that you use for the rest of that program.---# Please send patches to <config-patches@gnu.org>.  Submit a context-# diff and a properly formatted GNU ChangeLog entry.-#-# Configuration subroutine to validate and canonicalize a configuration type.-# Supply the specified configuration type as an argument.-# If it is invalid, we print an error message on stderr and exit with code 1.-# Otherwise, we print the canonical config type on stdout and succeed.--# You can get the latest version of this script from:-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD--# This file is supposed to be the same for all GNU packages-# and recognize all the CPU types, system types and aliases-# that are meaningful with *any* GNU software.-# Each package is responsible for reporting which valid configurations-# it does not support.  The user should be able to distinguish-# a failure to support a valid configuration from a meaningless-# configuration.--# The goal of this file is to map all the various variations of a given-# machine specification into a single specification in the form:-#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM-# or in some cases, the newer four-part form:-#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM-# It is wrong to echo any other type of specification.--me=`echo "$0" | sed -e 's,.*/,,'`--usage="\-Usage: $0 [OPTION] CPU-MFR-OPSYS-       $0 [OPTION] ALIAS--Canonicalize a configuration name.--Operation modes:-  -h, --help         print this help, then exit-  -t, --time-stamp   print date of last modification, then exit-  -v, --version      print version number, then exit--Report bugs and patches to <config-patches@gnu.org>."--version="\-GNU config.sub ($timestamp)--Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012-Free Software Foundation, Inc.--This is free software; see the source for copying conditions.  There is NO-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."--help="-Try \`$me --help' for more information."--# Parse command line-while test $# -gt 0 ; do-  case $1 in-    --time-stamp | --time* | -t )-       echo "$timestamp" ; exit ;;-    --version | -v )-       echo "$version" ; exit ;;-    --help | --h* | -h )-       echo "$usage"; exit ;;-    -- )     # Stop option processing-       shift; break ;;-    - )	# Use stdin as input.-       break ;;-    -* )-       echo "$me: invalid option $1$help"-       exit 1 ;;--    *local*)-       # First pass through any local machine types.-       echo $1-       exit ;;--    * )-       break ;;-  esac-done--case $# in- 0) echo "$me: missing argument$help" >&2-    exit 1;;- 1) ;;- *) echo "$me: too many arguments$help" >&2-    exit 1;;-esac--# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).-# Here we must recognize all the valid KERNEL-OS combinations.-maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`-case $maybe_os in-  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \-  linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \-  knetbsd*-gnu* | netbsd*-gnu* | \-  kopensolaris*-gnu* | \-  storm-chaos* | os2-emx* | rtmk-nova*)-    os=-$maybe_os-    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-    ;;-  android-linux)-    os=-linux-android-    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown-    ;;-  *)-    basic_machine=`echo $1 | sed 's/-[^-]*$//'`-    if [ $basic_machine != $1 ]-    then os=`echo $1 | sed 's/.*-/-/'`-    else os=; fi-    ;;-esac--### Let's recognize common machines as not being operating systems so-### that things like config.sub decstation-3100 work.  We also-### recognize some manufacturers as not being operating systems, so we-### can provide default operating systems below.-case $os in-	-sun*os*)-		# Prevent following clause from handling this invalid input.-		;;-	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \-	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \-	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \-	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\-	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \-	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \-	-apple | -axis | -knuth | -cray | -microblaze)-		os=-		basic_machine=$1-		;;-	-bluegene*)-		os=-cnk-		;;-	-sim | -cisco | -oki | -wec | -winbond)-		os=-		basic_machine=$1-		;;-	-scout)-		;;-	-wrs)-		os=-vxworks-		basic_machine=$1-		;;-	-chorusos*)-		os=-chorusos-		basic_machine=$1-		;;-	-chorusrdb)-		os=-chorusrdb-		basic_machine=$1-		;;-	-hiux*)-		os=-hiuxwe2-		;;-	-sco6)-		os=-sco5v6-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`-		;;-	-sco5)-		os=-sco3.2v5-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`-		;;-	-sco4)-		os=-sco3.2v4-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`-		;;-	-sco3.2.[4-9]*)-		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`-		;;-	-sco3.2v[4-9]*)-		# Don't forget version if it is 3.2v4 or newer.-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`-		;;-	-sco5v6*)-		# Don't forget version if it is 3.2v4 or newer.-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`-		;;-	-sco*)-		os=-sco3.2v2-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`-		;;-	-udk*)-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`-		;;-	-isc)-		os=-isc2.2-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`-		;;-	-clix*)-		basic_machine=clipper-intergraph-		;;-	-isc*)-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`-		;;-	-lynx*178)-		os=-lynxos178-		;;-	-lynx*5)-		os=-lynxos5-		;;-	-lynx*)-		os=-lynxos-		;;-	-ptx*)-		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`-		;;-	-windowsnt*)-		os=`echo $os | sed -e 's/windowsnt/winnt/'`-		;;-	-psos*)-		os=-psos-		;;-	-mint | -mint[0-9]*)-		basic_machine=m68k-atari-		os=-mint-		;;-esac--# Decode aliases for certain CPU-COMPANY combinations.-case $basic_machine in-	# Recognize the basic CPU types without company name.-	# Some are omitted here because they have special meanings below.-	1750a | 580 \-	| a29k \-	| aarch64 | aarch64_be \-	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \-	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \-	| am33_2.0 \-	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \-        | be32 | be64 \-	| bfin \-	| c4x | clipper \-	| d10v | d30v | dlx | dsp16xx \-	| epiphany \-	| fido | fr30 | frv \-	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \-	| hexagon \-	| i370 | i860 | i960 | ia64 \-	| ip2k | iq2000 \-	| le32 | le64 \-	| lm32 \-	| m32c | m32r | m32rle | m68000 | m68k | m88k \-	| maxq | mb | microblaze | mcore | mep | metag \-	| mips | mipsbe | mipseb | mipsel | mipsle \-	| mips16 \-	| mips64 | mips64el \-	| mips64octeon | mips64octeonel \-	| mips64orion | mips64orionel \-	| mips64r5900 | mips64r5900el \-	| mips64vr | mips64vrel \-	| mips64vr4100 | mips64vr4100el \-	| mips64vr4300 | mips64vr4300el \-	| mips64vr5000 | mips64vr5000el \-	| mips64vr5900 | mips64vr5900el \-	| mipsisa32 | mipsisa32el \-	| mipsisa32r2 | mipsisa32r2el \-	| mipsisa64 | mipsisa64el \-	| mipsisa64r2 | mipsisa64r2el \-	| mipsisa64sb1 | mipsisa64sb1el \-	| mipsisa64sr71k | mipsisa64sr71kel \-	| mipstx39 | mipstx39el \-	| mn10200 | mn10300 \-	| moxie \-	| mt \-	| msp430 \-	| nds32 | nds32le | nds32be \-	| nios | nios2 \-	| ns16k | ns32k \-	| open8 \-	| or32 \-	| pdp10 | pdp11 | pj | pjl \-	| powerpc | powerpc64 | powerpc64le | powerpcle \-	| pyramid \-	| rl78 | rx \-	| score \-	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \-	| sh64 | sh64le \-	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \-	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \-	| spu \-	| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \-	| ubicom32 \-	| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \-	| we32k \-	| x86 | xc16x | xstormy16 | xtensa \-	| z8k | z80)-		basic_machine=$basic_machine-unknown-		;;-	c54x)-		basic_machine=tic54x-unknown-		;;-	c55x)-		basic_machine=tic55x-unknown-		;;-	c6x)-		basic_machine=tic6x-unknown-		;;-	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)-		basic_machine=$basic_machine-unknown-		os=-none-		;;-	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)-		;;-	ms1)-		basic_machine=mt-unknown-		;;--	strongarm | thumb | xscale)-		basic_machine=arm-unknown-		;;-	xgate)-		basic_machine=$basic_machine-unknown-		os=-none-		;;-	xscaleeb)-		basic_machine=armeb-unknown-		;;--	xscaleel)-		basic_machine=armel-unknown-		;;--	# We use `pc' rather than `unknown'-	# because (1) that's what they normally are, and-	# (2) the word "unknown" tends to confuse beginning users.-	i*86 | x86_64)-	  basic_machine=$basic_machine-pc-	  ;;-	# Object if more than one company name word.-	*-*-*)-		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2-		exit 1-		;;-	# Recognize the basic CPU types with company name.-	580-* \-	| a29k-* \-	| aarch64-* | aarch64_be-* \-	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \-	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \-	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \-	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \-	| avr-* | avr32-* \-	| be32-* | be64-* \-	| bfin-* | bs2000-* \-	| c[123]* | c30-* | [cjt]90-* | c4x-* \-	| clipper-* | craynv-* | cydra-* \-	| d10v-* | d30v-* | dlx-* \-	| elxsi-* \-	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \-	| h8300-* | h8500-* \-	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \-	| hexagon-* \-	| i*86-* | i860-* | i960-* | ia64-* \-	| ip2k-* | iq2000-* \-	| le32-* | le64-* \-	| lm32-* \-	| m32c-* | m32r-* | m32rle-* \-	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \-	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \-	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \-	| mips16-* \-	| mips64-* | mips64el-* \-	| mips64octeon-* | mips64octeonel-* \-	| mips64orion-* | mips64orionel-* \-	| mips64r5900-* | mips64r5900el-* \-	| mips64vr-* | mips64vrel-* \-	| mips64vr4100-* | mips64vr4100el-* \-	| mips64vr4300-* | mips64vr4300el-* \-	| mips64vr5000-* | mips64vr5000el-* \-	| mips64vr5900-* | mips64vr5900el-* \-	| mipsisa32-* | mipsisa32el-* \-	| mipsisa32r2-* | mipsisa32r2el-* \-	| mipsisa64-* | mipsisa64el-* \-	| mipsisa64r2-* | mipsisa64r2el-* \-	| mipsisa64sb1-* | mipsisa64sb1el-* \-	| mipsisa64sr71k-* | mipsisa64sr71kel-* \-	| mipstx39-* | mipstx39el-* \-	| mmix-* \-	| mt-* \-	| msp430-* \-	| nds32-* | nds32le-* | nds32be-* \-	| nios-* | nios2-* \-	| none-* | np1-* | ns16k-* | ns32k-* \-	| open8-* \-	| orion-* \-	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \-	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \-	| pyramid-* \-	| rl78-* | romp-* | rs6000-* | rx-* \-	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \-	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \-	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \-	| sparclite-* \-	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \-	| tahoe-* \-	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \-	| tile*-* \-	| tron-* \-	| ubicom32-* \-	| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \-	| vax-* \-	| we32k-* \-	| x86-* | x86_64-* | xc16x-* | xps100-* \-	| xstormy16-* | xtensa*-* \-	| ymp-* \-	| z8k-* | z80-*)-		;;-	# Recognize the basic CPU types without company name, with glob match.-	xtensa*)-		basic_machine=$basic_machine-unknown-		;;-	# Recognize the various machine names and aliases which stand-	# for a CPU type and a company and sometimes even an OS.-	386bsd)-		basic_machine=i386-unknown-		os=-bsd-		;;-	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)-		basic_machine=m68000-att-		;;-	3b*)-		basic_machine=we32k-att-		;;-	a29khif)-		basic_machine=a29k-amd-		os=-udi-		;;-	abacus)-		basic_machine=abacus-unknown-		;;-	adobe68k)-		basic_machine=m68010-adobe-		os=-scout-		;;-	alliant | fx80)-		basic_machine=fx80-alliant-		;;-	altos | altos3068)-		basic_machine=m68k-altos-		;;-	am29k)-		basic_machine=a29k-none-		os=-bsd-		;;-	amd64)-		basic_machine=x86_64-pc-		;;-	amd64-*)-		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`-		;;-	amdahl)-		basic_machine=580-amdahl-		os=-sysv-		;;-	amiga | amiga-*)-		basic_machine=m68k-unknown-		;;-	amigaos | amigados)-		basic_machine=m68k-unknown-		os=-amigaos-		;;-	amigaunix | amix)-		basic_machine=m68k-unknown-		os=-sysv4-		;;-	apollo68)-		basic_machine=m68k-apollo-		os=-sysv-		;;-	apollo68bsd)-		basic_machine=m68k-apollo-		os=-bsd-		;;-	aros)-		basic_machine=i386-pc-		os=-aros-		;;-	aux)-		basic_machine=m68k-apple-		os=-aux-		;;-	balance)-		basic_machine=ns32k-sequent-		os=-dynix-		;;-	blackfin)-		basic_machine=bfin-unknown-		os=-linux-		;;-	blackfin-*)-		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`-		os=-linux-		;;-	bluegene*)-		basic_machine=powerpc-ibm-		os=-cnk-		;;-	c54x-*)-		basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`-		;;-	c55x-*)-		basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`-		;;-	c6x-*)-		basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`-		;;-	c90)-		basic_machine=c90-cray-		os=-unicos-		;;-	cegcc)-		basic_machine=arm-unknown-		os=-cegcc-		;;-	convex-c1)-		basic_machine=c1-convex-		os=-bsd-		;;-	convex-c2)-		basic_machine=c2-convex-		os=-bsd-		;;-	convex-c32)-		basic_machine=c32-convex-		os=-bsd-		;;-	convex-c34)-		basic_machine=c34-convex-		os=-bsd-		;;-	convex-c38)-		basic_machine=c38-convex-		os=-bsd-		;;-	cray | j90)-		basic_machine=j90-cray-		os=-unicos-		;;-	craynv)-		basic_machine=craynv-cray-		os=-unicosmp-		;;-	cr16 | cr16-*)-		basic_machine=cr16-unknown-		os=-elf-		;;-	crds | unos)-		basic_machine=m68k-crds-		;;-	crisv32 | crisv32-* | etraxfs*)-		basic_machine=crisv32-axis-		;;-	cris | cris-* | etrax*)-		basic_machine=cris-axis-		;;-	crx)-		basic_machine=crx-unknown-		os=-elf-		;;-	da30 | da30-*)-		basic_machine=m68k-da30-		;;-	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)-		basic_machine=mips-dec-		;;-	decsystem10* | dec10*)-		basic_machine=pdp10-dec-		os=-tops10-		;;-	decsystem20* | dec20*)-		basic_machine=pdp10-dec-		os=-tops20-		;;-	delta | 3300 | motorola-3300 | motorola-delta \-	      | 3300-motorola | delta-motorola)-		basic_machine=m68k-motorola-		;;-	delta88)-		basic_machine=m88k-motorola-		os=-sysv3-		;;-	dicos)-		basic_machine=i686-pc-		os=-dicos-		;;-	djgpp)-		basic_machine=i586-pc-		os=-msdosdjgpp-		;;-	dpx20 | dpx20-*)-		basic_machine=rs6000-bull-		os=-bosx-		;;-	dpx2* | dpx2*-bull)-		basic_machine=m68k-bull-		os=-sysv3-		;;-	ebmon29k)-		basic_machine=a29k-amd-		os=-ebmon-		;;-	elxsi)-		basic_machine=elxsi-elxsi-		os=-bsd-		;;-	encore | umax | mmax)-		basic_machine=ns32k-encore-		;;-	es1800 | OSE68k | ose68k | ose | OSE)-		basic_machine=m68k-ericsson-		os=-ose-		;;-	fx2800)-		basic_machine=i860-alliant-		;;-	genix)-		basic_machine=ns32k-ns-		;;-	gmicro)-		basic_machine=tron-gmicro-		os=-sysv-		;;-	go32)-		basic_machine=i386-pc-		os=-go32-		;;-	h3050r* | hiux*)-		basic_machine=hppa1.1-hitachi-		os=-hiuxwe2-		;;-	h8300hms)-		basic_machine=h8300-hitachi-		os=-hms-		;;-	h8300xray)-		basic_machine=h8300-hitachi-		os=-xray-		;;-	h8500hms)-		basic_machine=h8500-hitachi-		os=-hms-		;;-	harris)-		basic_machine=m88k-harris-		os=-sysv3-		;;-	hp300-*)-		basic_machine=m68k-hp-		;;-	hp300bsd)-		basic_machine=m68k-hp-		os=-bsd-		;;-	hp300hpux)-		basic_machine=m68k-hp-		os=-hpux-		;;-	hp3k9[0-9][0-9] | hp9[0-9][0-9])-		basic_machine=hppa1.0-hp-		;;-	hp9k2[0-9][0-9] | hp9k31[0-9])-		basic_machine=m68000-hp-		;;-	hp9k3[2-9][0-9])-		basic_machine=m68k-hp-		;;-	hp9k6[0-9][0-9] | hp6[0-9][0-9])-		basic_machine=hppa1.0-hp-		;;-	hp9k7[0-79][0-9] | hp7[0-79][0-9])-		basic_machine=hppa1.1-hp-		;;-	hp9k78[0-9] | hp78[0-9])-		# FIXME: really hppa2.0-hp-		basic_machine=hppa1.1-hp-		;;-	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)-		# FIXME: really hppa2.0-hp-		basic_machine=hppa1.1-hp-		;;-	hp9k8[0-9][13679] | hp8[0-9][13679])-		basic_machine=hppa1.1-hp-		;;-	hp9k8[0-9][0-9] | hp8[0-9][0-9])-		basic_machine=hppa1.0-hp-		;;-	hppa-next)-		os=-nextstep3-		;;-	hppaosf)-		basic_machine=hppa1.1-hp-		os=-osf-		;;-	hppro)-		basic_machine=hppa1.1-hp-		os=-proelf-		;;-	i370-ibm* | ibm*)-		basic_machine=i370-ibm-		;;-	i*86v32)-		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`-		os=-sysv32-		;;-	i*86v4*)-		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`-		os=-sysv4-		;;-	i*86v)-		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`-		os=-sysv-		;;-	i*86sol2)-		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`-		os=-solaris2-		;;-	i386mach)-		basic_machine=i386-mach-		os=-mach-		;;-	i386-vsta | vsta)-		basic_machine=i386-unknown-		os=-vsta-		;;-	iris | iris4d)-		basic_machine=mips-sgi-		case $os in-		    -irix*)-			;;-		    *)-			os=-irix4-			;;-		esac-		;;-	isi68 | isi)-		basic_machine=m68k-isi-		os=-sysv-		;;-	m68knommu)-		basic_machine=m68k-unknown-		os=-linux-		;;-	m68knommu-*)-		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`-		os=-linux-		;;-	m88k-omron*)-		basic_machine=m88k-omron-		;;-	magnum | m3230)-		basic_machine=mips-mips-		os=-sysv-		;;-	merlin)-		basic_machine=ns32k-utek-		os=-sysv-		;;-	microblaze)-		basic_machine=microblaze-xilinx-		;;-	mingw64)-		basic_machine=x86_64-pc-		os=-mingw64-		;;-	mingw32)-		basic_machine=i386-pc-		os=-mingw32-		;;-	mingw32ce)-		basic_machine=arm-unknown-		os=-mingw32ce-		;;-	miniframe)-		basic_machine=m68000-convergent-		;;-	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)-		basic_machine=m68k-atari-		os=-mint-		;;-	mips3*-*)-		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-		;;-	mips3*)-		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown-		;;-	monitor)-		basic_machine=m68k-rom68k-		os=-coff-		;;-	morphos)-		basic_machine=powerpc-unknown-		os=-morphos-		;;-	msdos)-		basic_machine=i386-pc-		os=-msdos-		;;-	ms1-*)-		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`-		;;-	msys)-		basic_machine=i386-pc-		os=-msys-		;;-	mvs)-		basic_machine=i370-ibm-		os=-mvs-		;;-	nacl)-		basic_machine=le32-unknown-		os=-nacl-		;;-	ncr3000)-		basic_machine=i486-ncr-		os=-sysv4-		;;-	netbsd386)-		basic_machine=i386-unknown-		os=-netbsd-		;;-	netwinder)-		basic_machine=armv4l-rebel-		os=-linux-		;;-	news | news700 | news800 | news900)-		basic_machine=m68k-sony-		os=-newsos-		;;-	news1000)-		basic_machine=m68030-sony-		os=-newsos-		;;-	news-3600 | risc-news)-		basic_machine=mips-sony-		os=-newsos-		;;-	necv70)-		basic_machine=v70-nec-		os=-sysv-		;;-	next | m*-next )-		basic_machine=m68k-next-		case $os in-		    -nextstep* )-			;;-		    -ns2*)-		      os=-nextstep2-			;;-		    *)-		      os=-nextstep3-			;;-		esac-		;;-	nh3000)-		basic_machine=m68k-harris-		os=-cxux-		;;-	nh[45]000)-		basic_machine=m88k-harris-		os=-cxux-		;;-	nindy960)-		basic_machine=i960-intel-		os=-nindy-		;;-	mon960)-		basic_machine=i960-intel-		os=-mon960-		;;-	nonstopux)-		basic_machine=mips-compaq-		os=-nonstopux-		;;-	np1)-		basic_machine=np1-gould-		;;-	neo-tandem)-		basic_machine=neo-tandem-		;;-	nse-tandem)-		basic_machine=nse-tandem-		;;-	nsr-tandem)-		basic_machine=nsr-tandem-		;;-	op50n-* | op60c-*)-		basic_machine=hppa1.1-oki-		os=-proelf-		;;-	openrisc | openrisc-*)-		basic_machine=or32-unknown-		;;-	os400)-		basic_machine=powerpc-ibm-		os=-os400-		;;-	OSE68000 | ose68000)-		basic_machine=m68000-ericsson-		os=-ose-		;;-	os68k)-		basic_machine=m68k-none-		os=-os68k-		;;-	pa-hitachi)-		basic_machine=hppa1.1-hitachi-		os=-hiuxwe2-		;;-	paragon)-		basic_machine=i860-intel-		os=-osf-		;;-	parisc)-		basic_machine=hppa-unknown-		os=-linux-		;;-	parisc-*)-		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`-		os=-linux-		;;-	pbd)-		basic_machine=sparc-tti-		;;-	pbb)-		basic_machine=m68k-tti-		;;-	pc532 | pc532-*)-		basic_machine=ns32k-pc532-		;;-	pc98)-		basic_machine=i386-pc-		;;-	pc98-*)-		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`-		;;-	pentium | p5 | k5 | k6 | nexgen | viac3)-		basic_machine=i586-pc-		;;-	pentiumpro | p6 | 6x86 | athlon | athlon_*)-		basic_machine=i686-pc-		;;-	pentiumii | pentium2 | pentiumiii | pentium3)-		basic_machine=i686-pc-		;;-	pentium4)-		basic_machine=i786-pc-		;;-	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)-		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`-		;;-	pentiumpro-* | p6-* | 6x86-* | athlon-*)-		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`-		;;-	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)-		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`-		;;-	pentium4-*)-		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`-		;;-	pn)-		basic_machine=pn-gould-		;;-	power)	basic_machine=power-ibm-		;;-	ppc | ppcbe)	basic_machine=powerpc-unknown-		;;-	ppc-* | ppcbe-*)-		basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`-		;;-	ppcle | powerpclittle | ppc-le | powerpc-little)-		basic_machine=powerpcle-unknown-		;;-	ppcle-* | powerpclittle-*)-		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`-		;;-	ppc64)	basic_machine=powerpc64-unknown-		;;-	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`-		;;-	ppc64le | powerpc64little | ppc64-le | powerpc64-little)-		basic_machine=powerpc64le-unknown-		;;-	ppc64le-* | powerpc64little-*)-		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`-		;;-	ps2)-		basic_machine=i386-ibm-		;;-	pw32)-		basic_machine=i586-unknown-		os=-pw32-		;;-	rdos)-		basic_machine=i386-pc-		os=-rdos-		;;-	rom68k)-		basic_machine=m68k-rom68k-		os=-coff-		;;-	rm[46]00)-		basic_machine=mips-siemens-		;;-	rtpc | rtpc-*)-		basic_machine=romp-ibm-		;;-	s390 | s390-*)-		basic_machine=s390-ibm-		;;-	s390x | s390x-*)-		basic_machine=s390x-ibm-		;;-	sa29200)-		basic_machine=a29k-amd-		os=-udi-		;;-	sb1)-		basic_machine=mipsisa64sb1-unknown-		;;-	sb1el)-		basic_machine=mipsisa64sb1el-unknown-		;;-	sde)-		basic_machine=mipsisa32-sde-		os=-elf-		;;-	sei)-		basic_machine=mips-sei-		os=-seiux-		;;-	sequent)-		basic_machine=i386-sequent-		;;-	sh)-		basic_machine=sh-hitachi-		os=-hms-		;;-	sh5el)-		basic_machine=sh5le-unknown-		;;-	sh64)-		basic_machine=sh64-unknown-		;;-	sparclite-wrs | simso-wrs)-		basic_machine=sparclite-wrs-		os=-vxworks-		;;-	sps7)-		basic_machine=m68k-bull-		os=-sysv2-		;;-	spur)-		basic_machine=spur-unknown-		;;-	st2000)-		basic_machine=m68k-tandem-		;;-	stratus)-		basic_machine=i860-stratus-		os=-sysv4-		;;-	strongarm-* | thumb-*)-		basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`-		;;-	sun2)-		basic_machine=m68000-sun-		;;-	sun2os3)-		basic_machine=m68000-sun-		os=-sunos3-		;;-	sun2os4)-		basic_machine=m68000-sun-		os=-sunos4-		;;-	sun3os3)-		basic_machine=m68k-sun-		os=-sunos3-		;;-	sun3os4)-		basic_machine=m68k-sun-		os=-sunos4-		;;-	sun4os3)-		basic_machine=sparc-sun-		os=-sunos3-		;;-	sun4os4)-		basic_machine=sparc-sun-		os=-sunos4-		;;-	sun4sol2)-		basic_machine=sparc-sun-		os=-solaris2-		;;-	sun3 | sun3-*)-		basic_machine=m68k-sun-		;;-	sun4)-		basic_machine=sparc-sun-		;;-	sun386 | sun386i | roadrunner)-		basic_machine=i386-sun-		;;-	sv1)-		basic_machine=sv1-cray-		os=-unicos-		;;-	symmetry)-		basic_machine=i386-sequent-		os=-dynix-		;;-	t3e)-		basic_machine=alphaev5-cray-		os=-unicos-		;;-	t90)-		basic_machine=t90-cray-		os=-unicos-		;;-	tile*)-		basic_machine=$basic_machine-unknown-		os=-linux-gnu-		;;-	tx39)-		basic_machine=mipstx39-unknown-		;;-	tx39el)-		basic_machine=mipstx39el-unknown-		;;-	toad1)-		basic_machine=pdp10-xkl-		os=-tops20-		;;-	tower | tower-32)-		basic_machine=m68k-ncr-		;;-	tpf)-		basic_machine=s390x-ibm-		os=-tpf-		;;-	udi29k)-		basic_machine=a29k-amd-		os=-udi-		;;-	ultra3)-		basic_machine=a29k-nyu-		os=-sym1-		;;-	v810 | necv810)-		basic_machine=v810-nec-		os=-none-		;;-	vaxv)-		basic_machine=vax-dec-		os=-sysv-		;;-	vms)-		basic_machine=vax-dec-		os=-vms-		;;-	vpp*|vx|vx-*)-		basic_machine=f301-fujitsu-		;;-	vxworks960)-		basic_machine=i960-wrs-		os=-vxworks-		;;-	vxworks68)-		basic_machine=m68k-wrs-		os=-vxworks-		;;-	vxworks29k)-		basic_machine=a29k-wrs-		os=-vxworks-		;;-	w65*)-		basic_machine=w65-wdc-		os=-none-		;;-	w89k-*)-		basic_machine=hppa1.1-winbond-		os=-proelf-		;;-	xbox)-		basic_machine=i686-pc-		os=-mingw32-		;;-	xps | xps100)-		basic_machine=xps100-honeywell-		;;-	xscale-* | xscalee[bl]-*)-		basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`-		;;-	ymp)-		basic_machine=ymp-cray-		os=-unicos-		;;-	z8k-*-coff)-		basic_machine=z8k-unknown-		os=-sim-		;;-	z80-*-coff)-		basic_machine=z80-unknown-		os=-sim-		;;-	none)-		basic_machine=none-none-		os=-none-		;;--# Here we handle the default manufacturer of certain CPU types.  It is in-# some cases the only manufacturer, in others, it is the most popular.-	w89k)-		basic_machine=hppa1.1-winbond-		;;-	op50n)-		basic_machine=hppa1.1-oki-		;;-	op60c)-		basic_machine=hppa1.1-oki-		;;-	romp)-		basic_machine=romp-ibm-		;;-	mmix)-		basic_machine=mmix-knuth-		;;-	rs6000)-		basic_machine=rs6000-ibm-		;;-	vax)-		basic_machine=vax-dec-		;;-	pdp10)-		# there are many clones, so DEC is not a safe bet-		basic_machine=pdp10-unknown-		;;-	pdp11)-		basic_machine=pdp11-dec-		;;-	we32k)-		basic_machine=we32k-att-		;;-	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)-		basic_machine=sh-unknown-		;;-	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)-		basic_machine=sparc-sun-		;;-	cydra)-		basic_machine=cydra-cydrome-		;;-	orion)-		basic_machine=orion-highlevel-		;;-	orion105)-		basic_machine=clipper-highlevel-		;;-	mac | mpw | mac-mpw)-		basic_machine=m68k-apple-		;;-	pmac | pmac-mpw)-		basic_machine=powerpc-apple-		;;-	*-unknown)-		# Make sure to match an already-canonicalized machine name.-		;;-	*)-		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2-		exit 1-		;;-esac--# Here we canonicalize certain aliases for manufacturers.-case $basic_machine in-	*-digital*)-		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`-		;;-	*-commodore*)-		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`-		;;-	*)-		;;-esac--# Decode manufacturer-specific aliases for certain operating systems.--if [ x"$os" != x"" ]-then-case $os in-	# First match some system type aliases-	# that might get confused with valid system types.-	# -solaris* is a basic system type, with this one exception.-	-auroraux)-		os=-auroraux-		;;-	-solaris1 | -solaris1.*)-		os=`echo $os | sed -e 's|solaris1|sunos4|'`-		;;-	-solaris)-		os=-solaris2-		;;-	-svr4*)-		os=-sysv4-		;;-	-unixware*)-		os=-sysv4.2uw-		;;-	-gnu/linux*)-		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`-		;;-	# First accept the basic system types.-	# The portable systems comes first.-	# Each alternative MUST END IN A *, to match a version number.-	# -sysv* is not here because it comes later, after sysvr4.-	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \-	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\-	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \-	      | -sym* | -kopensolaris* \-	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \-	      | -aos* | -aros* \-	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \-	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \-	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \-	      | -bitrig* | -openbsd* | -solidbsd* \-	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \-	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \-	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \-	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \-	      | -chorusos* | -chorusrdb* | -cegcc* \-	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \-	      | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \-	      | -linux-newlib* | -linux-musl* | -linux-uclibc* \-	      | -uxpv* | -beos* | -mpeix* | -udk* \-	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \-	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \-	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \-	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \-	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \-	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \-	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)-	# Remember, each alternative MUST END IN *, to match a version number.-		;;-	-qnx*)-		case $basic_machine in-		    x86-* | i*86-*)-			;;-		    *)-			os=-nto$os-			;;-		esac-		;;-	-nto-qnx*)-		;;-	-nto*)-		os=`echo $os | sed -e 's|nto|nto-qnx|'`-		;;-	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \-	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \-	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)-		;;-	-mac*)-		os=`echo $os | sed -e 's|mac|macos|'`-		;;-	-linux-dietlibc)-		os=-linux-dietlibc-		;;-	-linux*)-		os=`echo $os | sed -e 's|linux|linux-gnu|'`-		;;-	-sunos5*)-		os=`echo $os | sed -e 's|sunos5|solaris2|'`-		;;-	-sunos6*)-		os=`echo $os | sed -e 's|sunos6|solaris3|'`-		;;-	-opened*)-		os=-openedition-		;;-	-os400*)-		os=-os400-		;;-	-wince*)-		os=-wince-		;;-	-osfrose*)-		os=-osfrose-		;;-	-osf*)-		os=-osf-		;;-	-utek*)-		os=-bsd-		;;-	-dynix*)-		os=-bsd-		;;-	-acis*)-		os=-aos-		;;-	-atheos*)-		os=-atheos-		;;-	-syllable*)-		os=-syllable-		;;-	-386bsd)-		os=-bsd-		;;-	-ctix* | -uts*)-		os=-sysv-		;;-	-nova*)-		os=-rtmk-nova-		;;-	-ns2 )-		os=-nextstep2-		;;-	-nsk*)-		os=-nsk-		;;-	# Preserve the version number of sinix5.-	-sinix5.*)-		os=`echo $os | sed -e 's|sinix|sysv|'`-		;;-	-sinix*)-		os=-sysv4-		;;-	-tpf*)-		os=-tpf-		;;-	-triton*)-		os=-sysv3-		;;-	-oss*)-		os=-sysv3-		;;-	-svr4)-		os=-sysv4-		;;-	-svr3)-		os=-sysv3-		;;-	-sysvr4)-		os=-sysv4-		;;-	# This must come after -sysvr4.-	-sysv*)-		;;-	-ose*)-		os=-ose-		;;-	-es1800*)-		os=-ose-		;;-	-xenix)-		os=-xenix-		;;-	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)-		os=-mint-		;;-	-aros*)-		os=-aros-		;;-	-kaos*)-		os=-kaos-		;;-	-zvmoe)-		os=-zvmoe-		;;-	-dicos*)-		os=-dicos-		;;-	-nacl*)-		;;-	-none)-		;;-	*)-		# Get rid of the `-' at the beginning of $os.-		os=`echo $os | sed 's/[^-]*-//'`-		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2-		exit 1-		;;-esac-else--# Here we handle the default operating systems that come with various machines.-# The value should be what the vendor currently ships out the door with their-# machine or put another way, the most popular os provided with the machine.--# Note that if you're going to try to match "-MANUFACTURER" here (say,-# "-sun"), then you have to tell the case statement up towards the top-# that MANUFACTURER isn't an operating system.  Otherwise, code above-# will signal an error saying that MANUFACTURER isn't an operating-# system, and we'll never get to this point.--case $basic_machine in-	score-*)-		os=-elf-		;;-	spu-*)-		os=-elf-		;;-	*-acorn)-		os=-riscix1.2-		;;-	arm*-rebel)-		os=-linux-		;;-	arm*-semi)-		os=-aout-		;;-	c4x-* | tic4x-*)-		os=-coff-		;;-	hexagon-*)-		os=-elf-		;;-	tic54x-*)-		os=-coff-		;;-	tic55x-*)-		os=-coff-		;;-	tic6x-*)-		os=-coff-		;;-	# This must come before the *-dec entry.-	pdp10-*)-		os=-tops20-		;;-	pdp11-*)-		os=-none-		;;-	*-dec | vax-*)-		os=-ultrix4.2-		;;-	m68*-apollo)-		os=-domain-		;;-	i386-sun)-		os=-sunos4.0.2-		;;-	m68000-sun)-		os=-sunos3-		;;-	m68*-cisco)-		os=-aout-		;;-	mep-*)-		os=-elf-		;;-	mips*-cisco)-		os=-elf-		;;-	mips*-*)-		os=-elf-		;;-	or32-*)-		os=-coff-		;;-	*-tti)	# must be before sparc entry or we get the wrong os.-		os=-sysv3-		;;-	sparc-* | *-sun)-		os=-sunos4.1.1-		;;-	*-be)-		os=-beos-		;;-	*-haiku)-		os=-haiku-		;;-	*-ibm)-		os=-aix-		;;-	*-knuth)-		os=-mmixware-		;;-	*-wec)-		os=-proelf-		;;-	*-winbond)-		os=-proelf-		;;-	*-oki)-		os=-proelf-		;;-	*-hp)-		os=-hpux-		;;-	*-hitachi)-		os=-hiux-		;;-	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)-		os=-sysv-		;;-	*-cbm)-		os=-amigaos-		;;-	*-dg)-		os=-dgux-		;;-	*-dolphin)-		os=-sysv3-		;;-	m68k-ccur)-		os=-rtu-		;;-	m88k-omron*)-		os=-luna-		;;-	*-next )-		os=-nextstep-		;;-	*-sequent)-		os=-ptx-		;;-	*-crds)-		os=-unos-		;;-	*-ns)-		os=-genix-		;;-	i370-*)-		os=-mvs-		;;-	*-next)-		os=-nextstep3-		;;-	*-gould)-		os=-sysv-		;;-	*-highlevel)-		os=-bsd-		;;-	*-encore)-		os=-bsd-		;;-	*-sgi)-		os=-irix-		;;-	*-siemens)-		os=-sysv4-		;;-	*-masscomp)-		os=-rtu-		;;-	f30[01]-fujitsu | f700-fujitsu)-		os=-uxpv-		;;-	*-rom68k)-		os=-coff-		;;-	*-*bug)-		os=-coff-		;;-	*-apple)-		os=-macos-		;;-	*-atari*)-		os=-mint-		;;-	*)-		os=-none-		;;-esac-fi--# Here we handle the case where we know the os, and the CPU type, but not the-# manufacturer.  We pick the logical manufacturer.-vendor=unknown-case $basic_machine in-	*-unknown)-		case $os in-			-riscix*)-				vendor=acorn-				;;-			-sunos*)-				vendor=sun-				;;-			-cnk*|-aix*)-				vendor=ibm-				;;-			-beos*)-				vendor=be-				;;-			-hpux*)-				vendor=hp-				;;-			-mpeix*)-				vendor=hp-				;;-			-hiux*)-				vendor=hitachi-				;;-			-unos*)-				vendor=crds-				;;-			-dgux*)-				vendor=dg-				;;-			-luna*)-				vendor=omron-				;;-			-genix*)-				vendor=ns-				;;-			-mvs* | -opened*)-				vendor=ibm-				;;-			-os400*)-				vendor=ibm-				;;-			-ptx*)-				vendor=sequent-				;;-			-tpf*)-				vendor=ibm-				;;-			-vxsim* | -vxworks* | -windiss*)-				vendor=wrs-				;;-			-aux*)-				vendor=apple-				;;-			-hms*)-				vendor=hitachi-				;;-			-mpw* | -macos*)-				vendor=apple-				;;-			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)-				vendor=atari-				;;-			-vos*)-				vendor=stratus-				;;-		esac-		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`-		;;-esac--echo $basic_machine$os-exit--# Local variables:-# eval: (add-hook 'write-file-hooks 'time-stamp)-# time-stamp-start: "timestamp='"-# time-stamp-format: "%:y-%02m-%02d"-# time-stamp-end: "'"-# End:
− data/nix/config/install-sh
@@ -1,527 +0,0 @@-#!/bin/sh-# install - install a program, script, or datafile--scriptversion=2011-11-20.07; # UTC--# This originates from X11R5 (mit/util/scripts/install.sh), which was-# later released in X11R6 (xc/config/util/install.sh) with the-# following copyright and license.-#-# Copyright (C) 1994 X Consortium-#-# Permission is hereby granted, free of charge, to any person obtaining a copy-# of this software and associated documentation files (the "Software"), to-# deal in the Software without restriction, including without limitation the-# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or-# sell copies of the Software, and to permit persons to whom the Software is-# furnished to do so, subject to the following conditions:-#-# The above copyright notice and this permission notice shall be included in-# all copies or substantial portions of the Software.-#-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE-# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN-# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC--# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.-#-# Except as contained in this notice, the name of the X Consortium shall not-# be used in advertising or otherwise to promote the sale, use or other deal--# ings in this Software without prior written authorization from the X Consor--# tium.-#-#-# FSF changes to this file are in the public domain.-#-# Calling this script install-sh is preferred over install.sh, to prevent-# 'make' implicit rules from creating a file called install from it-# when there is no Makefile.-#-# This script is compatible with the BSD install script, but was written-# from scratch.--nl='-'-IFS=" ""	$nl"--# set DOITPROG to echo to test this script--# Don't use :- since 4.3BSD and earlier shells don't like it.-doit=${DOITPROG-}-if test -z "$doit"; then-  doit_exec=exec-else-  doit_exec=$doit-fi--# Put in absolute file names if you don't have them in your path;-# or use environment vars.--chgrpprog=${CHGRPPROG-chgrp}-chmodprog=${CHMODPROG-chmod}-chownprog=${CHOWNPROG-chown}-cmpprog=${CMPPROG-cmp}-cpprog=${CPPROG-cp}-mkdirprog=${MKDIRPROG-mkdir}-mvprog=${MVPROG-mv}-rmprog=${RMPROG-rm}-stripprog=${STRIPPROG-strip}--posix_glob='?'-initialize_posix_glob='-  test "$posix_glob" != "?" || {-    if (set -f) 2>/dev/null; then-      posix_glob=-    else-      posix_glob=:-    fi-  }-'--posix_mkdir=--# Desired mode of installed file.-mode=0755--chgrpcmd=-chmodcmd=$chmodprog-chowncmd=-mvcmd=$mvprog-rmcmd="$rmprog -f"-stripcmd=--src=-dst=-dir_arg=-dst_arg=--copy_on_change=false-no_target_directory=--usage="\-Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE-   or: $0 [OPTION]... SRCFILES... DIRECTORY-   or: $0 [OPTION]... -t DIRECTORY SRCFILES...-   or: $0 [OPTION]... -d DIRECTORIES...--In the 1st form, copy SRCFILE to DSTFILE.-In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.-In the 4th, create DIRECTORIES.--Options:-     --help     display this help and exit.-     --version  display version info and exit.--  -c            (ignored)-  -C            install only if different (preserve the last data modification time)-  -d            create directories instead of installing files.-  -g GROUP      $chgrpprog installed files to GROUP.-  -m MODE       $chmodprog installed files to MODE.-  -o USER       $chownprog installed files to USER.-  -s            $stripprog installed files.-  -t DIRECTORY  install into DIRECTORY.-  -T            report an error if DSTFILE is a directory.--Environment variables override the default commands:-  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG-  RMPROG STRIPPROG-"--while test $# -ne 0; do-  case $1 in-    -c) ;;--    -C) copy_on_change=true;;--    -d) dir_arg=true;;--    -g) chgrpcmd="$chgrpprog $2"-	shift;;--    --help) echo "$usage"; exit $?;;--    -m) mode=$2-	case $mode in-	  *' '* | *'	'* | *'-'*	  | *'*'* | *'?'* | *'['*)-	    echo "$0: invalid mode: $mode" >&2-	    exit 1;;-	esac-	shift;;--    -o) chowncmd="$chownprog $2"-	shift;;--    -s) stripcmd=$stripprog;;--    -t) dst_arg=$2-	# Protect names problematic for 'test' and other utilities.-	case $dst_arg in-	  -* | [=\(\)!]) dst_arg=./$dst_arg;;-	esac-	shift;;--    -T) no_target_directory=true;;--    --version) echo "$0 $scriptversion"; exit $?;;--    --)	shift-	break;;--    -*)	echo "$0: invalid option: $1" >&2-	exit 1;;--    *)  break;;-  esac-  shift-done--if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then-  # When -d is used, all remaining arguments are directories to create.-  # When -t is used, the destination is already specified.-  # Otherwise, the last argument is the destination.  Remove it from $@.-  for arg-  do-    if test -n "$dst_arg"; then-      # $@ is not empty: it contains at least $arg.-      set fnord "$@" "$dst_arg"-      shift # fnord-    fi-    shift # arg-    dst_arg=$arg-    # Protect names problematic for 'test' and other utilities.-    case $dst_arg in-      -* | [=\(\)!]) dst_arg=./$dst_arg;;-    esac-  done-fi--if test $# -eq 0; then-  if test -z "$dir_arg"; then-    echo "$0: no input file specified." >&2-    exit 1-  fi-  # It's OK to call 'install-sh -d' without argument.-  # This can happen when creating conditional directories.-  exit 0-fi--if test -z "$dir_arg"; then-  do_exit='(exit $ret); exit $ret'-  trap "ret=129; $do_exit" 1-  trap "ret=130; $do_exit" 2-  trap "ret=141; $do_exit" 13-  trap "ret=143; $do_exit" 15--  # Set umask so as not to create temps with too-generous modes.-  # However, 'strip' requires both read and write access to temps.-  case $mode in-    # Optimize common cases.-    *644) cp_umask=133;;-    *755) cp_umask=22;;--    *[0-7])-      if test -z "$stripcmd"; then-	u_plus_rw=-      else-	u_plus_rw='% 200'-      fi-      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;-    *)-      if test -z "$stripcmd"; then-	u_plus_rw=-      else-	u_plus_rw=,u+rw-      fi-      cp_umask=$mode$u_plus_rw;;-  esac-fi--for src-do-  # Protect names problematic for 'test' and other utilities.-  case $src in-    -* | [=\(\)!]) src=./$src;;-  esac--  if test -n "$dir_arg"; then-    dst=$src-    dstdir=$dst-    test -d "$dstdir"-    dstdir_status=$?-  else--    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command-    # might cause directories to be created, which would be especially bad-    # if $src (and thus $dsttmp) contains '*'.-    if test ! -f "$src" && test ! -d "$src"; then-      echo "$0: $src does not exist." >&2-      exit 1-    fi--    if test -z "$dst_arg"; then-      echo "$0: no destination specified." >&2-      exit 1-    fi-    dst=$dst_arg--    # If destination is a directory, append the input filename; won't work-    # if double slashes aren't ignored.-    if test -d "$dst"; then-      if test -n "$no_target_directory"; then-	echo "$0: $dst_arg: Is a directory" >&2-	exit 1-      fi-      dstdir=$dst-      dst=$dstdir/`basename "$src"`-      dstdir_status=0-    else-      # Prefer dirname, but fall back on a substitute if dirname fails.-      dstdir=`-	(dirname "$dst") 2>/dev/null ||-	expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \-	     X"$dst" : 'X\(//\)[^/]' \| \-	     X"$dst" : 'X\(//\)$' \| \-	     X"$dst" : 'X\(/\)' \| . 2>/dev/null ||-	echo X"$dst" |-	    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{-		   s//\1/-		   q-		 }-		 /^X\(\/\/\)[^/].*/{-		   s//\1/-		   q-		 }-		 /^X\(\/\/\)$/{-		   s//\1/-		   q-		 }-		 /^X\(\/\).*/{-		   s//\1/-		   q-		 }-		 s/.*/./; q'-      `--      test -d "$dstdir"-      dstdir_status=$?-    fi-  fi--  obsolete_mkdir_used=false--  if test $dstdir_status != 0; then-    case $posix_mkdir in-      '')-	# Create intermediate dirs using mode 755 as modified by the umask.-	# This is like FreeBSD 'install' as of 1997-10-28.-	umask=`umask`-	case $stripcmd.$umask in-	  # Optimize common cases.-	  *[2367][2367]) mkdir_umask=$umask;;-	  .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;--	  *[0-7])-	    mkdir_umask=`expr $umask + 22 \-	      - $umask % 100 % 40 + $umask % 20 \-	      - $umask % 10 % 4 + $umask % 2-	    `;;-	  *) mkdir_umask=$umask,go-w;;-	esac--	# With -d, create the new directory with the user-specified mode.-	# Otherwise, rely on $mkdir_umask.-	if test -n "$dir_arg"; then-	  mkdir_mode=-m$mode-	else-	  mkdir_mode=-	fi--	posix_mkdir=false-	case $umask in-	  *[123567][0-7][0-7])-	    # POSIX mkdir -p sets u+wx bits regardless of umask, which-	    # is incompatible with FreeBSD 'install' when (umask & 300) != 0.-	    ;;-	  *)-	    tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$-	    trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0--	    if (umask $mkdir_umask &&-		exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1-	    then-	      if test -z "$dir_arg" || {-		   # Check for POSIX incompatibilities with -m.-		   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or-		   # other-writable bit of parent directory when it shouldn't.-		   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.-		   ls_ld_tmpdir=`ls -ld "$tmpdir"`-		   case $ls_ld_tmpdir in-		     d????-?r-*) different_mode=700;;-		     d????-?--*) different_mode=755;;-		     *) false;;-		   esac &&-		   $mkdirprog -m$different_mode -p -- "$tmpdir" && {-		     ls_ld_tmpdir_1=`ls -ld "$tmpdir"`-		     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"-		   }-		 }-	      then posix_mkdir=:-	      fi-	      rmdir "$tmpdir/d" "$tmpdir"-	    else-	      # Remove any dirs left behind by ancient mkdir implementations.-	      rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null-	    fi-	    trap '' 0;;-	esac;;-    esac--    if-      $posix_mkdir && (-	umask $mkdir_umask &&-	$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"-      )-    then :-    else--      # The umask is ridiculous, or mkdir does not conform to POSIX,-      # or it failed possibly due to a race condition.  Create the-      # directory the slow way, step by step, checking for races as we go.--      case $dstdir in-	/*) prefix='/';;-	[-=\(\)!]*) prefix='./';;-	*)  prefix='';;-      esac--      eval "$initialize_posix_glob"--      oIFS=$IFS-      IFS=/-      $posix_glob set -f-      set fnord $dstdir-      shift-      $posix_glob set +f-      IFS=$oIFS--      prefixes=--      for d-      do-	test X"$d" = X && continue--	prefix=$prefix$d-	if test -d "$prefix"; then-	  prefixes=-	else-	  if $posix_mkdir; then-	    (umask=$mkdir_umask &&-	     $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break-	    # Don't fail if two instances are running concurrently.-	    test -d "$prefix" || exit 1-	  else-	    case $prefix in-	      *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;-	      *) qprefix=$prefix;;-	    esac-	    prefixes="$prefixes '$qprefix'"-	  fi-	fi-	prefix=$prefix/-      done--      if test -n "$prefixes"; then-	# Don't fail if two instances are running concurrently.-	(umask $mkdir_umask &&-	 eval "\$doit_exec \$mkdirprog $prefixes") ||-	  test -d "$dstdir" || exit 1-	obsolete_mkdir_used=true-      fi-    fi-  fi--  if test -n "$dir_arg"; then-    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&-    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&-    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||-      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1-  else--    # Make a couple of temp file names in the proper directory.-    dsttmp=$dstdir/_inst.$$_-    rmtmp=$dstdir/_rm.$$_--    # Trap to clean up those temp files at exit.-    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0--    # Copy the file name to the temp name.-    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&--    # and set any options; do chmod last to preserve setuid bits.-    #-    # If any of these fail, we abort the whole thing.  If we want to-    # ignore errors from any of these, just make sure not to ignore-    # errors from the above "$doit $cpprog $src $dsttmp" command.-    #-    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&-    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&-    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&-    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&--    # If -C, don't bother to copy if it wouldn't change the file.-    if $copy_on_change &&-       old=`LC_ALL=C ls -dlL "$dst"	2>/dev/null` &&-       new=`LC_ALL=C ls -dlL "$dsttmp"	2>/dev/null` &&--       eval "$initialize_posix_glob" &&-       $posix_glob set -f &&-       set X $old && old=:$2:$4:$5:$6 &&-       set X $new && new=:$2:$4:$5:$6 &&-       $posix_glob set +f &&--       test "$old" = "$new" &&-       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1-    then-      rm -f "$dsttmp"-    else-      # Rename the file to the real destination.-      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||--      # The rename failed, perhaps because mv can't rename something else-      # to itself, or perhaps because mv is so ancient that it does not-      # support -f.-      {-	# Now remove or move aside any old file at destination location.-	# We try this two ways since rm can't unlink itself on some-	# systems and the destination file might be busy for other-	# reasons.  In this case, the final cleanup might fail but the new-	# file should still install successfully.-	{-	  test ! -f "$dst" ||-	  $doit $rmcmd -f "$dst" 2>/dev/null ||-	  { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&-	    { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }-	  } ||-	  { echo "$0: cannot unlink or rename $dst" >&2-	    (exit 1); exit 1-	  }-	} &&--	# Now rename the file to the real destination.-	$doit $mvcmd "$dsttmp" "$dst"-      }-    fi || exit 1--    trap '' 0-  fi-done--# Local variables:-# eval: (add-hook 'write-file-hooks 'time-stamp)-# time-stamp-start: "scriptversion="-# time-stamp-format: "%:y-%02m-%02d.%02H"-# time-stamp-time-zone: "UTC"-# time-stamp-end: "; # UTC"-# End:
− data/nix/configure.ac
@@ -1,298 +0,0 @@-AC_INIT(nix, m4_esyscmd([bash -c "echo -n $(cat ./version)$VERSION_SUFFIX"]))-AC_CONFIG_SRCDIR(README.md)-AC_CONFIG_AUX_DIR(config)--AC_PROG_SED--# Construct a Nix system name (like "i686-linux").-AC_CANONICAL_HOST-AC_MSG_CHECKING([for the canonical Nix system name])--AC_ARG_WITH(system, AC_HELP_STRING([--with-system=SYSTEM],-  [Platform identifier (e.g., `i686-linux').]),-  [system=$withval],-  [case "$host_cpu" in-     i*86)-        machine_name="i686";;-     amd64)-        machine_name="x86_64";;-     armv6|armv7)-        machine_name="${host_cpu}l";;-     *)-        machine_name="$host_cpu";;-   esac--   case "$host_os" in-     linux-gnu*|linux-musl*)-        # For backward compatibility, strip the `-gnu' part.-        system="$machine_name-linux";;-     *)-        # Strip the version number from names such as `gnu0.3',-        # `darwin10.2.0', etc.-        system="$machine_name-`echo $host_os | "$SED" -e's/@<:@0-9.@:>@*$//g'`";;-   esac])--sys_name=$(uname -s | tr 'A-Z ' 'a-z_')--case $sys_name in-    cygwin*)-        sys_name=cygwin-        ;;-esac--AC_MSG_RESULT($system)-AC_SUBST(system)-AC_DEFINE_UNQUOTED(SYSTEM, ["$system"], [platform identifier (`cpu-os')])---# State should be stored in /nix/var, unless the user overrides it explicitly.-test "$localstatedir" = '${prefix}/var' && localstatedir=/nix/var---# Solaris-specific stuff.-AC_STRUCT_DIRENT_D_TYPE-if test "$sys_name" = sunos; then-    # Solaris requires -lsocket -lnsl for network functions-    LIBS="-lsocket -lnsl $LIBS"-fi---CFLAGS=-CXXFLAGS=-AC_PROG_CC-AC_PROG_CXX-AC_PROG_CPP-AX_CXX_COMPILE_STDCXX_14---# Use 64-bit file system calls so that we can support files > 2 GiB.-AC_SYS_LARGEFILE---# Check for pubsetbuf.-AC_MSG_CHECKING([for pubsetbuf])-AC_LANG_PUSH(C++)-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <iostream>-using namespace std;-static char buf[1024];]],-    [[cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));]])],-    [AC_MSG_RESULT(yes) AC_DEFINE(HAVE_PUBSETBUF, 1, [Whether pubsetbuf is available.])],-    AC_MSG_RESULT(no))-AC_LANG_POP(C++)---AC_CHECK_FUNCS([statvfs pipe2])---# Check for lutimes, optionally used for changing the mtime of-# symlinks.-AC_CHECK_FUNCS([lutimes])---# Check whether the store optimiser can optimise symlinks.-AC_MSG_CHECKING([whether it is possible to create a link to a symlink])-ln -s bla tmp_link-if ln tmp_link tmp_link2 2> /dev/null; then-    AC_MSG_RESULT(yes)-    AC_DEFINE(CAN_LINK_SYMLINK, 1, [Whether link() works on symlinks.])-else-    AC_MSG_RESULT(no)-fi-rm -f tmp_link tmp_link2---# Check for <locale>.-AC_LANG_PUSH(C++)-AC_CHECK_HEADERS([locale])-AC_LANG_POP(C++)---AC_DEFUN([NEED_PROG],-[-AC_PATH_PROG($1, $2)-if test -z "$$1"; then-    AC_MSG_ERROR([$2 is required])-fi-])--NEED_PROG(bash, bash)-NEED_PROG(patch, patch)-AC_PATH_PROG(xmllint, xmllint, false)-AC_PATH_PROG(xsltproc, xsltproc, false)-AC_PATH_PROG(flex, flex, false)-AC_PATH_PROG(bison, bison, false)-NEED_PROG(sed, sed)-NEED_PROG(tar, tar)-NEED_PROG(bzip2, bzip2)-NEED_PROG(gzip, gzip)-NEED_PROG(xz, xz)-AC_PATH_PROG(dot, dot)-AC_PATH_PROG(pv, pv, pv)-AC_PATH_PROGS(brotli, brotli bro, bro)-AC_PATH_PROG(lsof, lsof, lsof)---NEED_PROG(cat, cat)-NEED_PROG(tr, tr)-AC_ARG_WITH(coreutils-bin, AC_HELP_STRING([--with-coreutils-bin=PATH],-  [path of cat, mkdir, etc.]),-  coreutils=$withval, coreutils=$(dirname $cat))-AC_SUBST(coreutils)---AC_ARG_WITH(store-dir, AC_HELP_STRING([--with-store-dir=PATH],-  [path of the Nix store (defaults to /nix/store)]),-  storedir=$withval, storedir='/nix/store')-AC_SUBST(storedir)---# Look for OpenSSL, a required dependency.-PKG_CHECK_MODULES([OPENSSL], [libcrypto], [CXXFLAGS="$OPENSSL_CFLAGS $CXXFLAGS"])---# Look for libbz2, a required dependency.-AC_CHECK_LIB([bz2], [BZ2_bzWriteOpen], [true],-  [AC_MSG_ERROR([Nix requires libbz2, which is part of bzip2.  See http://www.bzip.org/.])])-AC_CHECK_HEADERS([bzlib.h], [true],-  [AC_MSG_ERROR([Nix requires libbz2, which is part of bzip2.  See http://www.bzip.org/.])])---# Look for SQLite, a required dependency.-PKG_CHECK_MODULES([SQLITE3], [sqlite3 >= 3.6.19], [CXXFLAGS="$SQLITE3_CFLAGS $CXXFLAGS"])---# Look for libcurl, a required dependency.-PKG_CHECK_MODULES([LIBCURL], [libcurl], [CXXFLAGS="$LIBCURL_CFLAGS $CXXFLAGS"])---# Look for libsodium, an optional dependency.-PKG_CHECK_MODULES([SODIUM], [libsodium],-  [AC_DEFINE([HAVE_SODIUM], [1], [Whether to use libsodium for cryptography.])-   CXXFLAGS="$SODIUM_CFLAGS $CXXFLAGS"-   have_sodium=1], [have_sodium=])-AC_SUBST(HAVE_SODIUM, [$have_sodium])---# Look for liblzma, a required dependency.-PKG_CHECK_MODULES([LIBLZMA], [liblzma], [CXXFLAGS="$LIBLZMA_CFLAGS $CXXFLAGS"])-AC_CHECK_LIB([lzma], [lzma_stream_encoder_mt],-  [AC_DEFINE([HAVE_LZMA_MT], [1], [xz multithreaded compression support])])---# Look for libbrotli{enc,dec}, optional dependencies-PKG_CHECK_MODULES([LIBBROTLI], [libbrotlienc libbrotlidec],-  [AC_DEFINE([HAVE_BROTLI], [1], [Whether to use libbrotli.])-   CXXFLAGS="$LIBBROTLI_CFLAGS $CXXFLAGS"]-   have_brotli=1], [have_brotli=])-AC_SUBST(HAVE_BROTLI, [$have_brotli])--# Look for libseccomp, required for Linux sandboxing.-if test "$sys_name" = linux; then-  AC_ARG_ENABLE([seccomp-sandboxing],-                AC_HELP_STRING([--disable-seccomp-sandboxing],-                               [Don't build support for seccomp sandboxing (only recommended if your arch doesn't support libseccomp yet!)]-                              ))-  if test "x$enable_seccomp_sandboxing" != "xno"; then-    PKG_CHECK_MODULES([LIBSECCOMP], [libseccomp],-                      [CXXFLAGS="$LIBSECCOMP_CFLAGS $CXXFLAGS"])-    have_seccomp=1-    AC_DEFINE([HAVE_SECCOMP], [1], [Whether seccomp is available and should be used for sandboxing.])-  else-    have_seccomp=-  fi-else-  have_seccomp=-fi-AC_SUBST(HAVE_SECCOMP, [$have_seccomp])---# Look for aws-cpp-sdk-s3.-AC_LANG_PUSH(C++)-AC_CHECK_HEADERS([aws/s3/S3Client.h],-  [AC_DEFINE([ENABLE_S3], [1], [Whether to enable S3 support via aws-sdk-cpp.])-  enable_s3=1], [enable_s3=])-AC_SUBST(ENABLE_S3, [$enable_s3])-AC_LANG_POP(C++)--if test -n "$enable_s3"; then-  declare -a aws_version_tokens=($(printf '#include <aws/core/VersionConfig.h>\nAWS_SDK_VERSION_STRING' | $CPP $CPPFLAGS - | grep -v '^#.*' | sed 's/"//g' | tr '.' ' '))-  AC_DEFINE_UNQUOTED([AWS_VERSION_MAJOR], ${aws_version_tokens@<:@0@:>@}, [Major version of aws-sdk-cpp.])-  AC_DEFINE_UNQUOTED([AWS_VERSION_MINOR], ${aws_version_tokens@<:@1@:>@}, [Minor version of aws-sdk-cpp.])-fi---# Whether to use the Boehm garbage collector.-AC_ARG_ENABLE(gc, AC_HELP_STRING([--enable-gc],-  [enable garbage collection in the Nix expression evaluator (requires Boehm GC) [default=no]]),-  gc=$enableval, gc=no)-if test "$gc" = yes; then-  PKG_CHECK_MODULES([BDW_GC], [bdw-gc])-  CXXFLAGS="$BDW_GC_CFLAGS $CXXFLAGS"-  AC_DEFINE(HAVE_BOEHMGC, 1, [Whether to use the Boehm garbage collector.])-fi---AC_ARG_ENABLE(init-state, AC_HELP_STRING([--disable-init-state],-  [do not initialise DB etc. in `make install']),-  init_state=$enableval, init_state=yes)-#AM_CONDITIONAL(INIT_STATE, test "$init_state" = "yes")---# documentation generation switch-AC_ARG_ENABLE(doc-gen, AC_HELP_STRING([--disable-doc-gen],-  [disable documentation generation]),-  doc_generate=$enableval, doc_generate=yes)-AC_SUBST(doc_generate)---# Setuid installations.-AC_CHECK_FUNCS([setresuid setreuid lchown])---# Nice to have, but not essential.-AC_CHECK_FUNCS([strsignal posix_fallocate sysconf])---# This is needed if bzip2 is a static library, and the Nix libraries-# are dynamic.-if test "$(uname)" = "Darwin"; then-    LDFLAGS="-all_load $LDFLAGS"-fi---# Figure out the extension of dynamic libraries.-eval dynlib_suffix=$shrext_cmds-AC_SUBST(dynlib_suffix)---# Do we have GNU tar?-AC_MSG_CHECKING([if you have a recent GNU tar])-if $tar --version 2> /dev/null | grep -q GNU && tar cvf /dev/null --warning=no-timestamp ./config.log > /dev/null; then-    AC_MSG_RESULT(yes)-    tarFlags="--warning=no-timestamp"-else-    AC_MSG_RESULT(no)-fi-AC_SUBST(tarFlags)---AC_ARG_WITH(sandbox-shell, AC_HELP_STRING([--with-sandbox-shell=PATH],-  [path of a statically-linked shell to use as /bin/sh in sandboxes]),-  sandbox_shell=$withval)-AC_SUBST(sandbox_shell)---# Expand all variables in config.status.-test "$prefix" = NONE && prefix=$ac_default_prefix-test "$exec_prefix" = NONE && exec_prefix='${prefix}'-for name in $ac_subst_vars; do-    declare $name="$(eval echo "${!name}")"-    declare $name="$(eval echo "${!name}")"-    declare $name="$(eval echo "${!name}")"-done--rm -f Makefile.config--AC_CONFIG_HEADER([config.h])-AC_CONFIG_FILES([])-AC_OUTPUT
− data/nix/corepkgs/buildenv.nix
@@ -1,25 +0,0 @@-{ derivations, manifest }:--derivation {-  name = "user-environment";-  system = "builtin";-  builder = "builtin:buildenv";--  inherit manifest;--  # !!! grmbl, need structured data for passing this in a clean way.-  derivations =-    map (d:-      [ (d.meta.active or "true")-        (d.meta.priority or 5)-        (builtins.length d.outputs)-      ] ++ map (output: builtins.getAttr output d) d.outputs)-      derivations;--  # Building user environments remotely just causes huge amounts of-  # network traffic, so don't do that.-  preferLocalBuild = true;--  # Also don't bother substituting.-  allowSubstitutes = false;-}
− data/nix/corepkgs/config.nix.in
@@ -1,29 +0,0 @@-let-  fromEnv = var: def:-    let val = builtins.getEnv var; in-    if val != "" then val else def;-in rec {-  shell = "@bash@";-  coreutils = "@coreutils@";-  bzip2 = "@bzip2@";-  gzip = "@gzip@";-  xz = "@xz@";-  tar = "@tar@";-  tarFlags = "@tarFlags@";-  tr = "@tr@";-  nixBinDir = fromEnv "NIX_BIN_DIR" "@bindir@";-  nixPrefix = "@prefix@";-  nixLibexecDir = fromEnv "NIX_LIBEXEC_DIR" "@libexecdir@";-  nixLocalstateDir = "@localstatedir@";-  nixSysconfDir = "@sysconfdir@";-  nixStoreDir = fromEnv "NIX_STORE_DIR" "@storedir@";--  # If Nix is installed in the Nix store, then automatically add it as-  # a dependency to the core packages. This ensures that they work-  # properly in a chroot.-  chrootDeps =-    if dirOf nixPrefix == builtins.storeDir then-      [ (builtins.storePath nixPrefix) ]-    else-      [ ];-}
− data/nix/corepkgs/derivation.nix
@@ -1,27 +0,0 @@-/* 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
− data/nix/corepkgs/fetchurl.nix
@@ -1,37 +0,0 @@-{ system ? "" # obsolete-, url-, md5 ? "", sha1 ? "", sha256 ? "", sha512 ? ""-, outputHash ?-    if sha512 != "" then sha512 else if sha1 != "" then sha1 else if md5 != "" then md5 else sha256-, outputHashAlgo ?-    if sha512 != "" then "sha512" else if sha1 != "" then "sha1" else if md5 != "" then "md5" else "sha256"-, executable ? false-, unpack ? false-, name ? baseNameOf (toString url)-}:--derivation {-  builder = "builtin:fetchurl";--  # New-style output content requirements.-  inherit outputHashAlgo outputHash;-  outputHashMode = if unpack || executable then "recursive" else "flat";--  inherit name url executable unpack;--  system = "builtin";--  # No need to double the amount of network traffic-  preferLocalBuild = true;--  impureEnvVars = [-    # We borrow these environment variables from the caller to allow-    # easy proxy configuration.  This is impure, but a fixed-output-    # derivation like fetchurl is allowed to do so since its result is-    # by definition pure.-    "http_proxy" "https_proxy" "ftp_proxy" "all_proxy" "no_proxy"-  ];--  # To make "nix-prefetch-url" work.-  urls = [ url ];-}
− data/nix/corepkgs/imported-drv-to-derivation.nix
@@ -1,21 +0,0 @@-attrs @ { drvPath, outputs, name, ... }:--let--  commonAttrs = (builtins.listToAttrs outputsList) //-    { all = map (x: x.value) outputsList;-      inherit drvPath name;-      type = "derivation";-    };--  outputToAttrListElement = outputName:-    { name = outputName;-      value = commonAttrs // {-        outPath = builtins.getAttr outputName attrs;-        inherit outputName;-      };-    };-    -  outputsList = map outputToAttrListElement outputs;-    -in (builtins.head outputsList).value
− data/nix/corepkgs/local.mk
@@ -1,5 +0,0 @@-corepkgs_FILES = buildenv.nix unpack-channel.nix derivation.nix fetchurl.nix imported-drv-to-derivation.nix--$(foreach file,config.nix $(corepkgs_FILES),$(eval $(call install-data-in,$(d)/$(file),$(datadir)/nix/corepkgs)))--template-files += $(d)/config.nix
− data/nix/corepkgs/unpack-channel.nix
@@ -1,43 +0,0 @@-with import <nix/config.nix>;--let--  builder = builtins.toFile "unpack-channel.sh"-    ''-      mkdir $out-      cd $out-      xzpat="\.xz\$"-      gzpat="\.gz\$"-      if [[ "$src" =~ $xzpat ]]; then-        ${xz} -d < $src | ${tar} xf - ${tarFlags}-      elif [[ "$src" =~ $gzpat ]]; then-        ${gzip} -d < $src | ${tar} xf - ${tarFlags}-      else-        ${bzip2} -d < $src | ${tar} xf - ${tarFlags}-      fi-      if [ * != $channelName ]; then-        mv * $out/$channelName-      fi-      if [ -n "$binaryCacheURL" ]; then-        mkdir $out/binary-caches-        echo -n "$binaryCacheURL" > $out/binary-caches/$channelName-      fi-    '';--in--{ name, channelName, src, binaryCacheURL ? "" }:--derivation {-  system = builtins.currentSystem;-  builder = shell;-  args = [ "-e" builder ];-  inherit name channelName src binaryCacheURL;--  PATH = "${nixBinDir}:${coreutils}";--  # No point in doing this remotely.-  preferLocalBuild = true;--  inherit chrootDeps;-}
− data/nix/local.mk
@@ -1,12 +0,0 @@-ifeq ($(MAKECMDGOALS), dist)-  dist-files += $(shell cat .dist-files)-endif--dist-files += configure config.h.in nix.spec perl/configure--clean-files += Makefile.config--GLOBAL_CXXFLAGS += -I . -I src -I src/libutil -I src/libstore -I src/libmain -I src/libexpr--$(foreach i, config.h $(call rwildcard, src/lib*, *.hh), \-  $(eval $(call install-file-in, $(i), $(includedir)/nix, 0644)))
− data/nix/maintainers/upload-release.pl
@@ -1,160 +0,0 @@-#! /usr/bin/env nix-shell-#! nix-shell -i perl -p perl perlPackages.LWPUserAgent perlPackages.LWPProtocolHttps perlPackages.FileSlurp gnupg1--use strict;-use Data::Dumper;-use File::Basename;-use File::Path;-use File::Slurp;-use File::Copy;-use JSON::PP;-use LWP::UserAgent;--my $evalId = $ARGV[0] or die "Usage: $0 EVAL-ID\n";--my $releasesDir = "/home/eelco/mnt/releases";-my $nixpkgsDir = "/home/eelco/Dev/nixpkgs-pristine";--# FIXME: cut&paste from nixos-channel-scripts.-sub fetch {-    my ($url, $type) = @_;--    my $ua = LWP::UserAgent->new;-    $ua->default_header('Accept', $type) if defined $type;--    my $response = $ua->get($url);-    die "could not download $url: ", $response->status_line, "\n" unless $response->is_success;--    return $response->decoded_content;-}--my $evalUrl = "https://hydra.nixos.org/eval/$evalId";-my $evalInfo = decode_json(fetch($evalUrl, 'application/json'));-#print Dumper($evalInfo);--my $nixRev = $evalInfo->{jobsetevalinputs}->{nix}->{revision} or die;--my $tarballInfo = decode_json(fetch("$evalUrl/job/tarball", 'application/json'));--my $releaseName = $tarballInfo->{releasename};-$releaseName =~ /nix-(.*)$/ or die;-my $version = $1;--print STDERR "Nix revision is $nixRev, version is $version\n";--File::Path::make_path($releasesDir);-if (system("mountpoint -q $releasesDir") != 0) {-    system("sshfs hydra-mirror:/releases $releasesDir") == 0 or die;-}--my $releaseDir = "$releasesDir/nix/$releaseName";-File::Path::make_path($releaseDir);--sub downloadFile {-    my ($jobName, $productNr, $dstName) = @_;--    my $buildInfo = decode_json(fetch("$evalUrl/job/$jobName", 'application/json'));--    my $srcFile = $buildInfo->{buildproducts}->{$productNr}->{path} or die "job '$jobName' lacks product $productNr\n";-    $dstName //= basename($srcFile);-    my $dstFile = "$releaseDir/" . $dstName;--    if (! -e $dstFile) {-        print STDERR "downloading $srcFile to $dstFile...\n";-        system("NIX_REMOTE=https://cache.nixos.org/ nix cat-store '$srcFile' > '$dstFile.tmp'") == 0-            or die "unable to fetch $srcFile\n";-        rename("$dstFile.tmp", $dstFile) or die;-    }--    my $sha256_expected = $buildInfo->{buildproducts}->{$productNr}->{sha256hash} or die;-    my $sha256_actual = `nix hash-file --type sha256 '$dstFile'`;-    chomp $sha256_actual;-    if ($sha256_expected ne $sha256_actual) {-        print STDERR "file $dstFile is corrupt\n";-        exit 1;-    }--    write_file("$dstFile.sha256", $sha256_expected);--    return ($dstFile, $sha256_expected);-}--downloadFile("tarball", "2"); # .tar.bz2-my ($tarball, $tarballHash) = downloadFile("tarball", "3"); # .tar.xz-my ($tarball_i686_linux, $tarball_i686_linux_hash) = downloadFile("binaryTarball.i686-linux", "1");-my ($tarball_x86_64_linux, $tarball_x86_64_linux_hash) = downloadFile("binaryTarball.x86_64-linux", "1");-my ($tarball_aarch64_linux, $tarball_aarch64_linux_hash) = downloadFile("binaryTarball.aarch64-linux", "1");-my ($tarball_x86_64_darwin, $tarball_x86_64_darwin_hash) = downloadFile("binaryTarball.x86_64-darwin", "1");--# Update Nixpkgs in a very hacky way.-system("cd $nixpkgsDir && git pull") == 0 or die;-my $oldName = `nix-instantiate --eval $nixpkgsDir -A nix.name`; chomp $oldName;-my $oldHash = `nix-instantiate --eval $nixpkgsDir -A nix.src.outputHash`; chomp $oldHash;-print STDERR "old stable version in Nixpkgs = $oldName / $oldHash\n";--my $fn = "$nixpkgsDir/pkgs/tools/package-management/nix/default.nix";-my $oldFile = read_file($fn);-$oldFile =~ s/$oldName/"$releaseName"/g;-$oldFile =~ s/$oldHash/"$tarballHash"/g;-write_file($fn, $oldFile);--$oldName =~ s/nix-//g;-$oldName =~ s/"//g;--sub getStorePath {-    my ($jobName) = @_;-    my $buildInfo = decode_json(fetch("$evalUrl/job/$jobName", 'application/json'));-    die unless $buildInfo->{buildproducts}->{1}->{type} eq "nix-build";-    return $buildInfo->{buildproducts}->{1}->{path};-}--write_file("$nixpkgsDir/nixos/modules/installer/tools/nix-fallback-paths.nix",-           "{\n" .-           "  x86_64-linux = \"" . getStorePath("build.x86_64-linux") . "\";\n" .-           "  i686-linux = \"" . getStorePath("build.i686-linux") . "\";\n" .-           "  aarch64-linux = \"" . getStorePath("build.aarch64-linux") . "\";\n" .-           "  x86_64-darwin = \"" . getStorePath("build.x86_64-darwin") . "\";\n" .-           "}\n");--system("cd $nixpkgsDir && git commit -a -m 'nix: $oldName -> $version'") == 0 or die;--# Extract the HTML manual.-File::Path::make_path("$releaseDir/manual");--system("tar xvf $tarball --strip-components=3 -C $releaseDir/manual --wildcards '*/doc/manual/*.html' '*/doc/manual/*.css' '*/doc/manual/*.gif' '*/doc/manual/*.png'") == 0 or die;--if (! -e "$releaseDir/manual/index.html") {-    symlink("manual.html", "$releaseDir/manual/index.html") or die;-}--# Update the "latest" symlink.-symlink("$releaseName", "$releasesDir/nix/latest-tmp") or die;-rename("$releasesDir/nix/latest-tmp", "$releasesDir/nix/latest") or die;--# Tag the release in Git.-chdir("/home/eelco/Dev/nix-pristine") or die;-system("git remote update origin") == 0 or die;-system("git tag --force --sign $version $nixRev -m 'Tagging release $version'") == 0 or die;--# Update the website.-my $siteDir = "/home/eelco/Dev/nixos-homepage-pristine";--system("cd $siteDir && git pull") == 0 or die;--write_file("$siteDir/nix-release.tt",-           "[%-\n" .-           "latestNixVersion = \"$version\"\n" .-           "nix_hash_i686_linux = \"$tarball_i686_linux_hash\"\n" .-           "nix_hash_x86_64_linux = \"$tarball_x86_64_linux_hash\"\n" .-           "nix_hash_aarch64_linux = \"$tarball_aarch64_linux_hash\"\n" .-           "nix_hash_x86_64_darwin = \"$tarball_x86_64_darwin_hash\"\n" .-           "-%]\n");--system("cd $siteDir && nix-shell --run 'make nix/install nix/install.sig'") == 0 or die;--copy("$siteDir/nix/install", "$siteDir/nix/install-$version") or die;-copy("$siteDir/nix/install.sig", "$siteDir/nix/install-$version.sig") or die;--system("cd $siteDir && git add nix/install-$version nix/install-$version.sig") == 0 or die;--system("cd $siteDir && git commit -a -m 'Nix $version released'") == 0 or die;
− data/nix/mk/README.md
@@ -1,6 +0,0 @@-This is a set of helper Makefiles for doing non-recursive builds with-GNU Make.  The canonical source can be found at-https://github.com/edolstra/make-rules.  You should copy the files-into the `mk` subdirectory of your project.--TODO: write more documentation.
− data/nix/mk/clean.mk
@@ -1,11 +0,0 @@-clean-files :=--clean:-	$(suppress) rm -fv -- $(clean-files)--dryclean:-	@for i in $(clean-files); do if [ -e $$i ]; then echo $$i; fi; done | sort--print-top-help += \-  echo "  clean: Delete generated files"; \-  echo "  dryclean: Show what files would be deleted by 'make clean'";
− data/nix/mk/dist.mk
@@ -1,17 +0,0 @@-ifdef PACKAGE_NAME--dist-name = $(PACKAGE_NAME)-$(PACKAGE_VERSION)--dist: $(dist-name).tar.bz2 $(dist-name).tar.xz--$(dist-name).tar.bz2: $(dist-files)-	$(trace-gen) tar cfj $@ $(sort $(dist-files)) --transform 's,^,$(dist-name)/,'--$(dist-name).tar.xz: $(dist-files)-	$(trace-gen) tar cfJ $@ $(sort $(dist-files)) --transform 's,^,$(dist-name)/,'--clean-files += $(dist-name).tar.bz2 $(dist-name).tar.xz--print-top-help += echo "  dist: Generate a source distribution";--endif
− data/nix/mk/functions.mk
@@ -1,14 +0,0 @@-# Utility function for recursively finding files, e.g.-# ‘$(call rwildcard, path/to/dir, *.c *.h)’.-rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))--# Given a file name, produce the corresponding dependency file-# (e.g. ‘foo/bar.o’ becomes ‘foo/.bar.o.dep’).-filename-to-dep = $(dir $1).$(notdir $1).dep--# Return the full path to a program by looking it up in $PATH, or the-# empty string if not found.-find-program = $(shell for i in $$(IFS=: ; echo $$PATH); do p=$$i/$(strip $1); if [ -e $$p ]; then echo $$p; break; fi; done)--# Ensure that the given string ends in a single slash.-add-trailing-slash = $(patsubst %/,%,$(1))/
− data/nix/mk/install.mk
@@ -1,62 +0,0 @@-# Add a rule for creating $(1) as a directory.  This template may be-# called multiple times for the same directory.-define create-dir-   _i := $$(call add-trailing-slash, $(DESTDIR)$$(strip $(1)))-  ifndef $$(_i)_SEEN-    $$(_i)_SEEN = 1-    $$(_i):-	$$(trace-mkdir) install -d "$$@"-  endif-endef---# Add a rule for installing file $(1) as file $(2) with mode $(3).-# The directory containing $(2) will be created automatically.-define install-file-as--  _i := $(DESTDIR)$$(strip $(2))--  install: $$(_i)--  $$(_i): $(1) | $$(dir $$(_i))-	$$(trace-install) install -m $(3) $(1) "$$@"--  $$(eval $$(call create-dir, $$(dir $(2))))--endef---# Add a rule for installing file $(1) in directory $(2) with mode-# $(3).  The directory will be created automatically.-define install-file-in-  $$(eval $$(call install-file-as,$(1),$(2)/$$(notdir $(1)),$(3)))-endef---define install-program-in-  $$(eval $$(call install-file-in,$(1),$(2),0755))-endef---define install-data-in-  $$(eval $$(call install-file-in,$(1),$(2),0644))-endef---# Install a symlink from $(2) to $(1).  Note that $(1) need not exist.-define install-symlink--  _i := $(DESTDIR)$$(strip $(2))--  install: $$(_i)--  $$(_i): | $$(dir $$(_i))-	$$(trace-install) ln -sfn $(1) "$$@"--  $$(eval $$(call create-dir, $$(dir $(2))))--endef---print-top-help += \-  echo "  install: Install into \$$(prefix) (currently set to '$(prefix)')";
− data/nix/mk/jars.mk
@@ -1,36 +0,0 @@-define build-jar--  $(1)_NAME ?= $(1)--  _d := $$(strip $$($(1)_DIR))--  $(1)_PATH := $$(_d)/$$($(1)_NAME).jar--  $(1)_TMPDIR := $$(_d)/.$$($(1)_NAME).jar.tmp--  _jars := $$(foreach jar, $$($(1)_JARS), $$($$(jar)_PATH))--  $$($(1)_PATH): $$($(1)_SOURCES) $$(_jars) $$($(1)_EXTRA_DEPS)| $$($(1)_ORDER_AFTER)-	@rm -rf $$($(1)_TMPDIR)-	@mkdir -p $$($(1)_TMPDIR)-	$$(trace-javac) javac $(GLOBAL_JAVACFLAGS) $$($(1)_JAVACFLAGS) -d $$($(1)_TMPDIR) \-	  $$(foreach fn, $$($(1)_SOURCES), '$$(fn)') \-	  -cp "$$(subst $$(space),,$$(foreach jar,$$($(1)_JARS),$$($$(jar)_PATH):))$$$$CLASSPATH"-	@echo -e '$$(subst $$(newline),\n,$$($(1)_MANIFEST))' > $$($(1)_PATH).manifest-	$$(trace-jar) jar cfm $$($(1)_PATH) $$($(1)_PATH).manifest -C $$($(1)_TMPDIR) .-	@rm $$($(1)_PATH).manifest-	@rm -rf $$($(1)_TMPDIR)--  $(1)_INSTALL_DIR ?= $$(jardir)--  $(1)_INSTALL_PATH := $$($(1)_INSTALL_DIR)/$$($(1)_NAME).jar--  $$(eval $$(call install-file-as, $$($(1)_PATH), $$($(1)_INSTALL_PATH), 0644))--  install: $$($(1)_INSTALL_PATH)--  jars-list += $$($(1)_PATH)--  clean-files += $$($(1)_PATH)--endef
− data/nix/mk/lib.mk
@@ -1,160 +0,0 @@-default: all---# Get rid of default suffixes. FIXME: is this a good idea?-.SUFFIXES:---# Initialise some variables.-bin-scripts :=-noinst-scripts :=-man-pages :=-install-tests :=-dist-files :=-OS = $(shell uname -s)---# Hack to define a literal space.-space :=-space +=---# Hack to define a literal newline.-define newline---endef---# Default installation paths.-prefix ?= /usr/local-libdir ?= $(prefix)/lib-bindir ?= $(prefix)/bin-libexecdir ?= $(prefix)/libexec-datadir ?= $(prefix)/share-jardir ?= $(datadir)/java-localstatedir ?= $(prefix)/var-sysconfdir ?= $(prefix)/etc-mandir ?= $(prefix)/share/man---# Initialise support for build directories.-builddir ?=--ifdef builddir-  buildprefix = $(builddir)/-else-  buildprefix =-endif---# Pass -fPIC if we're building dynamic libraries.-BUILD_SHARED_LIBS ?= 1--ifeq ($(BUILD_SHARED_LIBS), 1)-  ifeq (CYGWIN,$(findstring CYGWIN,$(OS)))-    GLOBAL_CFLAGS += -U__STRICT_ANSI__ -D_GNU_SOURCE-    GLOBAL_CXXFLAGS += -U__STRICT_ANSI__ -D_GNU_SOURCE-  else-    GLOBAL_CFLAGS += -fPIC-    GLOBAL_CXXFLAGS += -fPIC-  endif-  ifneq ($(OS), Darwin)-   ifneq ($(OS), SunOS)-    ifneq ($(OS), FreeBSD)-     GLOBAL_LDFLAGS += -Wl,--no-copy-dt-needed-entries-    endif-   endif-  endif-  SET_RPATH_TO_LIBS ?= 1-endif--# Pass -g if we want debug info.-BUILD_DEBUG ?= 1--ifeq ($(BUILD_DEBUG), 1)-  GLOBAL_CFLAGS += -g-  GLOBAL_CXXFLAGS += -g-  GLOBAL_JAVACFLAGS += -g-endif---include mk/functions.mk-include mk/tracing.mk-include mk/clean.mk-include mk/install.mk-include mk/libraries.mk-include mk/programs.mk-include mk/jars.mk-include mk/patterns.mk-include mk/templates.mk-include mk/tests.mk---# Include all sub-Makefiles.-define include-sub-makefile-  d := $$(patsubst %/,%,$$(dir $(1)))-  include $(1)-endef--$(foreach mf, $(makefiles), $(eval $(call include-sub-makefile, $(mf))))---# Instantiate stuff.-$(foreach lib, $(libraries), $(eval $(call build-library,$(lib))))-$(foreach prog, $(programs), $(eval $(call build-program,$(prog))))-$(foreach jar, $(jars), $(eval $(call build-jar,$(jar))))-$(foreach script, $(bin-scripts), $(eval $(call install-program-in,$(script),$(bindir))))-$(foreach script, $(bin-scripts), $(eval programs-list += $(script)))-$(foreach script, $(noinst-scripts), $(eval programs-list += $(script)))-$(foreach template, $(template-files), $(eval $(call instantiate-template,$(template))))-$(foreach test, $(install-tests), $(eval $(call run-install-test,$(test))))-$(foreach file, $(man-pages), $(eval $(call install-data-in, $(file), $(mandir)/man$(patsubst .%,%,$(suffix $(file))))))---include mk/dist.mk---.PHONY: default all man help--all: $(programs-list) $(libs-list) $(jars-list) $(man-pages)--man: $(man-pages)---help:-	@echo "The following targets are available:"-	@echo ""-	@echo "  default: Build default targets"-ifdef man-pages-	@echo "  man: Generate manual pages"-endif-	@$(print-top-help)-ifdef programs-list-	@echo ""-	@echo "The following programs can be built:"-	@echo ""-	@for i in $(programs-list); do echo "  $$i"; done-endif-ifdef libs-list-	@echo ""-	@echo "The following libraries can be built:"-	@echo ""-	@for i in $(libs-list); do echo "  $$i"; done-endif-ifdef jars-list-	@echo ""-	@echo "The following JARs can be built:"-	@echo ""-	@for i in $(jars-list); do echo "  $$i"; done-endif-	@echo ""-	@echo "The following variables control the build:"-	@echo ""-	@echo "  BUILD_SHARED_LIBS ($(BUILD_SHARED_LIBS)): Whether to build shared libraries"-	@echo "  BUILD_DEBUG ($(BUILD_DEBUG)): Whether to include debug symbols"-	@echo "  CC ($(CC)): C compiler to be used"-	@echo "  CFLAGS: Flags for the C compiler"-	@echo "  CXX ($(CXX)): C++ compiler to be used"-	@echo "  CXXFLAGS: Flags for the C++ compiler"-	@$(print-var-help)
− data/nix/mk/libraries.mk
@@ -1,162 +0,0 @@-libs-list :=--ifeq ($(OS), Darwin)-  SO_EXT = dylib-else-  ifeq (CYGWIN,$(findstring CYGWIN,$(OS)))-    SO_EXT = dll-  else-    SO_EXT = so-  endif-endif--# Build a library with symbolic name $(1).  The library is defined by-# various variables prefixed by ‘$(1)_’:-#-# - $(1)_NAME: the name of the library (e.g. ‘libfoo’); defaults to-#   $(1).-#-# - $(1)_DIR: the directory where the (non-installed) library will be-#   placed.-#-# - $(1)_SOURCES: the source files of the library.-#-# - $(1)_CFLAGS: additional C compiler flags.-#-# - $(1)_CXXFLAGS: additional C++ compiler flags.-#-# - $(1)_ORDER_AFTER: a set of targets on which the object files of-#   this libraries will have an order-only dependency.-#-# - $(1)_LIBS: the symbolic names of other libraries on which this-#   library depends.-#-# - $(1)_ALLOW_UNDEFINED: if set, the library is allowed to have-#   undefined symbols.  Has no effect for static libraries.-#-# - $(1)_LDFLAGS: additional linker flags.-#-# - $(1)_LDFLAGS_PROPAGATED: additional linker flags, also propagated-#   to the linking of programs/libraries that use this library.-#-# - $(1)_FORCE_INSTALL: if defined, the library will be installed even-#   if it's not needed (i.e. dynamically linked) by a program.-#-# - $(1)_INSTALL_DIR: the directory where the library will be-#   installed.  Defaults to $(libdir).-#-# - $(1)_EXCLUDE_FROM_LIBRARY_LIST: if defined, the library will not-#   be automatically marked as a dependency of the top-level all-#   target andwill not be listed in the make help output. This is-#   useful for libraries built solely for testing, for example.-#-# - BUILD_SHARED_LIBS: if equal to ‘1’, a dynamic library will be-#   built, otherwise a static library.-define build-library-  $(1)_NAME ?= $(1)-  _d := $(buildprefix)$$(strip $$($(1)_DIR))-  _srcs := $$(sort $$(foreach src, $$($(1)_SOURCES), $$(src)))-  $(1)_OBJS := $$(addprefix $(buildprefix), $$(addsuffix .o, $$(basename $$(_srcs))))-  _libs := $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_PATH))--  ifeq (CYGWIN,$(findstring CYGWIN,$(OS)))-    $(1)_INSTALL_DIR ?= $$(bindir)-  else-    $(1)_INSTALL_DIR ?= $$(libdir)-  endif--  $(1)_LDFLAGS_USE :=-  $(1)_LDFLAGS_USE_INSTALLED :=--  $$(eval $$(call create-dir, $$(_d)))--  ifeq ($(BUILD_SHARED_LIBS), 1)--    ifdef $(1)_ALLOW_UNDEFINED-      ifeq ($(OS), Darwin)-        $(1)_LDFLAGS += -undefined suppress -flat_namespace-      endif-    else-      ifneq ($(OS), Darwin)-        ifneq (CYGWIN,$(findstring CYGWIN,$(OS)))-          $(1)_LDFLAGS += -Wl,-z,defs-        endif-      endif-    endif--    ifneq ($(OS), Darwin)-      $(1)_LDFLAGS += -Wl,-soname=$$($(1)_NAME).$(SO_EXT)-    endif--    $(1)_PATH := $$(_d)/$$($(1)_NAME).$(SO_EXT)--    $$($(1)_PATH): $$($(1)_OBJS) $$(_libs) | $$(_d)/-	$$(trace-ld) $(CXX) -o $$(abspath $$@) -shared $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE)) $$($(1)_LDFLAGS_UNINSTALLED)--    ifneq ($(OS), Darwin)-      $(1)_LDFLAGS_USE += -Wl,-rpath,$$(abspath $$(_d))-    endif-    $(1)_LDFLAGS_USE += -L$$(_d) -l$$(patsubst lib%,%,$$(strip $$($(1)_NAME)))--    $(1)_INSTALL_PATH := $(DESTDIR)$$($(1)_INSTALL_DIR)/$$($(1)_NAME).$(SO_EXT)--    _libs_final := $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_INSTALL_PATH))--    $$(eval $$(call create-dir, $$($(1)_INSTALL_DIR)))--    $$($(1)_INSTALL_PATH): $$($(1)_OBJS) $$(_libs_final) | $(DESTDIR)$$($(1)_INSTALL_DIR)/-	$$(trace-ld) $(CXX) -o $$@ -shared $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE_INSTALLED))--    $(1)_LDFLAGS_USE_INSTALLED += -L$$(DESTDIR)$$($(1)_INSTALL_DIR) -l$$(patsubst lib%,%,$$(strip $$($(1)_NAME)))-    ifneq ($(OS), Darwin)-      ifeq ($(SET_RPATH_TO_LIBS), 1)-        $(1)_LDFLAGS_USE_INSTALLED += -Wl,-rpath,$$($(1)_INSTALL_DIR)-      else-        $(1)_LDFLAGS_USE_INSTALLED += -Wl,-rpath-link,$$($(1)_INSTALL_DIR)-      endif-    endif--    ifdef $(1)_FORCE_INSTALL-      install: $$($(1)_INSTALL_PATH)-    endif--  else--    $(1)_PATH := $$(_d)/$$($(1)_NAME).a--    $$($(1)_PATH): $$($(1)_OBJS) | $$(_d)/-	$(trace-ar) ar crs $$@ $$?--    $(1)_LDFLAGS_USE += $$($(1)_PATH) $$($(1)_LDFLAGS)--    $(1)_INSTALL_PATH := $$(libdir)/$$($(1)_NAME).a--  endif--  $(1)_LDFLAGS_USE += $$($(1)_LDFLAGS_PROPAGATED)-  $(1)_LDFLAGS_USE_INSTALLED += $$($(1)_LDFLAGS_PROPAGATED)--  # Propagate CFLAGS and CXXFLAGS to the individual object files.-  $$(foreach obj, $$($(1)_OBJS), $$(eval $$(obj)_CFLAGS=$$($(1)_CFLAGS)))-  $$(foreach obj, $$($(1)_OBJS), $$(eval $$(obj)_CXXFLAGS=$$($(1)_CXXFLAGS)))--  # Make each object file depend on the common dependencies.-  $$(foreach obj, $$($(1)_OBJS), $$(eval $$(obj): $$($(1)_COMMON_DEPS) $$(GLOBAL_COMMON_DEPS)))--  # Make each object file have order-only dependencies on the common-  # order-only dependencies. This includes the order-only dependencies-  # of libraries we're depending on.-  $(1)_ORDER_AFTER_CLOSED = $$($(1)_ORDER_AFTER) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_ORDER_AFTER_CLOSED))--  $$(foreach obj, $$($(1)_OBJS), $$(eval $$(obj): | $$($(1)_ORDER_AFTER_CLOSED) $$(GLOBAL_ORDER_AFTER)))--  # Include .dep files, if they exist.-  $(1)_DEPS := $$(foreach fn, $$($(1)_OBJS), $$(call filename-to-dep, $$(fn)))-  -include $$($(1)_DEPS)--  ifndef $(1)_EXCLUDE_FROM_LIBRARY_LIST-  libs-list += $$($(1)_PATH)-  endif-  clean-files += $$(_d)/*.a $$(_d)/*.$(SO_EXT) $$(_d)/*.o $$(_d)/.*.dep $$($(1)_DEPS) $$($(1)_OBJS)-  dist-files += $$(_srcs)-endef
− data/nix/mk/patterns.mk
@@ -1,11 +0,0 @@-$(buildprefix)%.o: %.cc-	@mkdir -p "$(dir $@)"-	$(trace-cxx) $(CXX) -o $@ -c $< $(GLOBAL_CXXFLAGS) $(GLOBAL_CXXFLAGS_PCH) $(CXXFLAGS) $($@_CXXFLAGS) -MMD -MF $(call filename-to-dep, $@) -MP--$(buildprefix)%.o: %.cpp-	@mkdir -p "$(dir $@)"-	$(trace-cxx) $(CXX) -o $@ -c $< $(GLOBAL_CXXFLAGS) $(GLOBAL_CXXFLAGS_PCH) $(CXXFLAGS) $($@_CXXFLAGS) -MMD -MF $(call filename-to-dep, $@) -MP--$(buildprefix)%.o: %.c-	@mkdir -p "$(dir $@)"-	$(trace-cc) $(CC) -o $@ -c $< $(GLOBAL_CFLAGS) $(CFLAGS) $($@_CFLAGS) -MMD -MF $(call filename-to-dep, $@) -MP
− data/nix/mk/programs.mk
@@ -1,79 +0,0 @@-programs-list :=--# Build a program with symbolic name $(1).  The program is defined by-# various variables prefixed by ‘$(1)_’:-#-# - $(1)_DIR: the directory where the (non-installed) program will be-#   placed.-#-# - $(1)_SOURCES: the source files of the program.-#-# - $(1)_CFLAGS: additional C compiler flags.-#-# - $(1)_CXXFLAGS: additional C++ compiler flags.-#-# - $(1)_ORDER_AFTER: a set of targets on which the object files of-#   this program will have an order-only dependency.-#-# - $(1)_LIBS: the symbolic names of libraries on which this program-#   depends.-#-# - $(1)_LDFLAGS: additional linker flags.-#-# - $(1)_INSTALL_DIR: the directory where the program will be-#   installed; defaults to $(bindir).-define build-program-  _d := $(buildprefix)$$($(1)_DIR)-  _srcs := $$(sort $$(foreach src, $$($(1)_SOURCES), $$(src)))-  $(1)_OBJS := $$(addprefix $(buildprefix), $$(addsuffix .o, $$(basename $$(_srcs))))-  _libs := $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_PATH))-  $(1)_PATH := $$(_d)/$(1)--  $$(eval $$(call create-dir, $$(_d)))--  $$($(1)_PATH): $$($(1)_OBJS) $$(_libs) | $$(_d)/-	$$(trace-ld) $(CXX) -o $$@ $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE))--  $(1)_INSTALL_DIR ?= $$(bindir)-  $(1)_INSTALL_PATH := $$($(1)_INSTALL_DIR)/$(1)--  $$(eval $$(call create-dir, $$($(1)_INSTALL_DIR)))--  install: $(DESTDIR)$$($(1)_INSTALL_PATH)--  ifeq ($(BUILD_SHARED_LIBS), 1)--    _libs_final := $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_INSTALL_PATH))--    $(DESTDIR)$$($(1)_INSTALL_PATH): $$($(1)_OBJS) $$(_libs_final) | $(DESTDIR)$$($(1)_INSTALL_DIR)/-	$$(trace-ld) $(CXX) -o $$@ $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE_INSTALLED))--  else--    $(DESTDIR)$$($(1)_INSTALL_PATH): $$($(1)_PATH) | $(DESTDIR)$$($(1)_INSTALL_DIR)/-	install -t $(DESTDIR)$$($(1)_INSTALL_DIR) $$<--  endif--  # Propagate CFLAGS and CXXFLAGS to the individual object files.-  $$(foreach obj, $$($(1)_OBJS), $$(eval $$(obj)_CFLAGS=$$($(1)_CFLAGS)))-  $$(foreach obj, $$($(1)_OBJS), $$(eval $$(obj)_CXXFLAGS=$$($(1)_CXXFLAGS)))--  # Make each object file depend on the common dependencies.-  $$(foreach obj, $$($(1)_OBJS), $$(eval $$(obj): $$($(1)_COMMON_DEPS) $$(GLOBAL_COMMON_DEPS)))--  # Make each object file have order-only dependencies on the common-  # order-only dependencies. This includes the order-only dependencies-  # of libraries we're depending on.-  $(1)_ORDER_AFTER_CLOSED = $$($(1)_ORDER_AFTER) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_ORDER_AFTER_CLOSED))--  $$(foreach obj, $$($(1)_OBJS), $$(eval $$(obj): | $$($(1)_ORDER_AFTER_CLOSED) $$(GLOBAL_ORDER_AFTER)))--  # Include .dep files, if they exist.-  $(1)_DEPS := $$(foreach fn, $$($(1)_OBJS), $$(call filename-to-dep, $$(fn)))-  -include $$($(1)_DEPS)--  programs-list += $$($(1)_PATH)-  clean-files += $$($(1)_PATH) $$(_d)/*.o $$(_d)/.*.dep $$($(1)_DEPS) $$($(1)_OBJS)-  dist-files += $$(_srcs)-endef
− data/nix/mk/templates.mk
@@ -1,19 +0,0 @@-template-files :=--# Create the file $(1) from $(1).in by running config.status (which-# substitutes all ‘@var@’ variables set by the configure script).-define instantiate-template--  clean-files += $(1)--endef--ifneq ($(MAKECMDGOALS), clean)--%.h: %.h.in-	$(trace-gen) rm -f $@ && ./config.status --quiet --header=$@--%: %.in-	$(trace-gen) rm -f $@ && ./config.status --quiet --file=$@--endif
− data/nix/mk/tests.mk
@@ -1,45 +0,0 @@-# Run program $1 as part of ‘make installcheck’.-define run-install-test--  installcheck: $1--  _installcheck-list += $1--endef--# Color code from https://unix.stackexchange.com/a/10065-installcheck:-	@total=0; failed=0; \-	red=""; \-	green=""; \-	yellow=""; \-	normal=""; \-	if [ -t 1 ]; then \-		red="[31;1m"; \-		green="[32;1m"; \-		yellow="[33;1m"; \-		normal="[m"; \-	fi; \-	for i in $(_installcheck-list); do \-	  total=$$((total + 1)); \-	  printf "running test $$i..."; \-	  log="$$(cd $$(dirname $$i) && $(tests-environment) $$(basename $$i) 2>&1)"; \-	  status=$$?; \-	  if [ $$status -eq 0 ]; then \-	    echo " [$${green}PASS$$normal]"; \-	  elif [ $$status -eq 99 ]; then \-	    echo " [$${yellow}SKIP$$normal]"; \-	  else \-	    echo " [$${red}FAIL$$normal]"; \-	    echo "$$log" | sed 's/^/    /'; \-	    failed=$$((failed + 1)); \-	  fi; \-	done; \-	if [ "$$failed" != 0 ]; then \-	  echo "$${red}$$failed out of $$total tests failed $$normal"; \-	  exit 1; \-	else \-		echo "$${green}All tests succeeded$$normal"; \-	fi--.PHONY: check installcheck
− data/nix/mk/tracing.mk
@@ -1,17 +0,0 @@-V ?= 0--ifeq ($(V), 0)--  trace-gen     = @echo "  GEN   " $@;-  trace-cc      = @echo "  CC    " $@;-  trace-cxx     = @echo "  CXX   " $@;-  trace-ld      = @echo "  LD    " $@;-  trace-ar      = @echo "  AR    " $@;-  trace-install = @echo "  INST  " $@;-  trace-javac   = @echo "  JAVAC " $@;-  trace-jar     = @echo "  JAR   " $@;-  trace-mkdir   = @echo "  MKDIR " $@;--  suppress  = @--endif
− data/nix/nix.spec.in
@@ -1,154 +0,0 @@-%undefine _hardened_build--%global nixbld_user "nix-builder-"-%global nixbld_group "nixbld"--Summary: The Nix software deployment system-Name: nix-Version: @PACKAGE_VERSION@-Release: 2%{?dist}-License: LGPLv2+-%if 0%{?rhel} && 0%{?rhel} < 7-Group: Applications/System-%endif-URL: http://nixos.org/-Source0: %{name}-%{version}.tar.bz2-%if 0%{?el5}-BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)-%endif-Requires: curl-Requires: bzip2-Requires: gzip-Requires: xz-Requires: libseccomp-Requires: boost-context-BuildRequires: bzip2-devel-BuildRequires: sqlite-devel-BuildRequires: libcurl-devel-BuildRequires: libseccomp-devel-BuildRequires: boost-devel--# Hack to make that shitty RPM scanning hack shut up.-Provides: perl(Nix::SSH)--%description-Nix is a purely functional package manager. It allows multiple-versions of a package to be installed side-by-side, ensures that-dependency specifications are complete, supports atomic upgrades and-rollbacks, allows non-root users to install software, and has many-other features. It is the basis of the NixOS Linux distribution, but-it can be used equally well under other Unix systems.--%package        devel-Summary:        Development files for %{name}-%if 0%{?rhel} && 0%{?rhel} < 7-Group:          Development/Libraries-%endif-Requires:       %{name}%{?_isa} = %{version}-%{release}--%description   devel-The %{name}-devel package contains libraries and header files for-developing applications that use %{name}.---%package doc-Summary:        Documentation files for %{name}-%if 0%{?rhel} && 0%{?rhel} < 7-Group:          Documentation-%endif-BuildArch:      noarch-Requires:       %{name} = %{version}-%{release}--%description   doc-The %{name}-doc package contains documentation files for %{name}.--%prep-%setup -q---%build-extraFlags=-# - override docdir so large documentation files are owned by the-#   -doc subpackage-# - set localstatedir by hand to the preferred nix value-%configure --localstatedir=/nix/var \-           --docdir=%{_defaultdocdir}/%{name}-doc-%{version} \-           $extraFlags-make -j$NIX_BUILD_CORES -l$NIX_BUILD_CORES---%install-%if 0%{?el5}-rm -rf $RPM_BUILD_ROOT-%endif-make DESTDIR=$RPM_BUILD_ROOT install--find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'--# make the store-mkdir -p $RPM_BUILD_ROOT/nix/store-chmod 1775 $RPM_BUILD_ROOT/nix/store--# make per-user directories-for d in profiles gcroots;-do-  mkdir -p $RPM_BUILD_ROOT/nix/var/nix/$d/per-user-  chmod 1777 $RPM_BUILD_ROOT/nix/var/nix/$d/per-user-done--# fix permission of nix profile-# (until this is fixed in the relevant Makefile)-chmod -x $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/nix.sh--# we ship this file in the base package-rm -f $RPM_BUILD_ROOT%{_defaultdocdir}/%{name}-doc-%{version}/README--# Get rid of Upstart job.-rm -rf $RPM_BUILD_ROOT%{_sysconfdir}/init---%clean-rm -rf $RPM_BUILD_ROOT---%pre-getent group %{nixbld_group} >/dev/null || groupadd -r %{nixbld_group}-for i in $(seq 10);-do-  getent passwd %{nixbld_user}$i >/dev/null || \-    useradd -r -g %{nixbld_group} -G %{nixbld_group} -d /var/empty \-      -s %{_sbindir}/nologin \-      -c "Nix build user $i" %{nixbld_user}$i-done--%post-chgrp %{nixbld_group} /nix/store-%if ! 0%{?rhel} || 0%{?rhel} >= 7-# Enable and start Nix worker-systemctl enable nix-daemon.socket nix-daemon.service-systemctl start  nix-daemon.socket-%endif--%files-%{_bindir}/nix*-%{_libdir}/*.so-%{_prefix}/libexec/*-%if ! 0%{?rhel} || 0%{?rhel} >= 7-%{_prefix}/lib/systemd/system/nix-daemon.socket-%{_prefix}/lib/systemd/system/nix-daemon.service-%endif-%{_datadir}/nix-%{_mandir}/man1/*.1*-%{_mandir}/man5/*.5*-%{_mandir}/man8/*.8*-%config(noreplace) %{_sysconfdir}/profile.d/nix.sh-%config(noreplace) %{_sysconfdir}/profile.d/nix-daemon.sh-/nix--%files devel-%{_includedir}/nix-%{_prefix}/lib/pkgconfig/*.pc--%files doc-%docdir %{_defaultdocdir}/%{name}-doc-%{version}-%{_defaultdocdir}/%{name}-doc-%{version}
− data/nix/perl/MANIFEST
@@ -1,7 +0,0 @@-Changes-Makefile.PL-MANIFEST-Nix.xs-README-t/Nix.t-lib/Nix.pm
− data/nix/perl/Makefile
@@ -1,14 +0,0 @@-makefiles = local.mk--GLOBAL_CXXFLAGS += -g -Wall---include Makefile.config--OPTIMIZE = 1--ifeq ($(OPTIMIZE), 1)-  GLOBAL_CFLAGS += -O3-  GLOBAL_CXXFLAGS += -O3-endif--include mk/lib.mk
− data/nix/perl/Makefile.config.in
@@ -1,18 +0,0 @@-CC = @CC@-CFLAGS = @CFLAGS@-CXX = @CXX@-CXXFLAGS = @CXXFLAGS@-HAVE_SODIUM = @HAVE_SODIUM@-PACKAGE_NAME = @PACKAGE_NAME@-PACKAGE_VERSION = @PACKAGE_VERSION@-SODIUM_LIBS = @SODIUM_LIBS@-NIX_CFLAGS = @NIX_CFLAGS@-NIX_LIBS = @NIX_LIBS@-nixbindir = @nixbindir@-curl = @curl@-nixlibexecdir = @nixlibexecdir@-nixlocalstatedir = @nixlocalstatedir@-perl = @perl@-perllibdir = @perllibdir@-nixstoredir = @nixstoredir@-nixsysconfdir = @nixsysconfdir@
− data/nix/perl/configure.ac
@@ -1,99 +0,0 @@-AC_INIT(nix-perl, m4_esyscmd([bash -c "echo -n $(cat ../version)$VERSION_SUFFIX"]))-AC_CONFIG_SRCDIR(MANIFEST)-AC_CONFIG_AUX_DIR(../config)--CFLAGS=-CXXFLAGS=-AC_PROG_CC-AC_PROG_CXX-AX_CXX_COMPILE_STDCXX_11--# Use 64-bit file system calls so that we can support files > 2 GiB.-AC_SYS_LARGEFILE--AC_DEFUN([NEED_PROG],-[-AC_PATH_PROG($1, $2)-if test -z "$$1"; then-    AC_MSG_ERROR([$2 is required])-fi-])--NEED_PROG(perl, perl)-NEED_PROG(curl, curl)-NEED_PROG(bzip2, bzip2)-NEED_PROG(xz, xz)--# Test that Perl has the open/fork feature (Perl 5.8.0 and beyond).-AC_MSG_CHECKING([whether Perl is recent enough])-if ! $perl -e 'open(FOO, "-|", "true"); while (<FOO>) { print; }; close FOO or die;'; then-    AC_MSG_RESULT(no)-    AC_MSG_ERROR([Your Perl version is too old.  Nix requires Perl 5.8.0 or newer.])-fi-AC_MSG_RESULT(yes)---# Figure out where to install Perl modules.-AC_MSG_CHECKING([for the Perl installation prefix])-perlversion=$($perl -e 'use Config; print $Config{version};')-perlarchname=$($perl -e 'use Config; print $Config{archname};')-AC_SUBST(perllibdir, [${libdir}/perl5/site_perl/$perlversion/$perlarchname])-AC_MSG_RESULT($perllibdir)--# Look for libsodium, an optional dependency.-PKG_CHECK_MODULES([SODIUM], [libsodium],-  [AC_DEFINE([HAVE_SODIUM], [1], [Whether to use libsodium for cryptography.])-   CXXFLAGS="$SODIUM_CFLAGS $CXXFLAGS"-   have_sodium=1], [have_sodium=])-AC_SUBST(HAVE_SODIUM, [$have_sodium])--# Check for the required Perl dependencies (DBI and DBD::SQLite).-perlFlags="-I$perllibdir"--AC_ARG_WITH(dbi, AC_HELP_STRING([--with-dbi=PATH],-  [prefix of the Perl DBI library]),-  perlFlags="$perlFlags -I$withval")--AC_ARG_WITH(dbd-sqlite, AC_HELP_STRING([--with-dbd-sqlite=PATH],-  [prefix of the Perl DBD::SQLite library]),-  perlFlags="$perlFlags -I$withval")--AC_MSG_CHECKING([whether DBD::SQLite works])-if ! $perl $perlFlags -e 'use DBI; use DBD::SQLite;' 2>&5; then-    AC_MSG_RESULT(no)-    AC_MSG_FAILURE([The Perl modules DBI and/or DBD::SQLite are missing.])-fi-AC_MSG_RESULT(yes)--AC_SUBST(perlFlags)--PKG_CHECK_MODULES([NIX], [nix-store])--NEED_PROG([NIX_INSTANTIATE_PROGRAM], [nix-instantiate])--# Get nix configure values-nixbindir=$("$NIX_INSTANTIATE_PROGRAM" --eval '<nix/config.nix>' -A nixBinDir | tr -d \")-nixlibexecdir=$("$NIX_INSTANTIATE_PROGRAM" --eval '<nix/config.nix>' -A nixLibexecDir | tr -d \")-nixlocalstatedir=$("$NIX_INSTANTIATE_PROGRAM" --eval '<nix/config.nix>' -A nixLocalstateDir | tr -d \")-nixsysconfdir=$("$NIX_INSTANTIATE_PROGRAM" --eval '<nix/config.nix>' -A nixSysconfDir | tr -d \")-nixstoredir=$("$NIX_INSTANTIATE_PROGRAM" --eval '<nix/config.nix>' -A nixStoreDir | tr -d \")-AC_SUBST(nixbindir)-AC_SUBST(nixlibexecdir)-AC_SUBST(nixlocalstatedir)-AC_SUBST(nixsysconfdir)-AC_SUBST(nixstoredir)--# Expand all variables in config.status.-test "$prefix" = NONE && prefix=$ac_default_prefix-test "$exec_prefix" = NONE && exec_prefix='${prefix}'-for name in $ac_subst_vars; do-    declare $name="$(eval echo "${!name}")"-    declare $name="$(eval echo "${!name}")"-    declare $name="$(eval echo "${!name}")"-done--rm -f Makefile.config-ln -sfn ../mk mk--AC_CONFIG_FILES([])-AC_OUTPUT
− data/nix/perl/lib/Nix/Config.pm.in
@@ -1,34 +0,0 @@-package Nix::Config;--use MIME::Base64;--$version = "@PACKAGE_VERSION@";--$binDir = $ENV{"NIX_BIN_DIR"} || "@nixbindir@";-$libexecDir = $ENV{"NIX_LIBEXEC_DIR"} || "@nixlibexecdir@";-$stateDir = $ENV{"NIX_STATE_DIR"} || "@nixlocalstatedir@/nix";-$logDir = $ENV{"NIX_LOG_DIR"} || "@nixlocalstatedir@/log/nix";-$confDir = $ENV{"NIX_CONF_DIR"} || "@nixsysconfdir@/nix";-$storeDir = $ENV{"NIX_STORE_DIR"} || "@nixstoredir@";--$bzip2 = "@bzip2@";-$xz = "@xz@";-$curl = "@curl@";--$useBindings = 1;--%config = ();--sub readConfig {-    my $config = "$confDir/nix.conf";-    return unless -f $config;--    open CONFIG, "<$config" or die "cannot open '$config'";-    while (<CONFIG>) {-        /^\s*([\w\-\.]+)\s*=\s*(.*)$/ or next;-        $config{$1} = $2;-    }-    close CONFIG;-}--return 1;
− data/nix/perl/lib/Nix/CopyClosure.pm
@@ -1,61 +0,0 @@-package Nix::CopyClosure;--use utf8;-use strict;-use Nix::Config;-use Nix::Store;-use Nix::SSH;-use List::Util qw(sum);-use IPC::Open2;---sub copyToOpen {-    my ($from, $to, $sshHost, $storePaths, $includeOutputs, $dryRun, $useSubstitutes) = @_;--    $useSubstitutes = 0 if $dryRun || !defined $useSubstitutes;--    # Get the closure of this path.-    my @closure = reverse(topoSortPaths(computeFSClosure(0, $includeOutputs,-        map { followLinksToStorePath $_ } @{$storePaths})));--    # Send the "query valid paths" command with the "lock" option-    # enabled. This prevents a race where the remote host-    # garbage-collect paths that are already there. Optionally, ask-    # the remote host to substitute missing paths.-    syswrite($to, pack("L<x4L<x4L<x4", 1, 1, $useSubstitutes)) or die;-    writeStrings(\@closure, $to);--    # Get back the set of paths that are already valid on the remote host.-    my %present;-    $present{$_} = 1 foreach readStrings($from);--    my @missing = grep { !$present{$_} } @closure;-    return if !@missing;--    my $missingSize = 0;-    $missingSize += (queryPathInfo($_, 1))[3] foreach @missing;--    printf STDERR "copying %d missing paths (%.2f MiB) to '$sshHost'...\n",-        scalar(@missing), $missingSize / (1024**2);-    return if $dryRun;--    # Send the "import paths" command.-    syswrite($to, pack("L<x4", 4)) or die;-    exportPaths(fileno($to), @missing);-    readInt($from) == 1 or die "remote machine '$sshHost' failed to import closure\n";-}---sub copyTo {-    my ($sshHost, $storePaths, $includeOutputs, $dryRun, $useSubstitutes) = @_;--    # Connect to the remote host.-    my ($from, $to) = connectToRemoteNix($sshHost, []);--    copyToOpen($from, $to, $sshHost, $storePaths, $includeOutputs, $dryRun, $useSubstitutes);--    close $to;-}---1;
− data/nix/perl/lib/Nix/Manifest.pm
@@ -1,325 +0,0 @@-package Nix::Manifest;--use utf8;-use strict;-use DBI;-use DBD::SQLite;-use Cwd;-use File::stat;-use File::Path;-use Fcntl ':flock';-use MIME::Base64;-use Nix::Config;-use Nix::Store;--our @ISA = qw(Exporter);-our @EXPORT = qw(readManifest writeManifest addPatch parseNARInfo fingerprintPath);---sub addNAR {-    my ($narFiles, $storePath, $info) = @_;--    $$narFiles{$storePath} = []-        unless defined $$narFiles{$storePath};--    my $narFileList = $$narFiles{$storePath};--    my $found = 0;-    foreach my $narFile (@{$narFileList}) {-        $found = 1 if $narFile->{url} eq $info->{url};-    }--    push @{$narFileList}, $info if !$found;-}---sub addPatch {-    my ($patches, $storePath, $patch) = @_;--    $$patches{$storePath} = []-        unless defined $$patches{$storePath};--    my $patchList = $$patches{$storePath};--    my $found = 0;-    foreach my $patch2 (@{$patchList}) {-        $found = 1 if-            $patch2->{url} eq $patch->{url} &&-            $patch2->{basePath} eq $patch->{basePath};-    }--    push @{$patchList}, $patch if !$found;--    return !$found;-}---sub readManifest_ {-    my ($manifest, $addNAR, $addPatch) = @_;--    # Decompress the manifest if necessary.-    if ($manifest =~ /\.bz2$/) {-        open MANIFEST, "$Nix::Config::bzip2 -d < $manifest |"-            or die "cannot decompress '$manifest': $!";-    } else {-        open MANIFEST, "<$manifest"-            or die "cannot open '$manifest': $!";-    }--    my $inside = 0;-    my $type;--    my $manifestVersion = 2;--    my ($storePath, $url, $hash, $size, $basePath, $baseHash, $patchType);-    my ($narHash, $narSize, $references, $deriver, $copyFrom, $system, $compressionType);--    while (<MANIFEST>) {-        chomp;-        s/\#.*$//g;-        next if (/^$/);--        if (!$inside) {--            if (/^\s*(\w*)\s*\{$/) {-                $type = $1;-                $type = "narfile" if $type eq "";-                $inside = 1;-                undef $storePath;-                undef $url;-                undef $hash;-                undef $size;-                undef $narHash;-                undef $narSize;-                undef $basePath;-                undef $baseHash;-                undef $patchType;-                undef $system;-                $references = "";-                $deriver = "";-                $compressionType = "bzip2";-            }--        } else {--            if (/^\}$/) {-                $inside = 0;--                if ($type eq "narfile") {-                    &$addNAR($storePath,-                        { url => $url, hash => $hash, size => $size-                        , narHash => $narHash, narSize => $narSize-                        , references => $references-                        , deriver => $deriver-                        , system => $system-                        , compressionType => $compressionType-                        });-                }--                elsif ($type eq "patch") {-                    &$addPatch($storePath,-                        { url => $url, hash => $hash, size => $size-                        , basePath => $basePath, baseHash => $baseHash-                        , narHash => $narHash, narSize => $narSize-                        , patchType => $patchType-                        });-                }--            }--            elsif (/^\s*StorePath:\s*(\/\S+)\s*$/) { $storePath = $1; }-            elsif (/^\s*CopyFrom:\s*(\/\S+)\s*$/) { $copyFrom = $1; }-            elsif (/^\s*Hash:\s*(\S+)\s*$/) { $hash = $1; }-            elsif (/^\s*URL:\s*(\S+)\s*$/) { $url = $1; }-            elsif (/^\s*Compression:\s*(\S+)\s*$/) { $compressionType = $1; }-            elsif (/^\s*Size:\s*(\d+)\s*$/) { $size = $1; }-            elsif (/^\s*BasePath:\s*(\/\S+)\s*$/) { $basePath = $1; }-            elsif (/^\s*BaseHash:\s*(\S+)\s*$/) { $baseHash = $1; }-            elsif (/^\s*Type:\s*(\S+)\s*$/) { $patchType = $1; }-            elsif (/^\s*NarHash:\s*(\S+)\s*$/) { $narHash = $1; }-            elsif (/^\s*NarSize:\s*(\d+)\s*$/) { $narSize = $1; }-            elsif (/^\s*References:\s*(.*)\s*$/) { $references = $1; }-            elsif (/^\s*Deriver:\s*(\S+)\s*$/) { $deriver = $1; }-            elsif (/^\s*ManifestVersion:\s*(\d+)\s*$/) { $manifestVersion = $1; }-            elsif (/^\s*System:\s*(\S+)\s*$/) { $system = $1; }--            # Compatibility;-            elsif (/^\s*NarURL:\s*(\S+)\s*$/) { $url = $1; }-            elsif (/^\s*MD5:\s*(\S+)\s*$/) { $hash = "md5:$1"; }--        }-    }--    close MANIFEST;--    return $manifestVersion;-}---sub readManifest {-    my ($manifest, $narFiles, $patches) = @_;-    readManifest_($manifest,-        sub { addNAR($narFiles, @_); },-        sub { addPatch($patches, @_); } );-}---sub writeManifest {-    my ($manifest, $narFiles, $patches, $noCompress) = @_;--    open MANIFEST, ">$manifest.tmp"; # !!! check exclusive--    print MANIFEST "version {\n";-    print MANIFEST "  ManifestVersion: 3\n";-    print MANIFEST "}\n";--    foreach my $storePath (sort (keys %{$narFiles})) {-        my $narFileList = $$narFiles{$storePath};-        foreach my $narFile (@{$narFileList}) {-            print MANIFEST "{\n";-            print MANIFEST "  StorePath: $storePath\n";-            print MANIFEST "  NarURL: $narFile->{url}\n";-            print MANIFEST "  Compression: $narFile->{compressionType}\n";-            print MANIFEST "  Hash: $narFile->{hash}\n" if defined $narFile->{hash};-            print MANIFEST "  Size: $narFile->{size}\n" if defined $narFile->{size};-            print MANIFEST "  NarHash: $narFile->{narHash}\n";-            print MANIFEST "  NarSize: $narFile->{narSize}\n" if $narFile->{narSize};-            print MANIFEST "  References: $narFile->{references}\n"-                if defined $narFile->{references} && $narFile->{references} ne "";-            print MANIFEST "  Deriver: $narFile->{deriver}\n"-                if defined $narFile->{deriver} && $narFile->{deriver} ne "";-            print MANIFEST "  System: $narFile->{system}\n" if defined $narFile->{system};-            print MANIFEST "}\n";-        }-    }--    foreach my $storePath (sort (keys %{$patches})) {-        my $patchList = $$patches{$storePath};-        foreach my $patch (@{$patchList}) {-            print MANIFEST "patch {\n";-            print MANIFEST "  StorePath: $storePath\n";-            print MANIFEST "  NarURL: $patch->{url}\n";-            print MANIFEST "  Hash: $patch->{hash}\n";-            print MANIFEST "  Size: $patch->{size}\n";-            print MANIFEST "  NarHash: $patch->{narHash}\n";-            print MANIFEST "  NarSize: $patch->{narSize}\n" if $patch->{narSize};-            print MANIFEST "  BasePath: $patch->{basePath}\n";-            print MANIFEST "  BaseHash: $patch->{baseHash}\n";-            print MANIFEST "  Type: $patch->{patchType}\n";-            print MANIFEST "}\n";-        }-    }---    close MANIFEST;--    rename("$manifest.tmp", $manifest)-        or die "cannot rename $manifest.tmp: $!";---    # Create a bzipped manifest.-    unless (defined $noCompress) {-        system("$Nix::Config::bzip2 < $manifest > $manifest.bz2.tmp") == 0-            or die "cannot compress manifest";--        rename("$manifest.bz2.tmp", "$manifest.bz2")-            or die "cannot rename $manifest.bz2.tmp: $!";-    }-}---# Return a fingerprint of a store path to be used in binary cache-# signatures. It contains the store path, the base-32 SHA-256 hash of-# the contents of the path, and the references.-sub fingerprintPath {-    my ($storePath, $narHash, $narSize, $references) = @_;-    die if substr($storePath, 0, length($Nix::Config::storeDir)) ne $Nix::Config::storeDir;-    die if substr($narHash, 0, 7) ne "sha256:";-    # Convert hash from base-16 to base-32, if necessary.-    $narHash = "sha256:" . convertHash("sha256", substr($narHash, 7), 1)-        if length($narHash) == 71;-    die if length($narHash) != 59;-    foreach my $ref (@{$references}) {-        die if substr($ref, 0, length($Nix::Config::storeDir)) ne $Nix::Config::storeDir;-    }-    return "1;" . $storePath . ";" . $narHash . ";" . $narSize . ";" . join(",", @{$references});-}---# Parse a NAR info file.-sub parseNARInfo {-    my ($storePath, $content, $requireValidSig, $location) = @_;--    my ($storePath2, $url, $fileHash, $fileSize, $narHash, $narSize, $deriver, $system, $sig);-    my $compression = "bzip2";-    my @refs;--    foreach my $line (split "\n", $content) {-        return undef unless $line =~ /^(.*): (.*)$/;-        if ($1 eq "StorePath") { $storePath2 = $2; }-        elsif ($1 eq "URL") { $url = $2; }-        elsif ($1 eq "Compression") { $compression = $2; }-        elsif ($1 eq "FileHash") { $fileHash = $2; }-        elsif ($1 eq "FileSize") { $fileSize = int($2); }-        elsif ($1 eq "NarHash") { $narHash = $2; }-        elsif ($1 eq "NarSize") { $narSize = int($2); }-        elsif ($1 eq "References") { @refs = split / /, $2; }-        elsif ($1 eq "Deriver") { $deriver = $2; }-        elsif ($1 eq "System") { $system = $2; }-        elsif ($1 eq "Sig") { $sig = $2; }-    }--    return undef if $storePath ne $storePath2 || !defined $url || !defined $narHash;--    my $res =-        { url => $url-        , compression => $compression-        , fileHash => $fileHash-        , fileSize => $fileSize-        , narHash => $narHash-        , narSize => $narSize-        , refs => [ @refs ]-        , deriver => $deriver-        , system => $system-        };--    if ($requireValidSig) {-        # FIXME: might be useful to support multiple signatures per .narinfo.--        if (!defined $sig) {-            warn "NAR info file '$location' lacks a signature; ignoring\n";-            return undef;-        }-        my ($keyName, $sig64) = split ":", $sig;-        return undef unless defined $keyName && defined $sig64;--        my $publicKey = $Nix::Config::binaryCachePublicKeys{$keyName};-        if (!defined $publicKey) {-            warn "NAR info file '$location' is signed by unknown key '$keyName'; ignoring\n";-            return undef;-        }--        my $fingerprint;-        eval {-            $fingerprint = fingerprintPath(-                $storePath, $narHash, $narSize,-                [ map { "$Nix::Config::storeDir/$_" } @refs ]);-        };-        if ($@) {-            warn "cannot compute fingerprint of '$location'; ignoring\n";-            return undef;-        }--        if (!checkSignature($publicKey, decode_base64($sig64), $fingerprint)) {-            warn "NAR info file '$location' has an incorrect signature; ignoring\n";-            return undef;-        }--        $res->{signedBy} = $keyName;-    }--    return $res;-}---return 1;
− data/nix/perl/lib/Nix/SSH.pm
@@ -1,110 +0,0 @@-package Nix::SSH;--use utf8;-use strict;-use File::Temp qw(tempdir);-use IPC::Open2;--our @ISA = qw(Exporter);-our @EXPORT = qw(-  @globalSshOpts-  readN readInt readString readStrings-  writeInt writeString writeStrings-  connectToRemoteNix-);---our @globalSshOpts = split ' ', ($ENV{"NIX_SSHOPTS"} or "");---sub readN {-    my ($bytes, $from) = @_;-    my $res = "";-    while ($bytes > 0) {-        my $s;-        my $n = sysread($from, $s, $bytes);-        die "I/O error reading from remote side\n" if !defined $n;-        die "got EOF while expecting $bytes bytes from remote side\n" if !$n;-        $bytes -= $n;-        $res .= $s;-    }-    return $res;-}---sub readInt {-    my ($from) = @_;-    return unpack("L<x4", readN(8, $from));-}---sub readString {-    my ($from) = @_;-    my $len = readInt($from);-    my $s = readN($len, $from);-    readN(8 - $len % 8, $from) if $len % 8; # skip padding-    return $s;-}---sub readStrings {-    my ($from) = @_;-    my $n = readInt($from);-    my @res;-    push @res, readString($from) while $n--;-    return @res;-}---sub writeInt {-    my ($n, $to) = @_;-    syswrite($to, pack("L<x4", $n)) or die;-}---sub writeString {-    my ($s, $to) = @_;-    my $len = length $s;-    my $req .= pack("L<x4", $len);-    $req .= $s;-    $req .= "\000" x (8 - $len % 8) if $len % 8;-    syswrite($to, $req) or die;-}---sub writeStrings {-    my ($ss, $to) = @_;-    writeInt(scalar(@{$ss}), $to);-    writeString($_, $to) foreach @{$ss};-}---sub connectToRemoteNix {-    my ($sshHost, $sshOpts, $extraFlags) = @_;--    $extraFlags ||= "";--    # Start ‘nix-store --serve’ on the remote host.-    my ($from, $to);-    # FIXME: don't start a shell, start ssh directly.-    my $pid = open2($from, $to, "exec ssh -x -a $sshHost @globalSshOpts @{$sshOpts} nix-store --serve --write $extraFlags");--    # Do the handshake.-    my $magic;-    eval {-        my $SERVE_MAGIC_1 = 0x390c9deb; # FIXME-        my $clientVersion = 0x200;-        syswrite($to, pack("L<x4L<x4", $SERVE_MAGIC_1, $clientVersion)) or die;-        $magic = readInt($from);-    };-    die "unable to connect to '$sshHost'\n" if $@;-    die "did not get valid handshake from remote host\n" if $magic  != 0x5452eecb;--    my $serverVersion = readInt($from);-    die "unsupported server version\n" if $serverVersion < 0x200 || $serverVersion >= 0x300;--    return ($from, $to, $pid);-}---1;
− data/nix/perl/lib/Nix/Store.pm
@@ -1,95 +0,0 @@-package Nix::Store;--use strict;-use warnings;-use Nix::Config;--require Exporter;--our @ISA = qw(Exporter);--our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );--our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );--our @EXPORT = qw(-    setVerbosity-    isValidPath queryReferences queryPathInfo queryDeriver queryPathHash-    queryPathFromHashPart-    topoSortPaths computeFSClosure followLinksToStorePath exportPaths importPaths-    hashPath hashFile hashString convertHash-    signString checkSignature-    addToStore makeFixedOutputPath-    derivationFromPath-    addTempRoot-);--our $VERSION = '0.15';--sub backtick {-    open(RES, "-|", @_) or die;-    local $/;-    my $res = <RES> || "";-    close RES or die;-    return $res;-}--if ($Nix::Config::useBindings) {-    require XSLoader;-    XSLoader::load('Nix::Store', $VERSION);-} else {--    # Provide slow fallbacks of some functions on platforms that don't-    # support the Perl bindings.--    use File::Temp;-    use Fcntl qw/F_SETFD/;--    *hashFile = sub {-        my ($algo, $base32, $path) = @_;-        my $res = backtick("$Nix::Config::binDir/nix-hash", "--flat", $path, "--type", $algo, $base32 ? "--base32" : ());-        chomp $res;-        return $res;-    };--    *hashPath = sub {-        my ($algo, $base32, $path) = @_;-        my $res = backtick("$Nix::Config::binDir/nix-hash", $path, "--type", $algo, $base32 ? "--base32" : ());-        chomp $res;-        return $res;-    };--    *hashString = sub {-        my ($algo, $base32, $s) = @_;-        my $fh = File::Temp->new();-        print $fh $s;-        my $res = backtick("$Nix::Config::binDir/nix-hash", $fh->filename, "--type", $algo, $base32 ? "--base32" : ());-        chomp $res;-        return $res;-    };--    *addToStore = sub {-        my ($srcPath, $recursive, $algo) = @_;-        die "not implemented" if $recursive || $algo ne "sha256";-        my $res = backtick("$Nix::Config::binDir/nix-store", "--add", $srcPath);-        chomp $res;-        return $res;-    };--    *isValidPath = sub {-        my ($path) = @_;-        my $res = backtick("$Nix::Config::binDir/nix-store", "--check-validity", "--print-invalid", $path);-        chomp $res;-        return $res ne $path;-    };--    *queryPathHash = sub {-        my ($path) = @_;-        my $res = backtick("$Nix::Config::binDir/nix-store", "--query", "--hash", $path);-        chomp $res;-        return $res;-    };-}--1;-__END__
− data/nix/perl/lib/Nix/Store.xs
@@ -1,346 +0,0 @@-#include "config.h"--#include "EXTERN.h"-#include "perl.h"-#include "XSUB.h"--/* Prevent a clash between some Perl and libstdc++ macros. */-#undef do_open-#undef do_close--#include "derivations.hh"-#include "globals.hh"-#include "store-api.hh"-#include "util.hh"-#include "crypto.hh"--#if HAVE_SODIUM-#include <sodium.h>-#endif---using namespace nix;---static ref<Store> store()-{-    static std::shared_ptr<Store> _store;-    if (!_store) {-        try {-            settings.loadConfFile();-            settings.lockCPU = false;-            _store = openStore();-        } catch (Error & e) {-            croak("%s", e.what());-        }-    }-    return ref<Store>(_store);-}---MODULE = Nix::Store PACKAGE = Nix::Store-PROTOTYPES: ENABLE---#undef dNOOP // Hack to work around "error: declaration of 'Perl___notused' has a different language linkage" error message on clang.-#define dNOOP---void init()-    CODE:-        store();---void setVerbosity(int level)-    CODE:-        verbosity = (Verbosity) level;---int isValidPath(char * path)-    CODE:-        try {-            RETVAL = store()->isValidPath(path);-        } catch (Error & e) {-            croak("%s", e.what());-        }-    OUTPUT:-        RETVAL---SV * queryReferences(char * path)-    PPCODE:-        try {-            PathSet paths = store()->queryPathInfo(path)->references;-            for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i)-                XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0)));-        } catch (Error & e) {-            croak("%s", e.what());-        }---SV * queryPathHash(char * path)-    PPCODE:-        try {-            auto s = store()->queryPathInfo(path)->narHash.to_string();-            XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));-        } catch (Error & e) {-            croak("%s", e.what());-        }---SV * queryDeriver(char * path)-    PPCODE:-        try {-            auto deriver = store()->queryPathInfo(path)->deriver;-            if (deriver == "") XSRETURN_UNDEF;-            XPUSHs(sv_2mortal(newSVpv(deriver.c_str(), 0)));-        } catch (Error & e) {-            croak("%s", e.what());-        }---SV * queryPathInfo(char * path, int base32)-    PPCODE:-        try {-            auto info = store()->queryPathInfo(path);-            if (info->deriver == "")-                XPUSHs(&PL_sv_undef);-            else-                XPUSHs(sv_2mortal(newSVpv(info->deriver.c_str(), 0)));-            auto s = info->narHash.to_string(base32 ? Base32 : Base16);-            XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));-            mXPUSHi(info->registrationTime);-            mXPUSHi(info->narSize);-            AV * arr = newAV();-            for (PathSet::iterator i = info->references.begin(); i != info->references.end(); ++i)-                av_push(arr, newSVpv(i->c_str(), 0));-            XPUSHs(sv_2mortal(newRV((SV *) arr)));-        } catch (Error & e) {-            croak("%s", e.what());-        }---SV * queryPathFromHashPart(char * hashPart)-    PPCODE:-        try {-            Path path = store()->queryPathFromHashPart(hashPart);-            XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0)));-        } catch (Error & e) {-            croak("%s", e.what());-        }---SV * computeFSClosure(int flipDirection, int includeOutputs, ...)-    PPCODE:-        try {-            PathSet paths;-            for (int n = 2; n < items; ++n)-                store()->computeFSClosure(SvPV_nolen(ST(n)), paths, flipDirection, includeOutputs);-            for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i)-                XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0)));-        } catch (Error & e) {-            croak("%s", e.what());-        }---SV * topoSortPaths(...)-    PPCODE:-        try {-            PathSet paths;-            for (int n = 0; n < items; ++n) paths.insert(SvPV_nolen(ST(n)));-            Paths sorted = store()->topoSortPaths(paths);-            for (Paths::iterator i = sorted.begin(); i != sorted.end(); ++i)-                XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0)));-        } catch (Error & e) {-            croak("%s", e.what());-        }---SV * followLinksToStorePath(char * path)-    CODE:-        try {-            RETVAL = newSVpv(store()->followLinksToStorePath(path).c_str(), 0);-        } catch (Error & e) {-            croak("%s", e.what());-        }-    OUTPUT:-        RETVAL---void exportPaths(int fd, ...)-    PPCODE:-        try {-            Paths paths;-            for (int n = 1; n < items; ++n) paths.push_back(SvPV_nolen(ST(n)));-            FdSink sink(fd);-            store()->exportPaths(paths, sink);-        } catch (Error & e) {-            croak("%s", e.what());-        }---void importPaths(int fd, int dontCheckSigs)-    PPCODE:-        try {-            FdSource source(fd);-            store()->importPaths(source, nullptr, dontCheckSigs ? NoCheckSigs : CheckSigs);-        } catch (Error & e) {-            croak("%s", e.what());-        }---SV * hashPath(char * algo, int base32, char * path)-    PPCODE:-        try {-            Hash h = hashPath(parseHashType(algo), path).first;-            auto s = h.to_string(base32 ? Base32 : Base16, false);-            XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));-        } catch (Error & e) {-            croak("%s", e.what());-        }---SV * hashFile(char * algo, int base32, char * path)-    PPCODE:-        try {-            Hash h = hashFile(parseHashType(algo), path);-            auto s = h.to_string(base32 ? Base32 : Base16, false);-            XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));-        } catch (Error & e) {-            croak("%s", e.what());-        }---SV * hashString(char * algo, int base32, char * s)-    PPCODE:-        try {-            Hash h = hashString(parseHashType(algo), s);-            auto s = h.to_string(base32 ? Base32 : Base16, false);-            XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));-        } catch (Error & e) {-            croak("%s", e.what());-        }---SV * convertHash(char * algo, char * s, int toBase32)-    PPCODE:-        try {-            Hash h(s, parseHashType(algo));-            string s = h.to_string(toBase32 ? Base32 : Base16, false);-            XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));-        } catch (Error & e) {-            croak("%s", e.what());-        }---SV * signString(char * secretKey_, char * msg)-    PPCODE:-        try {-#if HAVE_SODIUM-            auto sig = SecretKey(secretKey_).signDetached(msg);-            XPUSHs(sv_2mortal(newSVpv(sig.c_str(), sig.size())));-#else-            throw Error("Nix was not compiled with libsodium, required for signed binary cache support");-#endif-        } catch (Error & e) {-            croak("%s", e.what());-        }---int checkSignature(SV * publicKey_, SV * sig_, char * msg)-    CODE:-        try {-#if HAVE_SODIUM-            STRLEN publicKeyLen;-            unsigned char * publicKey = (unsigned char *) SvPV(publicKey_, publicKeyLen);-            if (publicKeyLen != crypto_sign_PUBLICKEYBYTES)-                throw Error("public key is not valid");--            STRLEN sigLen;-            unsigned char * sig = (unsigned char *) SvPV(sig_, sigLen);-            if (sigLen != crypto_sign_BYTES)-                throw Error("signature is not valid");--            RETVAL = crypto_sign_verify_detached(sig, (unsigned char *) msg, strlen(msg), publicKey) == 0;-#else-            throw Error("Nix was not compiled with libsodium, required for signed binary cache support");-#endif-        } catch (Error & e) {-            croak("%s", e.what());-        }-    OUTPUT:-        RETVAL---SV * addToStore(char * srcPath, int recursive, char * algo)-    PPCODE:-        try {-            Path path = store()->addToStore(baseNameOf(srcPath), srcPath, recursive, parseHashType(algo));-            XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0)));-        } catch (Error & e) {-            croak("%s", e.what());-        }---SV * makeFixedOutputPath(int recursive, char * algo, char * hash, char * name)-    PPCODE:-        try {-            Hash h(hash, parseHashType(algo));-            Path path = store()->makeFixedOutputPath(recursive, h, name);-            XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0)));-        } catch (Error & e) {-            croak("%s", e.what());-        }---SV * derivationFromPath(char * drvPath)-    PREINIT:-        HV *hash;-    CODE:-        try {-            Derivation drv = store()->derivationFromPath(drvPath);-            hash = newHV();--            HV * outputs = newHV();-            for (DerivationOutputs::iterator i = drv.outputs.begin(); i != drv.outputs.end(); ++i)-                hv_store(outputs, i->first.c_str(), i->first.size(), newSVpv(i->second.path.c_str(), 0), 0);-            hv_stores(hash, "outputs", newRV((SV *) outputs));--            AV * inputDrvs = newAV();-            for (DerivationInputs::iterator i = drv.inputDrvs.begin(); i != drv.inputDrvs.end(); ++i)-                av_push(inputDrvs, newSVpv(i->first.c_str(), 0)); // !!! ignores i->second-            hv_stores(hash, "inputDrvs", newRV((SV *) inputDrvs));--            AV * inputSrcs = newAV();-            for (PathSet::iterator i = drv.inputSrcs.begin(); i != drv.inputSrcs.end(); ++i)-                av_push(inputSrcs, newSVpv(i->c_str(), 0));-            hv_stores(hash, "inputSrcs", newRV((SV *) inputSrcs));--            hv_stores(hash, "platform", newSVpv(drv.platform.c_str(), 0));-            hv_stores(hash, "builder", newSVpv(drv.builder.c_str(), 0));--            AV * args = newAV();-            for (Strings::iterator i = drv.args.begin(); i != drv.args.end(); ++i)-                av_push(args, newSVpv(i->c_str(), 0));-            hv_stores(hash, "args", newRV((SV *) args));--            HV * env = newHV();-            for (StringPairs::iterator i = drv.env.begin(); i != drv.env.end(); ++i)-                hv_store(env, i->first.c_str(), i->first.size(), newSVpv(i->second.c_str(), 0), 0);-            hv_stores(hash, "env", newRV((SV *) env));--            RETVAL = newRV_noinc((SV *)hash);-        } catch (Error & e) {-            croak("%s", e.what());-        }-    OUTPUT:-        RETVAL---void addTempRoot(char * storePath)-    PPCODE:-        try {-            store()->addTempRoot(storePath);-        } catch (Error & e) {-            croak("%s", e.what());-        }
− data/nix/perl/lib/Nix/Utils.pm
@@ -1,47 +0,0 @@-package Nix::Utils;--use utf8;-use File::Temp qw(tempdir);--our @ISA = qw(Exporter);-our @EXPORT = qw(checkURL uniq writeFile readFile mkTempDir);--$urlRE = "(?: [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*]+ )";--sub checkURL {-    my ($url) = @_;-    die "invalid URL '$url'\n" unless $url =~ /^ $urlRE $ /x;-}--sub uniq {-    my %seen;-    my @res;-    foreach my $name (@_) {-        next if $seen{$name};-        $seen{$name} = 1;-        push @res, $name;-    }-    return @res;-}--sub writeFile {-    my ($fn, $s) = @_;-    open TMP, ">$fn" or die "cannot create file '$fn': $!";-    print TMP "$s" or die;-    close TMP or die;-}--sub readFile {-    local $/ = undef;-    my ($fn) = @_;-    open TMP, "<$fn" or die "cannot open file '$fn': $!";-    my $s = <TMP>;-    close TMP or die;-    return $s;-}--sub mkTempDir {-    my ($name) = @_;-    return tempdir("$name.XXXXXX", CLEANUP => 1, DIR => $ENV{"TMPDIR"} // $ENV{"XDG_RUNTIME_DIR"} // "/tmp")-        || die "cannot create a temporary directory";-}
− data/nix/perl/local.mk
@@ -1,43 +0,0 @@-nix_perl_sources := \-  lib/Nix/Store.pm \-  lib/Nix/Manifest.pm \-  lib/Nix/SSH.pm \-  lib/Nix/CopyClosure.pm \-  lib/Nix/Config.pm.in \-  lib/Nix/Utils.pm--nix_perl_modules := $(nix_perl_sources:.in=)--$(foreach x, $(nix_perl_modules), $(eval $(call install-data-in, $(x), $(perllibdir)/Nix)))--lib/Nix/Store.cc: lib/Nix/Store.xs-	$(trace-gen) xsubpp $^ -output $@--libraries += Store--Store_DIR := lib/Nix--Store_SOURCES := $(Store_DIR)/Store.cc--Store_CXXFLAGS = \-  $(NIX_CFLAGS) \-  -I$(shell perl -e 'use Config; print $$Config{archlibexp};')/CORE \-  -D_FILE_OFFSET_BITS=64 \-  -Wno-unknown-warning-option -Wno-unused-variable -Wno-literal-suffix \-  -Wno-reserved-user-defined-literal -Wno-duplicate-decl-specifier -Wno-pointer-bool-conversion--Store_LDFLAGS := $(SODIUM_LIBS) $(NIX_LIBS)--ifeq (CYGWIN,$(findstring CYGWIN,$(OS)))-  archlib = $(shell perl -E 'use Config; print $$Config{archlib};')-  libperl = $(shell perl -E 'use Config; print $$Config{libperl};')-  Store_LDFLAGS += $(shell find ${archlib} -name ${libperl})-endif--Store_ALLOW_UNDEFINED = 1--Store_FORCE_INSTALL = 1--Store_INSTALL_DIR = $(perllibdir)/auto/Nix/Store--clean-files += lib/Nix/Config.pm lib/Nix/Store.cc Makefile.config
− data/nix/release-common.nix
@@ -1,72 +0,0 @@-{ pkgs }:--with pkgs;--rec {-  # Use "busybox-sandbox-shell" if present,-  # if not (legacy) fallback and hope it's sufficient.-  sh = pkgs.busybox-sandbox-shell or (busybox.override {-    useMusl = true;-    enableStatic = true;-    enableMinimal = true;-    extraConfig = ''-      CONFIG_FEATURE_FANCY_ECHO y-      CONFIG_FEATURE_SH_MATH y-      CONFIG_FEATURE_SH_MATH_64 y--      CONFIG_ASH y-      CONFIG_ASH_OPTIMIZE_FOR_SIZE y--      CONFIG_ASH_ALIAS y-      CONFIG_ASH_BASH_COMPAT y-      CONFIG_ASH_CMDCMD y-      CONFIG_ASH_ECHO y-      CONFIG_ASH_GETOPTS y-      CONFIG_ASH_INTERNAL_GLOB y-      CONFIG_ASH_JOB_CONTROL y-      CONFIG_ASH_PRINTF y-      CONFIG_ASH_TEST y-    '';-  });--  configureFlags =-    [ "--disable-init-state"-      "--enable-gc"-    ] ++ lib.optionals stdenv.isLinux [-      "--with-sandbox-shell=${sh}/bin/busybox"-    ];--  tarballDeps =-    [ bison-      flex-      libxml2-      libxslt-      docbook5-      docbook5_xsl-      autoconf-archive-      autoreconfHook-    ];--  buildDeps =-    [ curl-      bzip2 xz brotli-      openssl pkgconfig sqlite boehmgc-      boost--      # Tests-      git-      mercurial-    ]-    ++ lib.optional stdenv.isLinux libseccomp-    ++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium-    ++ lib.optional (stdenv.isLinux || stdenv.isDarwin)-      (aws-sdk-cpp.override {-        apis = ["s3"];-        customMemoryManagement = false;-      });--  perlDeps =-    [ perl-      perlPackages.DBDSQLite-    ];-}
− data/nix/release.nix
@@ -1,352 +0,0 @@-{ nix ? builtins.fetchGit ./.-, nixpkgs ? builtins.fetchGit { url = https://github.com/NixOS/nixpkgs-channels.git; ref = "nixos-18.03"; }-, officialRelease ? false-, systems ? [ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" ]-}:--let--  pkgs = import nixpkgs { system = builtins.currentSystem or "x86_64-linux"; };--  jobs = rec {---    tarball =-      with pkgs;--      with import ./release-common.nix { inherit pkgs; };--      releaseTools.sourceTarball {-        name = "nix-tarball";-        version = builtins.readFile ./version;-        versionSuffix = if officialRelease then "" else "pre${toString nix.revCount}_${nix.shortRev}";-        src = nix;-        inherit officialRelease;--        buildInputs = tarballDeps ++ buildDeps;--        configureFlags = "--enable-gc";--        postUnpack = ''-          (cd $sourceRoot && find . -type f) | cut -c3- > $sourceRoot/.dist-files-          cat $sourceRoot/.dist-files-        '';--        preConfigure = ''-          (cd perl ; autoreconf --install --force --verbose)-          # TeX needs a writable font cache.-          export VARTEXFONTS=$TMPDIR/texfonts-        '';--        distPhase =-          ''-            runHook preDist-            make dist-            mkdir -p $out/tarballs-            cp *.tar.* $out/tarballs-          '';--        preDist = ''-          make install docdir=$out/share/doc/nix makefiles=doc/manual/local.mk-          echo "doc manual $out/share/doc/nix/manual" >> $out/nix-support/hydra-build-products-        '';-      };---    build = pkgs.lib.genAttrs systems (system:--      let pkgs = import nixpkgs { inherit system; }; in--      with pkgs;--      with import ./release-common.nix { inherit pkgs; };--      releaseTools.nixBuild {-        name = "nix";-        src = tarball;--        buildInputs = buildDeps;--        configureFlags = configureFlags ++-          [ "--sysconfdir=/etc" ];--        enableParallelBuilding = true;--        makeFlags = "profiledir=$(out)/etc/profile.d";--        preBuild = "unset NIX_INDENT_MAKE";--        installFlags = "sysconfdir=$(out)/etc";--        doInstallCheck = true;-        installCheckFlags = "sysconfdir=$(out)/etc";-      });---    perlBindings = pkgs.lib.genAttrs systems (system:--      let pkgs = import nixpkgs { inherit system; }; in with pkgs;--      releaseTools.nixBuild {-        name = "nix-perl";-        src = tarball;--        buildInputs =-          [ jobs.build.${system} curl bzip2 xz pkgconfig pkgs.perl boost ]-          ++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium;--        configureFlags = ''-          --with-dbi=${perlPackages.DBI}/${pkgs.perl.libPrefix}-          --with-dbd-sqlite=${perlPackages.DBDSQLite}/${pkgs.perl.libPrefix}-        '';--        enableParallelBuilding = true;--        postUnpack = "sourceRoot=$sourceRoot/perl";--        preBuild = "unset NIX_INDENT_MAKE";-      });---    binaryTarball = pkgs.lib.genAttrs systems (system:--      with import nixpkgs { inherit system; };--      let-        toplevel = builtins.getAttr system jobs.build;-        version = toplevel.src.version;-        installerClosureInfo = closureInfo { rootPaths = [ toplevel cacert ]; };-      in--      runCommand "nix-binary-tarball-${version}"-        { nativeBuildInputs = lib.optional (system != "aarch64-linux") shellcheck;-          meta.description = "Distribution-independent Nix bootstrap binaries for ${system}";-        }-        ''-          cp ${installerClosureInfo}/registration $TMPDIR/reginfo-          substitute ${./scripts/install-nix-from-closure.sh} $TMPDIR/install \-            --subst-var-by nix ${toplevel} \-            --subst-var-by cacert ${cacert}--          substitute ${./scripts/install-darwin-multi-user.sh} $TMPDIR/install-darwin-multi-user.sh \-            --subst-var-by nix ${toplevel} \-            --subst-var-by cacert ${cacert}-          substitute ${./scripts/install-systemd-multi-user.sh} $TMPDIR/install-systemd-multi-user.sh \-            --subst-var-by nix ${toplevel} \-            --subst-var-by cacert ${cacert}-          substitute ${./scripts/install-multi-user.sh} $TMPDIR/install-multi-user \-            --subst-var-by nix ${toplevel} \-            --subst-var-by cacert ${cacert}--          if type -p shellcheck; then-            # SC1090: Don't worry about not being able to find-            #         $nix/etc/profile.d/nix.sh-            shellcheck --exclude SC1090 $TMPDIR/install-            shellcheck $TMPDIR/install-darwin-multi-user.sh-            shellcheck $TMPDIR/install-systemd-multi-user.sh--            # SC1091: Don't panic about not being able to source-            #         /etc/profile-            # SC2002: Ignore "useless cat" "error", when loading-            #         .reginfo, as the cat is a much cleaner-            #         implementation, even though it is "useless"-            # SC2116: Allow ROOT_HOME=$(echo ~root) for resolving-            #         root's home directory-            shellcheck --external-sources \-              --exclude SC1091,SC2002,SC2116 $TMPDIR/install-multi-user-          fi--          chmod +x $TMPDIR/install-          chmod +x $TMPDIR/install-darwin-multi-user.sh-          chmod +x $TMPDIR/install-systemd-multi-user.sh-          chmod +x $TMPDIR/install-multi-user-          dir=nix-${version}-${system}-          fn=$out/$dir.tar.bz2-          mkdir -p $out/nix-support-          echo "file binary-dist $fn" >> $out/nix-support/hydra-build-products-          tar cvfj $fn \-            --owner=0 --group=0 --mode=u+rw,uga+r \-            --absolute-names \-            --hard-dereference \-            --transform "s,$TMPDIR/install,$dir/install," \-            --transform "s,$TMPDIR/reginfo,$dir/.reginfo," \-            --transform "s,$NIX_STORE,$dir/store,S" \-            $TMPDIR/install $TMPDIR/install-darwin-multi-user.sh \-            $TMPDIR/install-systemd-multi-user.sh \-            $TMPDIR/install-multi-user $TMPDIR/reginfo \-            $(cat ${installerClosureInfo}/store-paths)-        '');---    coverage =-      with pkgs;--      with import ./release-common.nix { inherit pkgs; };--      releaseTools.coverageAnalysis {-        name = "nix-build";-        src = tarball;--        buildInputs = buildDeps;--        configureFlags = ''-          --disable-init-state-        '';--        dontInstall = false;--        doInstallCheck = true;--        lcovFilter = [ "*/boost/*" "*-tab.*" "*/nlohmann/*" "*/linenoise/*" ];--        # We call `dot', and even though we just use it to-        # syntax-check generated dot files, it still requires some-        # fonts.  So provide those.-        FONTCONFIG_FILE = texFunctions.fontsConf;-      };---    rpm_fedora27x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora27x86_64) [ ];---    #deb_debian8i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian8i386) [ "libsodium-dev" ] [ "libsodium13" ];-    #deb_debian8x86_64 = makeDeb_x86_64 (diskImageFunsFun: diskImageFunsFun.debian8x86_64) [ "libsodium-dev" ] [ "libsodium13" ];--    deb_ubuntu1710i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1710i386) [ ] [ "libsodium18" ];-    deb_ubuntu1710x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1710x86_64) [ ] [ "libsodium18" "libboost-context1.62.0" ];---    # System tests.-    tests.remoteBuilds = (import ./tests/remote-builds.nix rec {-      inherit nixpkgs;-      nix = build.x86_64-linux; system = "x86_64-linux";-    });--    tests.nix-copy-closure = (import ./tests/nix-copy-closure.nix rec {-      inherit nixpkgs;-      nix = build.x86_64-linux; system = "x86_64-linux";-    });--    tests.setuid = pkgs.lib.genAttrs-      ["i686-linux" "x86_64-linux"]-      (system:-        import ./tests/setuid.nix rec {-          inherit nixpkgs;-          nix = build.${system}; inherit system;-        });--    tests.binaryTarball =-      with import nixpkgs { system = "x86_64-linux"; };-      vmTools.runInLinuxImage (runCommand "nix-binary-tarball-test"-        { diskImage = vmTools.diskImages.ubuntu1204x86_64;-        }-        ''-          useradd -m alice-          su - alice -c 'tar xf ${binaryTarball.x86_64-linux}/*.tar.*'-          mkdir /dest-nix-          mount -o bind /dest-nix /nix # Provide a writable /nix.-          chown alice /nix-          su - alice -c '_NIX_INSTALLER_TEST=1 ./nix-*/install'-          su - alice -c 'nix-store --verify'-          su - alice -c 'PAGER= nix-store -qR ${build.x86_64-linux}'-          mkdir -p $out/nix-support-          touch $out/nix-support/hydra-build-products-          umount /nix-        ''); # */--    tests.evalNixpkgs =-      import (nixpkgs + "/pkgs/top-level/make-tarball.nix") {-        inherit nixpkgs;-        inherit pkgs;-        nix = build.x86_64-linux;-        officialRelease = false;-      };--    tests.evalNixOS =-      pkgs.runCommand "eval-nixos" { buildInputs = [ build.x86_64-linux ]; }-        ''-          export NIX_STATE_DIR=$TMPDIR-          nix-store --init--          nix-instantiate ${nixpkgs}/nixos/release-combined.nix -A tested --dry-run \-            --arg nixpkgs '{ outPath = ${nixpkgs}; revCount = 123; shortRev = "abcdefgh"; }'--          touch $out-        '';---    # Aggregate job containing the release-critical jobs.-    release = pkgs.releaseTools.aggregate {-      name = "nix-${tarball.version}";-      meta.description = "Release-critical builds";-      constituents =-        [ tarball-          build.i686-linux-          build.x86_64-darwin-          build.x86_64-linux-          binaryTarball.i686-linux-          binaryTarball.x86_64-darwin-          binaryTarball.x86_64-linux-          tests.remoteBuilds-          tests.nix-copy-closure-          tests.binaryTarball-          tests.evalNixpkgs-          tests.evalNixOS-        ];-    };--  };---  makeRPM_i686 = makeRPM "i686-linux";-  makeRPM_x86_64 = makeRPM "x86_64-linux";--  makeRPM =-    system: diskImageFun: extraPackages:--    with import nixpkgs { inherit system; };--    releaseTools.rpmBuild rec {-      name = "nix-rpm";-      src = jobs.tarball;-      diskImage = (diskImageFun vmTools.diskImageFuns)-        { extraPackages =-            [ "sqlite" "sqlite-devel" "bzip2-devel" "libcurl-devel" "openssl-devel" "xz-devel" "libseccomp-devel" "libsodium-devel" "boost-devel" ]-            ++ extraPackages; };-      # At most 2047MB can be simulated in qemu-system-i386-      memSize = 2047;-      meta.schedulingPriority = 50;-      postRPMInstall = "cd /tmp/rpmout/BUILD/nix-* && make installcheck";-      #enableParallelBuilding = true;-    };---  makeDeb_i686 = makeDeb "i686-linux";-  makeDeb_x86_64 = makeDeb "x86_64-linux";--  makeDeb =-    system: diskImageFun: extraPackages: extraDebPackages:--    with import nixpkgs { inherit system; };--    releaseTools.debBuild {-      name = "nix-deb";-      src = jobs.tarball;-      diskImage = (diskImageFun vmTools.diskImageFuns)-        { extraPackages =-            [ "libsqlite3-dev" "libbz2-dev" "libcurl-dev" "libcurl3-nss" "libssl-dev" "liblzma-dev" "libseccomp-dev" "libsodium-dev" "libboost-all-dev" ]-            ++ extraPackages; };-      memSize = 2047;-      meta.schedulingPriority = 50;-      postInstall = "make installcheck";-      configureFlags = "--sysconfdir=/etc";-      debRequires =-        [ "curl" "libsqlite3-0" "libbz2-1.0" "bzip2" "xz-utils" "libssl1.0.0" "liblzma5" "libseccomp2" ]-        ++ extraDebPackages;-      debMaintainer = "Eelco Dolstra <eelco.dolstra@logicblox.com>";-      doInstallCheck = true;-      #enableParallelBuilding = true;-    };---in jobs
− data/nix/scripts/install-darwin-multi-user.sh
@@ -1,144 +0,0 @@-#!/usr/bin/env bash--set -eu-set -o pipefail--readonly PLIST_DEST=/Library/LaunchDaemons/org.nixos.nix-daemon.plist--dsclattr() {-    /usr/bin/dscl . -read "$1" \-        | awk "/$2/ { print \$2 }"-}--poly_validate_assumptions() {-    if [ "$(uname -s)" != "Darwin" ]; then-        failure "This script is for use with macOS!"-    fi-}--poly_service_installed_check() {-    [ -e "$PLIST_DEST" ]-}--poly_service_uninstall_directions() {-        cat <<EOF-$1. Delete $PLIST_DEST--  sudo launchctl unload $PLIST_DEST-  sudo rm $PLIST_DEST--EOF-}--poly_service_setup_note() {-    cat <<EOF- - load and start a LaunchDaemon (at $PLIST_DEST) for nix-daemon--EOF-}--poly_configure_nix_daemon_service() {-    _sudo "to set up the nix-daemon as a LaunchDaemon" \-          ln -sfn "/nix/var/nix/profiles/default$PLIST_DEST" "$PLIST_DEST"--    _sudo "to load the LaunchDaemon plist for nix-daemon" \-          launchctl load /Library/LaunchDaemons/org.nixos.nix-daemon.plist--    _sudo "to start the nix-daemon" \-          launchctl start org.nixos.nix-daemon--}--poly_group_exists() {-    /usr/bin/dscl . -read "/Groups/$1" > /dev/null 2>&1-}--poly_group_id_get() {-    dsclattr "/Groups/$1" "PrimaryGroupID"-}--poly_create_build_group() {-    _sudo "Create the Nix build group, $NIX_BUILD_GROUP_NAME" \-          /usr/sbin/dseditgroup -o create \-          -r "Nix build group for nix-daemon" \-          -i "$NIX_BUILD_GROUP_ID" \-          "$NIX_BUILD_GROUP_NAME" >&2-}--poly_user_exists() {-    /usr/bin/dscl . -read "/Users/$1" > /dev/null 2>&1-}--poly_user_id_get() {-    dsclattr "/Users/$1" "UniqueID"-}--poly_user_hidden_get() {-    dsclattr "/Users/$1" "IsHidden"-}--poly_user_hidden_set() {-    _sudo "in order to make $1 a hidden user" \-          /usr/bin/dscl . -create "/Users/$1" "IsHidden" "1"-}--poly_user_home_get() {-    dsclattr "/Users/$1" "NFSHomeDirectory"-}--poly_user_home_set() {-    _sudo "in order to give $1 a safe home directory" \-          /usr/bin/dscl . -create "/Users/$1" "NFSHomeDirectory" "$2"-}--poly_user_note_get() {-    dsclattr "/Users/$1" "RealName"-}--poly_user_note_set() {-    _sudo "in order to give $username a useful note" \-          /usr/bin/dscl . -create "/Users/$1" "RealName" "$2"-}--poly_user_shell_get() {-    dsclattr "/Users/$1" "UserShell"-}--poly_user_shell_set() {-    _sudo "in order to give $1 a safe home directory" \-          /usr/bin/dscl . -create "/Users/$1" "UserShell" "$2"-}--poly_user_in_group_check() {-    username=$1-    group=$2-    dseditgroup -o checkmember -m "$username" "$group" > /dev/null 2>&1-}--poly_user_in_group_set() {-    username=$1-    group=$2--    _sudo "Add $username to the $group group"\-          /usr/sbin/dseditgroup -o edit -t user \-          -a "$username" "$group"-}--poly_user_primary_group_get() {-    dsclattr "/Users/$1" "PrimaryGroupID"-}--poly_user_primary_group_set() {-    _sudo "to let the nix daemon use this user for builds (this might seem redundant, but there are two concepts of group membership)" \-          /usr/bin/dscl . -create "/Users/$1" "PrimaryGroupID" "$2"-}--poly_create_build_user() {-    username=$1-    uid=$2-    builder_num=$3--    _sudo "Creating the Nix build user (#$builder_num), $username" \-          /usr/bin/dscl . create "/Users/$username" \-          UniqueID "${uid}"-}
− data/nix/scripts/install-multi-user.sh
@@ -1,797 +0,0 @@-#!/usr/bin/env bash--set -eu-set -o pipefail--# Sourced from:-# - https://github.com/LnL7/nix-darwin/blob/8c29d0985d74b4a990238497c47a2542a5616b3c/bootstrap.sh-# - https://gist.github.com/expipiplus1/e571ce88c608a1e83547c918591b149f/ac504c6c1b96e65505fbda437a28ce563408ecb0-# - https://github.com/NixOS/nixos-org-configurations/blob/a122f418797713d519aadf02e677fce0dc1cb446/delft/scripts/nix-mac-installer.sh-# - https://github.com/matthewbauer/macNixOS/blob/f6045394f9153edea417be90c216788e754feaba/install-macNixOS.sh-# - https://gist.github.com/LnL7/9717bd6cdcb30b086fd7f2093e5f8494/86b26f852ce563e973acd30f796a9a416248c34a-#-# however tracking which bits came from which would be impossible.--readonly ESC='\033[0m'-readonly BOLD='\033[38;1m'-readonly BLUE='\033[38;34m'-readonly BLUE_UL='\033[38;4;34m'-readonly GREEN='\033[38;32m'-readonly GREEN_UL='\033[38;4;32m'-readonly RED='\033[38;31m'-readonly RED_UL='\033[38;4;31m'-readonly YELLOW='\033[38;33m'-readonly YELLOW_UL='\033[38;4;33m'--readonly NIX_USER_COUNT="32"-readonly NIX_BUILD_GROUP_ID="30000"-readonly NIX_BUILD_GROUP_NAME="nixbld"-readonly NIX_FIRST_BUILD_UID="30001"-# Please don't change this. We don't support it, because the-# default shell profile that comes with Nix doesn't support it.-readonly NIX_ROOT="/nix"--readonly PROFILE_TARGETS=("/etc/bashrc" "/etc/profile.d/nix.sh" "/etc/zshrc")-readonly PROFILE_BACKUP_SUFFIX=".backup-before-nix"-readonly PROFILE_NIX_FILE="$NIX_ROOT/var/nix/profiles/default/etc/profile.d/nix-daemon.sh"--readonly NIX_INSTALLED_NIX="@nix@"-readonly NIX_INSTALLED_CACERT="@cacert@"-readonly EXTRACTED_NIX_PATH="$(dirname "$0")"--readonly ROOT_HOME=$(echo ~root)--if [ -t 0 ]; then-    readonly IS_HEADLESS='no'-else-    readonly IS_HEADLESS='yes'-fi--headless() {-    if [ "$IS_HEADLESS" = "yes" ]; then-        return 0-    else-        return 1-    fi-}--contactme() {-    echo "We'd love to help if you need it."-    echo ""-    echo "If you can, open an issue at https://github.com/nixos/nix/issues"-    echo ""-    echo "Or feel free to contact the team,"-    echo " - on IRC #nixos on irc.freenode.net"-    echo " - on twitter @nixos_org"-}--uninstall_directions() {-    subheader "Uninstalling nix:"-    local step=0--    if poly_service_installed_check; then-        step=$((step + 1))-        poly_service_uninstall_directions "$step"-    fi--    for profile_target in "${PROFILE_TARGETS[@]}"; do-        if [ -e "$profile_target" ] && [ -e "$profile_target$PROFILE_BACKUP_SUFFIX" ]; then-            step=$((step + 1))-            cat <<EOF-$step. Restore $profile_target$PROFILE_BACKUP_SUFFIX back to $profile_target--  sudo mv $profile_target$PROFILE_BACKUP_SUFFIX $profile_target--(after this one, you may need to re-open any terminals that were-opened while it existed.)--EOF-        fi-    done--    step=$((step + 1))-    cat <<EOF-$step. Delete the files Nix added to your system:--  sudo rm -rf /etc/nix $NIX_ROOT $ROOT_HOME/.nix-profile $ROOT_HOME/.nix-defexpr $ROOT_HOME/.nix-channels $HOME/.nix-profile $HOME/.nix-defexpr $HOME/.nix-channels--and that is it.--EOF--}--nix_user_for_core() {-    printf "nixbld%d" "$1"-}--nix_uid_for_core() {-    echo $((NIX_FIRST_BUILD_UID + $1 - 1))-}--_textout() {-    echo -en "$1"-    shift-    if [ "$*" = "" ]; then-        cat-    else-        echo "$@"-    fi-    echo -en "$ESC"-}--header() {-    follow="---------------------------------------------------------"-    header=$(echo "---- $* $follow$follow$follow" | head -c 80)-    echo ""-    _textout "$BLUE" "$header"-}--warningheader() {-    follow="---------------------------------------------------------"-    header=$(echo "---- $* $follow$follow$follow" | head -c 80)-    echo ""-    _textout "$RED" "$header"-}--subheader() {-    echo ""-    _textout "$BLUE_UL" "$*"-}--row() {-    printf "$BOLD%s$ESC:\\t%s\\n" "$1" "$2"-}--task() {-    echo ""-    ok "~~> $1"-}--bold() {-    echo "$BOLD$*$ESC"-}--ok() {-    _textout "$GREEN" "$@"-}--warning() {-    warningheader "warning!"-    cat-    echo ""-}--failure() {-    header "oh no!"-    _textout "$RED" "$@"-    echo ""-    _textout "$RED" "$(contactme)"-    trap finish_cleanup EXIT-    exit 1-}--ui_confirm() {-    _textout "$GREEN$GREEN_UL" "$1"--    if headless; then-        echo "No TTY, assuming you would say yes :)"-        return 0-    fi--    local prompt="[y/n] "-    echo -n "$prompt"-    while read -r y; do-        if [ "$y" = "y" ]; then-            echo ""-            return 0-        elif [ "$y" = "n" ]; then-            echo ""-            return 1-        else-            _textout "$RED" "Sorry, I didn't understand. I can only understand answers of y or n"-            echo -n "$prompt"-        fi-    done-    echo ""-    return 1-}--__sudo() {-    local expl="$1"-    local cmd="$2"-    shift-    header "sudo execution"--    echo "I am executing:"-    echo ""-    printf "    $ sudo %s\\n" "$cmd"-    echo ""-    echo "$expl"-    echo ""--    return 0-}--_sudo() {-    local expl="$1"-    shift-    if ! headless; then-        __sudo "$expl" "$*"-    fi-    sudo "$@"-}---readonly SCRATCH=$(mktemp -d -t tmp.XXXXXXXXXX)-function finish_cleanup {-    rm -rf "$SCRATCH"-}--function finish_fail {-    finish_cleanup--    failure <<EOF-Jeeze, something went wrong. If you can take all the output and open-an issue, we'd love to fix the problem so nobody else has this issue.--:(-EOF-}-trap finish_fail EXIT--function finish_success {-    finish_cleanup--    ok "Alright! We're done!"-    cat <<EOF--Before Nix will work in your existing shells, you'll need to close-them and open them again. Other than that, you should be ready to go.--Try it! Open a new terminal, and type:--  $ nix-shell -p nix-info --run "nix-info -m"--Thank you for using this installer. If you have any feedback, don't-hesitate:--$(contactme)-EOF-}---validate_starting_assumptions() {-    poly_validate_assumptions--    if [ $EUID -eq 0 ]; then-        failure <<EOF-Please do not run this script with root privileges. We will call sudo-when we need to.-EOF-    fi--    if type nix-env 2> /dev/null >&2; then-        failure <<EOF-Nix already appears to be installed, and this tool assumes it is-_not_ yet installed.--$(uninstall_directions)-EOF-    fi--    if [ "${NIX_REMOTE:-}" != "" ]; then-        failure <<EOF-For some reason, \$NIX_REMOTE is set. It really should not be set-before this installer runs, and it hints that Nix is currently-installed. Please delete the old Nix installation and start again.--Note: You might need to close your shell window and open a new shell-to clear the variable.-EOF-    fi--    if echo "${SSL_CERT_FILE:-}" | grep -qE "(nix/var/nix|nix-profile)"; then-        failure <<EOF-It looks like \$SSL_CERT_FILE is set to a path that used to be part of-the old Nix installation. Please unset that variable and try again:--  $ unset SSL_CERT_FILE--EOF-    fi--    for file in ~/.bash_profile ~/.bash_login ~/.profile ~/.zshenv ~/.zprofile ~/.zshrc ~/.zlogin; do-        if [ -f "$file" ]; then-            if grep -l "^[^#].*.nix-profile" "$file"; then-                failure <<EOF-I found a reference to a ".nix-profile" in $file.-This has a high chance of breaking a new nix installation. It was most-likely put there by a previous Nix installer.--Please remove this reference and try running this again. You should-also look for similar references in:-- - ~/.bash_profile- - ~/.bash_login- - ~/.profile--or other shell init files that you may have.--$(uninstall_directions)-EOF-            fi-        fi-    done--    if [ -d /nix ]; then-        failure <<EOF-There are some relics of a previous installation of Nix at /nix, and-this scripts assumes Nix is _not_ yet installed. Please delete the old-Nix installation and start again.--$(uninstall_directions)-EOF-    fi--    if [ -d /etc/nix ]; then-        failure <<EOF-There are some relics of a previous installation of Nix at /etc/nix, and-this scripts assumes Nix is _not_ yet installed. Please delete the old-Nix installation and start again.--$(uninstall_directions)-EOF-    fi--    for profile_target in "${PROFILE_TARGETS[@]}"; do-        if [ -e "$profile_target$PROFILE_BACKUP_SUFFIX" ]; then-        failure <<EOF-When this script runs, it backs up the current $profile_target to-$profile_target$PROFILE_BACKUP_SUFFIX. This backup file already exists, though.--Please follow these instructions to clean up the old backup file:--1. Copy $profile_target and $profile_target$PROFILE_BACKUP_SUFFIX to another place, just-in case.--2. Take care to make sure that $profile_target$PROFILE_BACKUP_SUFFIX doesn't look like-it has anything nix-related in it. If it does, something is probably-quite wrong. Please open an issue or get in touch immediately.--3. Take care to make sure that $profile_target doesn't look like it has-anything nix-related in it. If it does, and $profile_target _did not_,-run:--  $ /usr/bin/sudo /bin/mv $profile_target$PROFILE_BACKUP_SUFFIX $profile_target--and try again.-EOF-        fi--        if [ -e "$profile_target" ] && grep -qi "nix" "$profile_target"; then-            failure <<EOF-It looks like $profile_target already has some Nix configuration in-there. There should be no reason to run this again. If you're having-trouble, please open an issue.-EOF-        fi-    done--    danger_paths=("$ROOT_HOME/.nix-defexpr" "$ROOT_HOME/.nix-channels" "$ROOT_HOME/.nix-profile")-    for danger_path in "${danger_paths[@]}"; do-        if _sudo "making sure that $danger_path doesn't exist" \-           test -e "$danger_path"; then-            failure <<EOF-I found a file at $danger_path, which is a relic of a previous-installation. You must first delete this file before continuing.--$(uninstall_directions)-EOF-        fi-    done-}--setup_report() {-    header "Nix config report"-    row "        Temp Dir" "$SCRATCH"-    row "        Nix Root" "$NIX_ROOT"-    row "     Build Users" "$NIX_USER_COUNT"-    row "  Build Group ID" "$NIX_BUILD_GROUP_ID"-    row "Build Group Name" "$NIX_BUILD_GROUP_NAME"-    if [ "${ALLOW_PREEXISTING_INSTALLATION:-}" != "" ]; then-        row "Preexisting Install" "Allowed"-    fi--    subheader "build users:"--    row "    Username" "UID"-    for i in $(seq 1 "$NIX_USER_COUNT"); do-        row "     $(nix_user_for_core "$i")" "$(nix_uid_for_core "$i")"-    done-    echo ""-}--create_build_group() {-    local primary_group_id--    task "Setting up the build group $NIX_BUILD_GROUP_NAME"-    if ! poly_group_exists "$NIX_BUILD_GROUP_NAME"; then-        poly_create_build_group-        row "            Created" "Yes"-    else-        primary_group_id=$(poly_group_id_get "$NIX_BUILD_GROUP_NAME")-        if [ "$primary_group_id" -ne "$NIX_BUILD_GROUP_ID" ]; then-            failure <<EOF-It seems the build group $NIX_BUILD_GROUP_NAME already exists, but-with the UID $primary_group_id. This script can't really handle-that right now, so I'm going to give up.--You can fix this by editing this script and changing the-NIX_BUILD_GROUP_ID variable near the top to from $NIX_BUILD_GROUP_ID-to $primary_group_id and re-run.-EOF-        else-            row "            Exists" "Yes"-        fi-    fi-}--create_build_user_for_core() {-    local coreid-    local username-    local uid--    coreid="$1"-    username=$(nix_user_for_core "$coreid")-    uid=$(nix_uid_for_core "$coreid")--    task "Setting up the build user $username"--    if ! poly_user_exists "$username"; then-        poly_create_build_user "$username" "$uid" "$coreid"-        row "           Created" "Yes"-    else-        actual_uid=$(poly_user_id_get "$username")-        if [ "$actual_uid" != "$uid" ]; then-            failure <<EOF-It seems the build user $username already exists, but with the UID-with the UID '$actual_uid'. This script can't really handle that right-now, so I'm going to give up.--If you already created the users and you know they start from-$actual_uid and go up from there, you can edit this script and change-NIX_FIRST_BUILD_UID near the top of the file to $actual_uid and try-again.-EOF-        else-            row "            Exists" "Yes"-        fi-    fi--    if [ "$(poly_user_hidden_get "$username")" = "1" ]; then-        row "            Hidden" "Yes"-    else-        poly_user_hidden_set "$username"-        row "            Hidden" "Yes"-    fi--    if [ "$(poly_user_home_get "$username")" = "/var/empty" ]; then-        row "    Home Directory" "/var/empty"-    else-        poly_user_home_set "$username" "/var/empty"-        row "    Home Directory" "/var/empty"-    fi--    # We use grep instead of an equality check because it is difficult-    # to extract _just_ the user's note, instead it is prefixed with-    # some plist junk. This was causing the user note to always be set,-    # even if there was no reason for it.-    if ! poly_user_note_get "$username" | grep -q "Nix build user $coreid"; then-        row "              Note" "Nix build user $coreid"-    else-        poly_user_note_set "$username" "Nix build user $coreid"-        row "              Note" "Nix build user $coreid"-    fi--    if [ "$(poly_user_shell_get "$username")" = "/sbin/nologin" ]; then-        row "   Logins Disabled" "Yes"-    else-        poly_user_shell_set "$username" "/sbin/nologin"-        row "   Logins Disabled" "Yes"-    fi--    if poly_user_in_group_check "$username" "$NIX_BUILD_GROUP_NAME"; then-        row "  Member of $NIX_BUILD_GROUP_NAME" "Yes"-    else-        poly_user_in_group_set "$username" "$NIX_BUILD_GROUP_NAME"-        row "  Member of $NIX_BUILD_GROUP_NAME" "Yes"-    fi--    if [ "$(poly_user_primary_group_get "$username")" = "$NIX_BUILD_GROUP_ID" ]; then-        row "    PrimaryGroupID" "$NIX_BUILD_GROUP_ID"-    else-        poly_user_primary_group_set "$username" "$NIX_BUILD_GROUP_ID"-        row "    PrimaryGroupID" "$NIX_BUILD_GROUP_ID"-    fi-}--create_build_users() {-    for i in $(seq 1 "$NIX_USER_COUNT"); do-        create_build_user_for_core "$i"-    done-}--create_directories() {-    _sudo "to make the basic directory structure of Nix (part 1)" \-          mkdir -pv -m 0755 /nix /nix/var /nix/var/log /nix/var/log/nix /nix/var/log/nix/drvs /nix/var/nix{,/db,/gcroots,/profiles,/temproots,/userpool}--    _sudo "to make the basic directory structure of Nix (part 2)" \-          mkdir -pv -m 1777 /nix/var/nix/{gcroots,profiles}/per-user--    _sudo "to make the basic directory structure of Nix (part 3)" \-          mkdir -pv -m 1775 /nix/store--    _sudo "to make the basic directory structure of Nix (part 4)" \-          chgrp "$NIX_BUILD_GROUP_NAME" /nix/store--    _sudo "to set up the root user's profile (part 1)" \-          mkdir -pv -m 0755 /nix/var/nix/profiles/per-user/root--    _sudo "to set up the root user's profile (part 2)" \-          mkdir -pv -m 0700 "$ROOT_HOME/.nix-defexpr"--    _sudo "to place the default nix daemon configuration (part 1)" \-          mkdir -pv -m 0555 /etc/nix-}--place_channel_configuration() {-    echo "https://nixos.org/channels/nixpkgs-unstable nixpkgs" > "$SCRATCH/.nix-channels"-    _sudo "to set up the default system channel (part 1)" \-          install -m 0664 "$SCRATCH/.nix-channels" "$ROOT_HOME/.nix-channels"-}--welcome_to_nix() {-    ok "Welcome to the Multi-User Nix Installation"--    cat <<EOF--This installation tool will set up your computer with the Nix package-manager. This will happen in a few stages:--1. Make sure your computer doesn't already have Nix. If it does, I-   will show you instructions on how to clean up your old one.--2. Show you what we are going to install and where. Then we will ask-   if you are ready to continue.--3. Create the system users and groups that the Nix daemon uses to run-   builds.--4. Perform the basic installation of the Nix files daemon.--5. Configure your shell to import special Nix Profile files, so you-   can use Nix.--6. Start the Nix daemon.--EOF--    if ui_confirm "Would you like to see a more detailed list of what we will do?"; then-        cat <<EOF--We will:-- - make sure your computer doesn't already have Nix files-   (if it does, I  will tell you how to clean them up.)- - create local users (see the list above for the users we'll make)- - create a local group ($NIX_BUILD_GROUP_NAME)- - install Nix in to $NIX_ROOT- - create a configuration file in /etc/nix- - set up the "default profile" by creating some Nix-related files in-   $ROOT_HOME-EOF-        for profile_target in "${PROFILE_TARGETS[@]}"; do-            if [ -e "$profile_target" ]; then-                cat <<EOF- - back up $profile_target to $profile_target$PROFILE_BACKUP_SUFFIX- - update $profile_target to include some Nix configuration-EOF-            fi-        done-        poly_service_setup_note-        if ! ui_confirm "Ready to continue?"; then-            failure <<EOF-Okay, maybe you would like to talk to the team.-EOF-        fi-    fi-}--chat_about_sudo() {-    header "let's talk about sudo"--    if headless; then-        cat <<EOF-This script is going to call sudo a lot. Normally, it would show you-exactly what commands it is running and why. However, the script is-run in a headless fashion, like this:--  $ curl https://nixos.org/nix/install | sh--or maybe in a CI pipeline. Because of that, we're going to skip the-verbose output in the interest of brevity.--If you would like to-see the output, try like this:--  $ curl -o install-nix https://nixos.org/nix/install-  $ sh ./install-nix--EOF-        return 0-    fi--    cat <<EOF-This script is going to call sudo a lot. Every time we do, it'll-output exactly what it'll do, and why.--Just like this:-EOF--    __sudo "to demonstrate how our sudo prompts look" \-           echo "this is a sudo prompt"--    cat <<EOF--This might look scary, but everything can be undone by running just a-few commands. We used to ask you to confirm each time sudo ran, but it-was too many times. Instead, I'll just ask you this one time:--EOF-    if ui_confirm "Can we use sudo?"; then-        ok "Yay! Thanks! Let's get going!"-    else-        failure <<EOF-That is okay, but we can't install.-EOF-    fi-}--install_from_extracted_nix() {-    (-        cd "$EXTRACTED_NIX_PATH"--        _sudo "to copy the basic Nix files to the new store at $NIX_ROOT/store" \-              rsync -rlpt ./store/* "$NIX_ROOT/store/"--        if [ -d "$NIX_INSTALLED_NIX" ]; then-            echo "      Alright! We have our first nix at $NIX_INSTALLED_NIX"-        else-            failure <<EOF-Something went wrong, and I didn't find Nix installed at-$NIX_INSTALLED_NIX.-EOF-        fi--        _sudo "to initialize the Nix Database" \-              $NIX_INSTALLED_NIX/bin/nix-store --init--        cat ./.reginfo \-            | _sudo "to load data for the first time in to the Nix Database" \-                   "$NIX_INSTALLED_NIX/bin/nix-store" --load-db--        echo "      Just finished getting the nix database ready."-    )-}--shell_source_lines() {-    cat <<EOF--# Nix-if [ -e '$PROFILE_NIX_FILE' ]; then-  . '$PROFILE_NIX_FILE'-fi-# End Nix--EOF-}--configure_shell_profile() {-    # If there is an /etc/profile.d directory, we want to ensure there-    # is a nix.sh within it, so we can use the following loop to add-    # the source lines to it. Note that I'm _not_ adding the source-    # lines here, because we want to be using the regular machinery.-    #-    # If we go around that machinery, it becomes more complicated and-    # adds complications to the uninstall instruction generator and-    # old instruction sniffer as well.-    if [ -d /etc/profile.d ]; then-        _sudo "create a stub /etc/profile.d/nix.sh which will be updated" \-              touch /etc/profile.d/nix.sh-    fi--    for profile_target in "${PROFILE_TARGETS[@]}"; do-        if [ -e "$profile_target" ]; then-            _sudo "to back up your current $profile_target to $profile_target$PROFILE_BACKUP_SUFFIX" \-                  cp "$profile_target" "$profile_target$PROFILE_BACKUP_SUFFIX"--            shell_source_lines \-                | _sudo "extend your $profile_target with nix-daemon settings" \-                        tee -a "$profile_target"-        fi-    done-}--setup_default_profile() {-    _sudo "to installing a bootstrapping Nix in to the default Profile" \-          HOME="$ROOT_HOME" "$NIX_INSTALLED_NIX/bin/nix-env" -i "$NIX_INSTALLED_NIX"--    _sudo "to installing a bootstrapping SSL certificate just for Nix in to the default Profile" \-          HOME="$ROOT_HOME" "$NIX_INSTALLED_NIX/bin/nix-env" -i "$NIX_INSTALLED_CACERT"--    _sudo "to update the default channel in the default profile" \-          HOME="$ROOT_HOME" NIX_SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt "$NIX_INSTALLED_NIX/bin/nix-channel" --update nixpkgs-}---place_nix_configuration() {-    cat <<EOF > "$SCRATCH/nix.conf"-build-users-group = $NIX_BUILD_GROUP_NAME--max-jobs = $NIX_USER_COUNT-cores = 1-sandbox = false-EOF-    _sudo "to place the default nix daemon configuration (part 2)" \-          install -m 0664 "$SCRATCH/nix.conf" /etc/nix/nix.conf-}--main() {-    if [ "$(uname -s)" = "Darwin" ]; then-        # shellcheck source=./install-darwin-multi-user.sh-        . "$EXTRACTED_NIX_PATH/install-darwin-multi-user.sh"-    elif [ "$(uname -s)" = "Linux" ] && [ -e /run/systemd/system ]; then-        # shellcheck source=./install-systemd-multi-user.sh-        . "$EXTRACTED_NIX_PATH/install-systemd-multi-user.sh"-    else-        failure "Sorry, I don't know what to do on $(uname)"-    fi--    welcome_to_nix-    chat_about_sudo--    if [ "${ALLOW_PREEXISTING_INSTALLATION:-}" = "" ]; then-        validate_starting_assumptions-    fi--    setup_report--    if ! ui_confirm "Ready to continue?"; then-        ok "Alright, no changes have been made :)"-        contactme-        trap finish_cleanup EXIT-        exit 1-    fi--    create_build_group-    create_build_users-    create_directories-    place_channel_configuration-    install_from_extracted_nix--    configure_shell_profile--    set +eu-    . /etc/profile-    set -eu--    setup_default_profile-    place_nix_configuration-    poly_configure_nix_daemon_service--    trap finish_success EXIT-}---main
− data/nix/scripts/install-nix-from-closure.sh
@@ -1,181 +0,0 @@-#!/bin/sh--set -e--dest="/nix"-self="$(dirname "$0")"-nix="@nix@"-cacert="@cacert@"---if ! [ -e "$self/.reginfo" ]; then-    echo "$0: incomplete installer (.reginfo is missing)" >&2-fi--if [ -z "$USER" ]; then-    echo "$0: \$USER is not set" >&2-    exit 1-fi--if [ -z "$HOME" ]; then-    echo "$0: \$HOME is not set" >&2-    exit 1-fi--# macOS support for 10.10 or higher-if [ "$(uname -s)" = "Darwin" ]; then-    if [ $(($(sw_vers -productVersion | cut -d '.' -f 2))) -lt 10 ]; then-        echo "$0: macOS $(sw_vers -productVersion) is not supported, upgrade to 10.10 or higher"-        exit 1-    fi-fi--# Determine if we should punt to the single-user installer or not-if [ "$(uname -s)" = "Darwin" ]; then-    INSTALL_MODE=daemon-elif [ "$(uname -s)" = "Linux" ] && [ -e /run/systemd/system ]; then-    INSTALL_MODE=daemon-else-    INSTALL_MODE=no-daemon-fi--# Trivially handle the --daemon / --no-daemon options-if [ "x${1:-}" = "x--no-daemon" ]; then-    INSTALL_MODE=no-daemon-elif [ "x${1:-}" = "x--daemon" ]; then-    INSTALL_MODE=daemon-elif [ "x${1:-}" != "x" ]; then-    (-        echo "Nix Installer [--daemon|--no-daemon]"-        echo ""-        echo " --daemon:    Force the installer to use the Daemon"-        echo "              based installer, even though it may not"-        echo "              work."-        echo ""-        echo " --no-daemon: Force a no-daemon, single-user"-        echo "              installation even when the preferred"-        echo "              method is with the daemon."-        echo ""-    ) >&2-    exit-fi--if [ "$INSTALL_MODE" = "daemon" ]; then-    printf '\e[1;31mSwitching to the Daemon-based Installer\e[0m\n'-    exec "$self/install-multi-user"-    exit 0-fi--if [ "$(id -u)" -eq 0 ]; then-    printf '\e[1;31mwarning: installing Nix as root is not supported by this script!\e[0m\n'-fi--echo "performing a single-user installation of Nix..." >&2--if ! [ -e $dest ]; then-    cmd="mkdir -m 0755 $dest && chown $USER $dest"-    echo "directory $dest does not exist; creating it by running '$cmd' using sudo" >&2-    if ! sudo sh -c "$cmd"; then-        echo "$0: please manually run '$cmd' as root to create $dest" >&2-        exit 1-    fi-fi--if ! [ -w $dest ]; then-    echo "$0: directory $dest exists, but is not writable by you. This could indicate that another user has already performed a single-user installation of Nix on this system. If you wish to enable multi-user support see http://nixos.org/nix/manual/#ssec-multi-user. If you wish to continue with a single-user install for $USER please run 'chown -R $USER $dest' as root." >&2-    exit 1-fi--mkdir -p $dest/store--printf "copying Nix to %s..." "${dest}/store" >&2--for i in $(cd "$self/store" >/dev/null && echo ./*); do-    printf "." >&2-    i_tmp="$dest/store/$i.$$"-    if [ -e "$i_tmp" ]; then-        rm -rf "$i_tmp"-    fi-    if ! [ -e "$dest/store/$i" ]; then-        cp -Rp "$self/store/$i" "$i_tmp"-        chmod -R a-w "$i_tmp"-        chmod +w "$i_tmp"-        mv "$i_tmp" "$dest/store/$i"-        chmod -w "$dest/store/$i"-    fi-done-echo "" >&2--echo "initialising Nix database..." >&2-if ! $nix/bin/nix-store --init; then-    echo "$0: failed to initialize the Nix database" >&2-    exit 1-fi--if ! "$nix/bin/nix-store" --load-db < "$self/.reginfo"; then-    echo "$0: unable to register valid paths" >&2-    exit 1-fi--. "$nix/etc/profile.d/nix.sh"--if ! "$nix/bin/nix-env" -i "$nix"; then-    echo "$0: unable to install Nix into your default profile" >&2-    exit 1-fi--# Install an SSL certificate bundle.-if [ -z "$NIX_SSL_CERT_FILE" ] || ! [ -f "$NIX_SSL_CERT_FILE" ]; then-    $nix/bin/nix-env -i "$cacert"-    export NIX_SSL_CERT_FILE="$HOME/.nix-profile/etc/ssl/certs/ca-bundle.crt"-fi--# Subscribe the user to the Nixpkgs channel and fetch it.-if ! $nix/bin/nix-channel --list | grep -q "^nixpkgs "; then-    $nix/bin/nix-channel --add https://nixos.org/channels/nixpkgs-unstable-fi-if [ -z "$_NIX_INSTALLER_TEST" ]; then-    $nix/bin/nix-channel --update nixpkgs-fi--added=-if [ -z "$NIX_INSTALLER_NO_MODIFY_PROFILE" ]; then--    # Make the shell source nix.sh during login.-    p=$HOME/.nix-profile/etc/profile.d/nix.sh--    for i in .bash_profile .bash_login .profile; do-        fn="$HOME/$i"-        if [ -w "$fn" ]; then-            if ! grep -q "$p" "$fn"; then-                echo "modifying $fn..." >&2-                echo "if [ -e $p ]; then . $p; fi # added by Nix installer" >> "$fn"-            fi-            added=1-            break-        fi-    done--fi--if [ -z "$added" ]; then-    cat >&2 <<EOF--Installation finished!  To ensure that the necessary environment-variables are set, please add the line--  . $p--to your shell profile (e.g. ~/.profile).-EOF-else-    cat >&2 <<EOF--Installation finished!  To ensure that the necessary environment-variables are set, either log in again, or type--  . $p--in your shell.-EOF-fi
− data/nix/scripts/install-systemd-multi-user.sh
@@ -1,154 +0,0 @@-#!/usr/bin/env bash--set -eu-set -o pipefail--readonly SERVICE_SRC=/lib/systemd/system/nix-daemon.service-readonly SERVICE_DEST=/etc/systemd/system/nix-daemon.service--readonly SOCKET_SRC=/lib/systemd/system/nix-daemon.socket-readonly SOCKET_DEST=/etc/systemd/system/nix-daemon.socket--poly_validate_assumptions() {-    if [ "$(uname -s)" != "Linux" ]; then-        failure "This script is for use with Linux!"-    fi-}--poly_service_installed_check() {-    [ "$(systemctl is-enabled nix-daemon.service)" = "linked" ] \-        || [ "$(systemctl is-enabled nix-daemon.socket)" = "enabled" ]-}--poly_service_uninstall_directions() {-        cat <<EOF-$1. Delete the systemd service and socket units--  sudo systemctl stop nix-daemon.socket-  sudo systemctl stop nix-daemon.service-  sudo systemctl disable nix-daemon.socket-  sudo systemctl disable nix-daemon.service-  sudo systemctl daemon-reload-EOF-}--poly_service_setup_note() {-    cat <<EOF- - load and start a service (at $SERVICE_DEST-   and $SOCKET_DEST) for nix-daemon--EOF-}--poly_configure_nix_daemon_service() {-    _sudo "to set up the nix-daemon service" \-          systemctl link "/nix/var/nix/profiles/default$SERVICE_SRC"--    _sudo "to set up the nix-daemon socket service" \-          systemctl enable "/nix/var/nix/profiles/default$SOCKET_SRC"--    _sudo "to load the systemd unit for nix-daemon" \-          systemctl daemon-reload--    _sudo "to start the nix-daemon.socket" \-          systemctl start nix-daemon.socket--    _sudo "to start the nix-daemon.service" \-          systemctl start nix-daemon.service--}--poly_group_exists() {-    getent group "$1" > /dev/null 2>&1-}--poly_group_id_get() {-    getent group "$1" | cut -d: -f3-}--poly_create_build_group() {-    _sudo "Create the Nix build group, $NIX_BUILD_GROUP_NAME" \-          groupadd -g "$NIX_BUILD_GROUP_ID" --system \-          "$NIX_BUILD_GROUP_NAME" >&2-}--poly_user_exists() {-    getent passwd "$1" > /dev/null 2>&1-}--poly_user_id_get() {-    getent passwd "$1" | cut -d: -f3-}--poly_user_hidden_get() {-    echo "1"-}--poly_user_hidden_set() {-    true-}--poly_user_home_get() {-    getent passwd "$1" | cut -d: -f6-}--poly_user_home_set() {-    _sudo "in order to give $1 a safe home directory" \-          usermod --home "$2" "$1"-}--poly_user_note_get() {-    getent passwd "$1" | cut -d: -f5-}--poly_user_note_set() {-    _sudo "in order to give $1 a useful comment" \-          usermod --comment "$2" "$1"-}--poly_user_shell_get() {-    getent passwd "$1" | cut -d: -f7-}--poly_user_shell_set() {-    _sudo "in order to prevent $1 from logging in" \-          usermod --shell "$2" "$1"-}--poly_user_in_group_check() {-    groups "$1" | grep -q "$2" > /dev/null 2>&1-}--poly_user_in_group_set() {-    _sudo "Add $1 to the $2 group"\-          usermod --append --groups "$2" "$1"-}--poly_user_primary_group_get() {-    getent passwd "$1" | cut -d: -f4-}--poly_user_primary_group_set() {-    _sudo "to let the nix daemon use this user for builds (this might seem redundant, but there are two concepts of group membership)" \-          usermod --gid "$2" "$1"--}--poly_create_build_user() {-    username=$1-    uid=$2-    builder_num=$3--    _sudo "Creating the Nix build user, $username" \-          useradd \-          --home-dir /var/empty \-          --comment "Nix build user $builder_num" \-          --gid "$NIX_BUILD_GROUP_ID" \-          --groups "$NIX_BUILD_GROUP_NAME" \-          --no-user-group \-          --system \-          --shell /sbin/nologin \-          --uid "$uid" \-          --password "!" \-          "$username"-}
− data/nix/scripts/local.mk
@@ -1,13 +0,0 @@-nix_noinst_scripts := \-  $(d)/nix-http-export.cgi \-  $(d)/nix-profile.sh \-  $(d)/nix-reduce-build--noinst-scripts += $(nix_noinst_scripts)--profiledir = $(sysconfdir)/profile.d--$(eval $(call install-file-as, $(d)/nix-profile.sh, $(profiledir)/nix.sh, 0644))-$(eval $(call install-file-as, $(d)/nix-profile-daemon.sh, $(profiledir)/nix-daemon.sh, 0644))--clean-files += $(nix_noinst_scripts)
− data/nix/scripts/nix-http-export.cgi.in
@@ -1,51 +0,0 @@-#! /bin/sh--export HOME=/tmp-export NIX_REMOTE=daemon--TMP_DIR="${TMP_DIR:-/tmp/nix-export}"--@coreutils@/mkdir -p "$TMP_DIR" || true-@coreutils@/chmod a+r "$TMP_DIR"--needed_path="?$QUERY_STRING"-needed_path="${needed_path#*[?&]needed_path=}"-needed_path="${needed_path%%&*}"-#needed_path="$(echo $needed_path  | ./unhttp)"-needed_path="${needed_path//%2B/+}"-needed_path="${needed_path//%3D/=}"--echo needed_path: "$needed_path" >&2--NIX_STORE="${NIX_STORE_DIR:-/nix/store}"--echo NIX_STORE: "${NIX_STORE}" >&2--full_path="${NIX_STORE}"/"$needed_path"--if [ "$needed_path" != "${needed_path%.drv}" ]; then-	echo "Status: 403 You should create the derivation file yourself"-	echo "Content-Type: text/plain"-	echo-	echo "Refusing to disclose derivation contents"-	exit-fi--if @bindir@/nix-store --check-validity "$full_path"; then-	if ! [ -e nix-export/"$needed_path".nar.gz ]; then-		@bindir@/nix-store --export "$full_path" | @gzip@ > "$TMP_DIR"/"$needed_path".nar.gz-		@coreutils@/ln -fs  "$TMP_DIR"/"$needed_path".nar.gz nix-export/"$needed_path".nar.gz -	fi;-	echo "Status: 301 Moved"-	echo "Location: nix-export/"$needed_path".nar.gz"-	echo-else -	echo "Status: 404 No such path found"-	echo "Content-Type: text/plain"-	echo-	echo "Path not found:"-	echo "$needed_path"-	echo "checked:"-	echo "$full_path"-fi-
− data/nix/scripts/nix-profile-daemon.sh.in
@@ -1,54 +0,0 @@-# Only execute this file once per shell.-if [ -n "$__ETC_PROFILE_NIX_SOURCED" ]; then return; fi-__ETC_PROFILE_NIX_SOURCED=1--# Set up secure multi-user builds: non-root users build through the-# Nix daemon.-if [ "$USER" != root -o ! -w @localstatedir@/nix/db ]; then-    export NIX_REMOTE=daemon-fi--export NIX_USER_PROFILE_DIR="@localstatedir@/nix/profiles/per-user/$USER"-export NIX_PROFILES="@localstatedir@/nix/profiles/default $HOME/.nix-profile"--# Set up the per-user profile.-mkdir -m 0755 -p $NIX_USER_PROFILE_DIR-if ! test -O "$NIX_USER_PROFILE_DIR"; then-    echo "WARNING: bad ownership on $NIX_USER_PROFILE_DIR" >&2-fi--if test -w $HOME; then-  if ! test -L $HOME/.nix-profile; then-      if test "$USER" != root; then-          ln -s $NIX_USER_PROFILE_DIR/profile $HOME/.nix-profile-      else-          # Root installs in the system-wide profile by default.-          ln -s @localstatedir@/nix/profiles/default $HOME/.nix-profile-      fi-  fi--  # Subscribe the root user to the NixOS channel by default.-  if [ "$USER" = root -a ! -e $HOME/.nix-channels ]; then-      echo "https://nixos.org/channels/nixpkgs-unstable nixpkgs" > $HOME/.nix-channels-  fi--  # Create the per-user garbage collector roots directory.-  NIX_USER_GCROOTS_DIR=@localstatedir@/nix/gcroots/per-user/$USER-  mkdir -m 0755 -p $NIX_USER_GCROOTS_DIR-  if ! test -O "$NIX_USER_GCROOTS_DIR"; then-      echo "WARNING: bad ownership on $NIX_USER_GCROOTS_DIR" >&2-  fi--  # Set up a default Nix expression from which to install stuff.-  if [ ! -e $HOME/.nix-defexpr -o -L $HOME/.nix-defexpr ]; then-      rm -f $HOME/.nix-defexpr-      mkdir -p $HOME/.nix-defexpr-      if [ "$USER" != root ]; then-          ln -s @localstatedir@/nix/profiles/per-user/root/channels $HOME/.nix-defexpr/channels_root-      fi-  fi-fi--export NIX_SSL_CERT_FILE="@localstatedir@/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"-export NIX_PATH="@localstatedir@/nix/profiles/per-user/root/channels"-export PATH="$HOME/.nix-profile/bin:$HOME/.nix-profile/lib/kde4/libexec:@localstatedir@/nix/profiles/default/bin:@localstatedir@/nix/profiles/default:@localstatedir@/nix/profiles/default/lib/kde4/libexec:$PATH"
− data/nix/scripts/nix-profile.sh.in
@@ -1,84 +0,0 @@-if [ -n "$HOME" ] && [ -n "$USER" ]; then-    __savedpath="$PATH"-    export PATH=@coreutils@--    # Set up the per-user profile.-    # This part should be kept in sync with nixpkgs:nixos/modules/programs/shell.nix--    NIX_LINK=$HOME/.nix-profile--    NIX_USER_PROFILE_DIR=@localstatedir@/nix/profiles/per-user/$USER--    mkdir -m 0755 -p "$NIX_USER_PROFILE_DIR"--    if [ "$(stat --printf '%u' "$NIX_USER_PROFILE_DIR")" != "$(id -u)" ]; then-        echo "Nix: WARNING: bad ownership on "$NIX_USER_PROFILE_DIR", should be $(id -u)" >&2-    fi--    if [ -w "$HOME" ]; then-        if ! [ -L "$NIX_LINK" ]; then-            echo "Nix: creating $NIX_LINK" >&2-            if [ "$USER" != root ]; then-                if ! ln -s "$NIX_USER_PROFILE_DIR"/profile "$NIX_LINK"; then-                    echo "Nix: WARNING: could not create $NIX_LINK -> $NIX_USER_PROFILE_DIR/profile" >&2-                fi-            else-                # Root installs in the system-wide profile by default.-                ln -s @localstatedir@/nix/profiles/default "$NIX_LINK"-            fi-        fi--        # Subscribe the user to the unstable Nixpkgs channel by default.-        if [ ! -e "$HOME/.nix-channels" ]; then-            echo "https://nixos.org/channels/nixpkgs-unstable nixpkgs" > "$HOME/.nix-channels"-        fi--        # Create the per-user garbage collector roots directory.-        __user_gcroots=@localstatedir@/nix/gcroots/per-user/"$USER"-        mkdir -m 0755 -p "$__user_gcroots"-        if [ "$(stat --printf '%u' "$__user_gcroots")" != "$(id -u)" ]; then-            echo "Nix: WARNING: bad ownership on $__user_gcroots, should be $(id -u)" >&2-        fi-        unset __user_gcroots--        # Set up a default Nix expression from which to install stuff.-        __nix_defexpr="$HOME"/.nix-defexpr-        [ -L "$__nix_defexpr" ] && rm -f "$__nix_defexpr"-        mkdir -m 0755 -p "$__nix_defexpr"-        if [ "$USER" != root ] && [ ! -L "$__nix_defexpr"/channels_root ]; then-            ln -s @localstatedir@/nix/profiles/per-user/root/channels "$__nix_defexpr"/channels_root-        fi-        unset __nix_defexpr-    fi--    # Append ~/.nix-defexpr/channels/nixpkgs to $NIX_PATH so that-    # <nixpkgs> paths work when the user has fetched the Nixpkgs-    # channel.-    export NIX_PATH="${NIX_PATH:+$NIX_PATH:}nixpkgs=$HOME/.nix-defexpr/channels/nixpkgs"--    # Set up environment.-    # This part should be kept in sync with nixpkgs:nixos/modules/programs/environment.nix-    NIX_PROFILES="@localstatedir@/nix/profiles/default $NIX_USER_PROFILE_DIR"--    # Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.-    if [ -e /etc/ssl/certs/ca-certificates.crt ]; then # NixOS, Ubuntu, Debian, Gentoo, Arch-        export NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt-    elif [ -e /etc/ssl/ca-bundle.pem ]; then # openSUSE Tumbleweed-        export NIX_SSL_CERT_FILE=/etc/ssl/ca-bundle.pem-    elif [ -e /etc/ssl/certs/ca-bundle.crt ]; then # Old NixOS-        export NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt-    elif [ -e /etc/pki/tls/certs/ca-bundle.crt ]; then # Fedora, CentOS-        export NIX_SSL_CERT_FILE=/etc/pki/tls/certs/ca-bundle.crt-    elif [ -e "$NIX_LINK/etc/ssl/certs/ca-bundle.crt" ]; then # fall back to cacert in Nix profile-        export NIX_SSL_CERT_FILE="$NIX_LINK/etc/ssl/certs/ca-bundle.crt"-    elif [ -e "$NIX_LINK/etc/ca-bundle.crt" ]; then # old cacert in Nix profile-        export NIX_SSL_CERT_FILE="$NIX_LINK/etc/ca-bundle.crt"-    fi--    if [ -n "${MANPATH}" ]; then-        export MANPATH="$NIX_LINK/share/man:$MANPATH"-    fi--    export PATH="$NIX_LINK/bin:$__savedpath"-    unset __savedpath NIX_LINK NIX_USER_PROFILE_DIR NIX_PROFILES-fi
− data/nix/scripts/nix-reduce-build.in
@@ -1,171 +0,0 @@-#! @bash@--WORKING_DIRECTORY=$(mktemp -d "${TMPDIR:-/tmp}"/nix-reduce-build-XXXXXX);-cd "$WORKING_DIRECTORY";--if test -z "$1" || test "a--help" = "a$1" ; then-	echo 'nix-reduce-build (paths or Nix expressions) -- (package sources)' >&2-	echo As in: >&2-	echo nix-reduce-build /etc/nixos/nixos -- ssh://user@somewhere.nowhere.example.org >&2-	echo nix-reduce-build /etc/nixos/nixos -- \\-	echo "   " \''http://somewhere.nowhere.example.org/nix/nix-http-export.cgi?needed_path='\' >&2-	echo "  store path name will be added into the end of the URL" >&2-	echo nix-reduce-build /etc/nixos/nixos -- file://home/user/nar/ >&2-	echo "  that should be a directory where gzipped 'nix-store --export' ">&2-	echo "  files are located (they should have .nar.gz extension)"  >&2-	echo "        Or all together: " >&2-	echo -e nix-reduce-build /expr.nix /e2.nix -- \\\\\\\n\-	"    ssh://a@b.example.com http://n.example.com/get-nar?q= file://nar/" >&2-	echo "        Also supports best-effort local builds of failing expression set:" >&2-	echo "nix-reduce-build /e.nix -- nix-daemon:// nix-self://" >&2-	echo "  nix-daemon:// builds using daemon"-	echo "  nix-self:// builds directly using nix-store from current installation" >&2-	echo "  nix-daemon-fixed:// and nix-self-fixed:// do the same, but only for" >&2;-	echo "derivations with specified output hash (sha256, sha1 or md5)." >&2-	echo "  nix-daemon-substitute:// and nix-self-substitute:// try to substitute" >&2;-	echo "maximum amount of paths" >&2;-	echo "  nix-daemon-build:// and nix-self-build:// try to build (not substitute)" >&2;-	echo "maximum amount of paths" >&2;-	echo "        If no package sources are specified, required paths are listed." >&2;-	exit;-fi;--while ! test "$1" = "--" || test "$1" = "" ; do -	echo "$1" >> initial; >&2-	shift;-done-shift;-echo Will work on $(cat initial | wc -l) targets. >&2--while read ; do-	case "$REPLY" in -		${NIX_STORE_DIR:-/nix/store}/*)-			echo "$REPLY" >> paths; >&2-			;;-		*)-			(-				IFS=: ;-				nix-instantiate $REPLY >> paths;-			);-			;;-	esac;-done < initial;-echo Proceeding $(cat paths | wc -l) paths. >&2--while read; do-	case "$REPLY" in-		*.drv)-			echo "$REPLY" >> derivers; >&2-			;;-		*)-			nix-store --query --deriver "$REPLY" >>derivers;-			;;-	esac;-done < paths;-echo Found $(cat derivers | wc -l) derivers. >&2--cat derivers | xargs nix-store --query -R > derivers-closure;-echo Proceeding at most $(cat derivers-closure | wc -l) derivers. >&2--cat derivers-closure | egrep '[.]drv$' | xargs nix-store --query --outputs > wanted-paths;-cat derivers-closure | egrep -v '[.]drv$' >> wanted-paths;-echo Prepared $(cat wanted-paths | wc -l) paths to get. >&2--cat wanted-paths | xargs nix-store --check-validity --print-invalid > needed-paths;-echo We need $(cat needed-paths | wc -l) paths. >&2--egrep '[.]drv$' derivers-closure > critical-derivers;--if test -z "$1" ; then-	cat needed-paths;	-fi;--refresh_critical_derivers() {-    echo "Finding needed derivers..." >&2;-    cat critical-derivers | while read; do-        if ! (nix-store --query --outputs "$REPLY" | xargs nix-store --check-validity &> /dev/null;); then-            echo "$REPLY";-        fi;-    done > new-critical-derivers;-    mv new-critical-derivers critical-derivers;-    echo The needed paths are realized by $(cat critical-derivers | wc -l) derivers. >&2-}--build_here() {-    cat critical-derivers | while read; do -        echo "Realising $REPLY using nix-daemon" >&2-        @bindir@/nix-store -r "${REPLY}"-    done;-}--try_to_substitute(){-    cat needed-paths | while read ; do -        echo "Building $REPLY using nix-daemon" >&2-        @bindir@/nix-store -r "${NIX_STORE_DIR:-/nix/store}/${REPLY##*/}"-    done;-}--for i in "$@"; do -	sshHost="${i#ssh://}";-	httpHost="${i#http://}";-	httpsHost="${i#https://}";-	filePath="${i#file:/}";-	if [ "$i" != "$sshHost" ]; then-		cat needed-paths | while read; do -			echo "Getting $REPLY and its closure over ssh" >&2-			nix-copy-closure --from "$sshHost" --gzip "$REPLY" </dev/null || true; -		done;-	elif [ "$i" != "$httpHost" ] || [ "$i" != "$httpsHost" ]; then-		cat needed-paths | while read; do-			echo "Getting $REPLY over http/https" >&2-			curl ${BAD_CERTIFICATE:+-k} -L "$i${REPLY##*/}" | gunzip | nix-store --import;-		done;-	elif [ "$i" != "$filePath" ] ; then-		cat needed-paths | while read; do -			echo "Installing $REPLY from file" >&2-			gunzip < "$filePath/${REPLY##*/}".nar.gz | nix-store --import;-		done;-	elif [ "$i" = "nix-daemon://" ] ; then-		NIX_REMOTE=daemon try_to_substitute;-		refresh_critical_derivers;-		NIX_REMOTE=daemon build_here;-	elif [ "$i" = "nix-self://" ] ; then-		NIX_REMOTE= try_to_substitute;-		refresh_critical_derivers;-		NIX_REMOTE= build_here;-	elif [ "$i" = "nix-daemon-fixed://" ] ; then-		refresh_critical_derivers;--		cat critical-derivers | while read; do -			if egrep '"(md5|sha1|sha256)"' "$REPLY" &>/dev/null; then-				echo "Realising $REPLY using nix-daemon" >&2-				NIX_REMOTE=daemon @bindir@/nix-store -r "${REPLY}"-			fi;-		done;-	elif [ "$i" = "nix-self-fixed://" ] ; then-		refresh_critical_derivers;--		cat critical-derivers | while read; do -			if egrep '"(md5|sha1|sha256)"' "$REPLY" &>/dev/null; then-				echo "Realising $REPLY using direct Nix build" >&2-				NIX_REMOTE= @bindir@/nix-store -r "${REPLY}"-			fi;-		done;-	elif [ "$i" = "nix-daemon-substitute://" ] ; then-		NIX_REMOTE=daemon try_to_substitute;-	elif [ "$i" = "nix-self-substitute://" ] ; then-		NIX_REMOTE= try_to_substitute;-	elif [ "$i" = "nix-daemon-build://" ] ; then-		refresh_critical_derivers;-		NIX_REMOTE=daemon build_here;-	elif [ "$i" = "nix-self-build://" ] ; then-		refresh_critical_derivers;-		NIX_REMOTE= build_here;-	fi;-	mv needed-paths wanted-paths;-	cat wanted-paths | xargs nix-store --check-validity --print-invalid > needed-paths;-	echo We still need $(cat needed-paths | wc -l) paths. >&2-done;--cd /-rm -r "$WORKING_DIRECTORY"
− data/nix/shell.nix
@@ -1,25 +0,0 @@-{ useClang ? false }:--with import (builtins.fetchGit { url = https://github.com/NixOS/nixpkgs-channels.git; ref = "nixos-18.03"; }) {};--with import ./release-common.nix { inherit pkgs; };--(if useClang then clangStdenv else stdenv).mkDerivation {-  name = "nix";--  buildInputs = buildDeps ++ tarballDeps ++ perlDeps;--  inherit configureFlags;--  enableParallelBuilding = true;--  installFlags = "sysconfdir=$(out)/etc";--  shellHook =-    ''-      export prefix=$(pwd)/inst-      configureFlags+=" --prefix=$prefix"-      PKG_CONFIG_PATH=$prefix/lib/pkgconfig:$PKG_CONFIG_PATH-      PATH=$prefix/bin:$PATH-    '';-}
− data/nix/tests/add.sh
@@ -1,28 +0,0 @@-source common.sh--path1=$(nix-store --add ./dummy)-echo $path1--path2=$(nix-store --add-fixed sha256 --recursive ./dummy)-echo $path2--if test "$path1" != "$path2"; then-    echo "nix-store --add and --add-fixed mismatch"-    exit 1-fi    --path3=$(nix-store --add-fixed sha256 ./dummy)-echo $path3-test "$path1" != "$path3" || exit 1--path4=$(nix-store --add-fixed sha1 --recursive ./dummy)-echo $path4-test "$path1" != "$path4" || exit 1--hash1=$(nix-store -q --hash $path1)-echo $hash1--hash2=$(nix-hash --type sha256 --base32 ./dummy)-echo $hash2--test "$hash1" = "sha256:$hash2"
− data/nix/tests/binary-cache.sh
@@ -1,161 +0,0 @@-source common.sh--clearStore-clearCache--# Create the binary cache.-outPath=$(nix-build dependencies.nix --no-out-link)--nix copy --to file://$cacheDir $outPath---basicTests() {--    # By default, a binary cache doesn't support "nix-env -qas", but does-    # support installation.-    clearStore-    clearCacheCache--    nix-env --substituters "file://$cacheDir" -f dependencies.nix -qas \* | grep -- "---"--    nix-store --substituters "file://$cacheDir" --no-require-sigs -r $outPath--    [ -x $outPath/program ]---    # But with the right configuration, "nix-env -qas" should also work.-    clearStore-    clearCacheCache-    echo "WantMassQuery: 1" >> $cacheDir/nix-cache-info--    nix-env --substituters "file://$cacheDir" -f dependencies.nix -qas \* | grep -- "--S"-    nix-env --substituters "file://$cacheDir" -f dependencies.nix -qas \* | grep -- "--S"--    x=$(nix-env -f dependencies.nix -qas \* --prebuilt-only)-    [ -z "$x" ]--    nix-store --substituters "file://$cacheDir" --no-require-sigs -r $outPath--    nix-store --check-validity $outPath-    nix-store -qR $outPath | grep input-2--    echo "WantMassQuery: 0" >> $cacheDir/nix-cache-info-}---# Test LocalBinaryCacheStore.-basicTests---# Test HttpBinaryCacheStore.-export _NIX_FORCE_HTTP_BINARY_CACHE_STORE=1-basicTests---unset _NIX_FORCE_HTTP_BINARY_CACHE_STORE---# Test whether Nix notices if the NAR doesn't match the hash in the NAR info.-clearStore--nar=$(ls $cacheDir/nar/*.nar.xz | head -n1)-mv $nar $nar.good-mkdir -p $TEST_ROOT/empty-nix-store --dump $TEST_ROOT/empty | xz > $nar--nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result 2>&1 | tee $TEST_ROOT/log-grep -q "hash mismatch" $TEST_ROOT/log--mv $nar.good $nar---# Test whether this unsigned cache is rejected if the user requires signed caches.-clearStore-clearCacheCache--if nix-store --substituters "file://$cacheDir" -r $outPath; then-    echo "unsigned binary cache incorrectly accepted"-    exit 1-fi---# Test whether fallback works if we have cached info but the-# corresponding NAR has disappeared.-clearStore--nix-build --substituters "file://$cacheDir" dependencies.nix --dry-run # get info--mkdir $cacheDir/tmp-mv $cacheDir/*.nar* $cacheDir/tmp/--NIX_DEBUG_SUBST=1 nix-build --substituters "file://$cacheDir" dependencies.nix -o $TEST_ROOT/result --fallback--mv $cacheDir/tmp/* $cacheDir/---# Test whether building works if the binary cache contains an-# incomplete closure.-clearStore--rm $(grep -l "StorePath:.*dependencies-input-2" $cacheDir/*.narinfo)--nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result 2>&1 | tee $TEST_ROOT/log-grep -q "copying path" $TEST_ROOT/log---if [ -n "$HAVE_SODIUM" ]; then--# Create a signed binary cache.-clearCache--declare -a res=($(nix-store --generate-binary-cache-key test.nixos.org-1 $TEST_ROOT/sk1 $TEST_ROOT/pk1 ))-publicKey="$(cat $TEST_ROOT/pk1)"--res=($(nix-store --generate-binary-cache-key test.nixos.org-1 $TEST_ROOT/sk2 $TEST_ROOT/pk2))-badKey="$(cat $TEST_ROOT/pk2)"--res=($(nix-store --generate-binary-cache-key foo.nixos.org-1 $TEST_ROOT/sk3 $TEST_ROOT/pk3))-otherKey="$(cat $TEST_ROOT/pk3)"--nix copy --to file://$cacheDir?secret-key=$TEST_ROOT/sk1 $outPath---# Downloading should fail if we don't provide a key.-clearStore-clearCacheCache--(! nix-store -r $outPath --substituters "file://$cacheDir")---# And it should fail if we provide an incorrect key.-clearStore-clearCacheCache--(! nix-store -r $outPath --substituters "file://$cacheDir" --trusted-public-keys "$badKey")---# It should succeed if we provide the correct key.-nix-store -r $outPath --substituters "file://$cacheDir" --trusted-public-keys "$otherKey $publicKey"---# It should fail if we corrupt the .narinfo.-clearStore--cacheDir2=$TEST_ROOT/binary-cache-2-rm -rf $cacheDir2-cp -r $cacheDir $cacheDir2--for i in $cacheDir2/*.narinfo; do-    grep -v References $i > $i.tmp-    mv $i.tmp $i-done--clearCacheCache--(! nix-store -r $outPath --substituters "file://$cacheDir2" --trusted-public-keys "$publicKey")--# If we provide a bad and a good binary cache, it should succeed.--nix-store -r $outPath --substituters "file://$cacheDir2 file://$cacheDir" --trusted-public-keys "$publicKey"--fi # HAVE_LIBSODIUM
− data/nix/tests/brotli.sh
@@ -1,28 +0,0 @@-source common.sh---# Only test if we found brotli libraries-# (CLI tool is likely unavailable if libraries are missing)-if [ -n "$HAVE_BROTLI" ]; then--clearStore-clearCache--cacheURI="file://$cacheDir?compression=br"--outPath=$(nix-build dependencies.nix --no-out-link)--nix copy --to $cacheURI $outPath--HASH=$(nix hash-path $outPath)--clearStore-clearCacheCache--nix copy --from $cacheURI $outPath --no-check-sigs--HASH2=$(nix hash-path $outPath)--[[ $HASH = $HASH2 ]]--fi # HAVE_BROTLI
− data/nix/tests/build-dry.sh
@@ -1,52 +0,0 @@-source common.sh--###################################################-# Check that --dry-run isn't confused with read-only mode-# https://github.com/NixOS/nix/issues/1795--clearStore-clearCache--# Ensure this builds successfully first-nix build -f dependencies.nix--clearStore-clearCache--# Try --dry-run using old command first-nix-build dependencies.nix --dry-run 2>&1 | grep "will be built"-# Now new command:-nix build -f dependencies.nix --dry-run 2>&1 | grep "will be built"--# TODO: XXX: FIXME: #1793-# Disable this part of the test until the problem is resolved:-if [ -n "$ISSUE_1795_IS_FIXED" ]; then-clearStore-clearCache--# Try --dry-run using new command first-nix build -f dependencies.nix --dry-run 2>&1 | grep "will be built"-# Now old command:-nix-build dependencies.nix --dry-run 2>&1 | grep "will be built"-fi--###################################################-# Check --dry-run doesn't create links with --dry-run-# https://github.com/NixOS/nix/issues/1849-clearStore-clearCache--RESULT=$TEST_ROOT/result-link-rm -f $RESULT--nix-build dependencies.nix -o $RESULT --dry-run--[[ ! -h $RESULT ]] || fail "nix-build --dry-run created output link"--nix build -f dependencies.nix -o $RESULT --dry-run--[[ ! -h $RESULT ]] || fail "nix build --dry-run created output link"--nix build -f dependencies.nix -o $RESULT--[[ -h $RESULT ]]
− data/nix/tests/build-hook.nix
@@ -1,23 +0,0 @@-with import ./config.nix;--let--  input1 = mkDerivation {-    name = "build-hook-input-1";-    builder = ./dependencies.builder1.sh;-    requiredSystemFeatures = ["foo"];-  };--  input2 = mkDerivation {-    name = "build-hook-input-2";-    builder = ./dependencies.builder2.sh;-  };--in--  mkDerivation {-    name = "build-hook";-    builder = ./dependencies.builder0.sh;-    input1 = " " + input1 + "/.";-    input2 = " ${input2}/.";-  }
− data/nix/tests/build-remote.sh
@@ -1,23 +0,0 @@-source common.sh--clearStore--if ! canUseSandbox; then exit; fi-if [[ ! $SHELL =~ /nix/store ]]; then exit; fi--chmod -R u+w $TEST_ROOT/store0 || true-chmod -R u+w $TEST_ROOT/store1 || true-rm -rf $TEST_ROOT/store0 $TEST_ROOT/store1--nix build -f build-hook.nix -o $TEST_ROOT/result --max-jobs 0 \-  --sandbox-paths /nix/store --sandbox-build-dir /build-tmp \-  --builders "$TEST_ROOT/store0; $TEST_ROOT/store1 - - 1 1 foo"--outPath=$TEST_ROOT/result--cat $outPath/foobar | grep FOOBAR--# Ensure that input1 was built on store1 due to the required feature.-p=$(readlink -f $outPath/input-2)-(! nix path-info --store $TEST_ROOT/store0 --all | grep dependencies.builder1.sh)-nix path-info --store $TEST_ROOT/store1 --all | grep dependencies.builder1.sh
− data/nix/tests/case-hack.sh
@@ -1,19 +0,0 @@-source common.sh--clearStore--rm -rf $TEST_ROOT/case--opts="--option use-case-hack true"--# Check whether restoring and dumping a NAR that contains case-# collisions is round-tripping, even on a case-insensitive system.-nix-store $opts  --restore $TEST_ROOT/case < case.nar-nix-store $opts --dump $TEST_ROOT/case > $TEST_ROOT/case.nar-cmp case.nar $TEST_ROOT/case.nar-[ "$(nix-hash $opts --type sha256 $TEST_ROOT/case)" = "$(nix-hash --flat --type sha256 case.nar)" ]--# Check whether we detect true collisions (e.g. those remaining after-# removal of the suffix).-touch "$TEST_ROOT/case/xt_CONNMARK.h~nix~case~hack~3"-(! nix-store $opts --dump $TEST_ROOT/case > /dev/null)
− data/nix/tests/case.nar

binary file changed (2416 → absent bytes)

− data/nix/tests/check-refs.nix
@@ -1,70 +0,0 @@-with import ./config.nix;--rec {--  dep = import ./dependencies.nix;--  makeTest = nr: args: mkDerivation ({-    name = "check-refs-" + toString nr;-  } // args);--  src = builtins.toFile "aux-ref" "bla bla";--  test1 = makeTest 1 {-    builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $dep $out/link";-    inherit dep;-  };--  test2 = makeTest 2 {-    builder = builtins.toFile "builder.sh" "mkdir $out; ln -s ${src} $out/link";-    inherit dep;-  };--  test3 = makeTest 3 {-    builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $dep $out/link";-    allowedReferences = [];-    inherit dep;-  };--  test4 = makeTest 4 {-    builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $dep $out/link";-    allowedReferences = [dep];-    inherit dep;-  };--  test5 = makeTest 5 {-    builder = builtins.toFile "builder.sh" "mkdir $out";-    allowedReferences = [];-    inherit dep;-  };--  test6 = makeTest 6 {-    builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $out $out/link";-    allowedReferences = [];-    inherit dep;-  };--  test7 = makeTest 7 {-    builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $out $out/link";-    allowedReferences = ["out"];-    inherit dep;-  };--  test8 = makeTest 8 {-    builder = builtins.toFile "builder.sh" "mkdir $out; ln -s ${test1} $out/link";-    inherit dep;-  };--  test9 = makeTest 9 {-    builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $dep $out/link";-    inherit dep;-    disallowedReferences = [dep];-  };--  test10 = makeTest 10 {-    builder = builtins.toFile "builder.sh" "mkdir $out; echo $test5; ln -s $dep $out/link";-    inherit dep test5;-    disallowedReferences = [test5];-  };--}
− data/nix/tests/check-refs.sh
@@ -1,40 +0,0 @@-source common.sh--RESULT=$TEST_ROOT/result--dep=$(nix-build -o $RESULT check-refs.nix -A dep)--# test1 references dep, not itself.-test1=$(nix-build -o $RESULT check-refs.nix -A test1)-(! nix-store -q --references $test1 | grep -q $test1)-nix-store -q --references $test1 | grep -q $dep--# test2 references src, not itself nor dep.-test2=$(nix-build -o $RESULT check-refs.nix -A test2)-(! nix-store -q --references $test2 | grep -q $test2)-(! nix-store -q --references $test2 | grep -q $dep)-nix-store -q --references $test2 | grep -q aux-ref--# test3 should fail (unallowed ref).-(! nix-build -o $RESULT check-refs.nix -A test3)--# test4 should succeed.-nix-build -o $RESULT check-refs.nix -A test4--# test5 should succeed.-nix-build -o $RESULT check-refs.nix -A test5--# test6 should fail (unallowed self-ref).-(! nix-build -o $RESULT check-refs.nix -A test6)--# test7 should succeed (allowed self-ref).-nix-build -o $RESULT check-refs.nix -A test7--# test8 should fail (toFile depending on derivation output).-(! nix-build -o $RESULT check-refs.nix -A test8)--# test9 should fail (disallowed reference).-(! nix-build -o $RESULT check-refs.nix -A test9)--# test10 should succeed (no disallowed references).-nix-build -o $RESULT check-refs.nix -A test10
− data/nix/tests/check-reqs.nix
@@ -1,57 +0,0 @@-with import ./config.nix;--rec {-  dep1 = mkDerivation {-    name = "check-reqs-dep1";-    builder = builtins.toFile "builder.sh" "mkdir $out; touch $out/file1";-  };--  dep2 = mkDerivation {-    name = "check-reqs-dep2";-    builder = builtins.toFile "builder.sh" "mkdir $out; touch $out/file2";-  };--  deps = mkDerivation {-    name = "check-reqs-deps";-    dep1 = dep1;-    dep2 = dep2;-    builder = builtins.toFile "builder.sh" ''-      mkdir $out-      ln -s $dep1/file1 $out/file1-      ln -s $dep2/file2 $out/file2-    '';-  };--  makeTest = nr: allowreqs: mkDerivation {-    name = "check-reqs-" + toString nr;-    inherit deps;-    builder = builtins.toFile "builder.sh" ''-      mkdir $out-      ln -s $deps $out/depdir1-    '';-    allowedRequisites = allowreqs;-  };--  # When specifying all the requisites, the build succeeds.-  test1 = makeTest 1 [ dep1 dep2 deps ];--  # But missing anything it fails.-  test2 = makeTest 2 [ dep2 deps ];-  test3 = makeTest 3 [ dep1 deps ];-  test4 = makeTest 4 [ deps ];-  test5 = makeTest 5 [];--  test6 = mkDerivation {-    name = "check-reqs";-    inherit deps;-    builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $deps $out/depdir1";-    disallowedRequisites = [dep1];-  };--  test7 = mkDerivation {-    name = "check-reqs";-    inherit deps;-    builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $deps $out/depdir1";-    disallowedRequisites = [test1];-  };-}
− data/nix/tests/check-reqs.sh
@@ -1,14 +0,0 @@-source common.sh--RESULT=$TEST_ROOT/result--nix-build -o $RESULT check-reqs.nix -A test1--(! nix-build -o $RESULT check-reqs.nix -A test2)-(! nix-build -o $RESULT check-reqs.nix -A test3)-(! nix-build -o $RESULT check-reqs.nix -A test4) 2>&1 | grep -q 'check-reqs-dep1'-(! nix-build -o $RESULT check-reqs.nix -A test4) 2>&1 | grep -q 'check-reqs-dep2'-(! nix-build -o $RESULT check-reqs.nix -A test5)-(! nix-build -o $RESULT check-reqs.nix -A test6)--nix-build -o $RESULT check-reqs.nix -A test7
− data/nix/tests/check.nix
@@ -1,17 +0,0 @@-with import ./config.nix;--{-  nondeterministic = mkDerivation {-    name = "nondeterministic";-    buildCommand =-      ''-        mkdir $out-        date +%s.%N > $out/date-      '';-  };--  fetchurl = import <nix/fetchurl.nix> {-    url = "file://" + toString ./lang/eval-okay-xml.exp.xml;-    sha256 = "0kg4sla7ihm8ijr8cb3117fhl99zrc2bwy1jrngsfmkh8bav4m0v";-  };-}
− data/nix/tests/check.sh
@@ -1,32 +0,0 @@-source common.sh--clearStore--nix-build dependencies.nix --no-out-link-nix-build dependencies.nix --no-out-link --check--nix-build check.nix -A nondeterministic --no-out-link-(! nix-build check.nix -A nondeterministic --no-out-link --check 2> $TEST_ROOT/log)-grep 'may not be deterministic' $TEST_ROOT/log--clearStore--nix-build dependencies.nix --no-out-link --repeat 3--(! nix-build check.nix -A nondeterministic --no-out-link --repeat 1 2> $TEST_ROOT/log)-grep 'differs from previous round' $TEST_ROOT/log--path=$(nix-build check.nix -A fetchurl --no-out-link --hashed-mirrors '')--chmod +w $path-echo foo > $path-chmod -w $path--nix-build check.nix -A fetchurl --no-out-link --check --hashed-mirrors ''--# Note: "check" doesn't repair anything, it just compares to the hash stored in the database.-[[ $(cat $path) = foo ]]--nix-build check.nix -A fetchurl --no-out-link --repair --hashed-mirrors ''--[[ $(cat $path) != foo ]]
− data/nix/tests/common.sh.in
@@ -1,123 +0,0 @@-set -e--export TEST_ROOT=$(realpath ${TMPDIR:-/tmp}/nix-test)-export NIX_STORE_DIR-if ! NIX_STORE_DIR=$(readlink -f $TEST_ROOT/store 2> /dev/null); then-    # Maybe the build directory is symlinked.-    export NIX_IGNORE_SYMLINK_STORE=1-    NIX_STORE_DIR=$TEST_ROOT/store-fi-export NIX_LOCALSTATE_DIR=$TEST_ROOT/var-export NIX_LOG_DIR=$TEST_ROOT/var/log/nix-export NIX_STATE_DIR=$TEST_ROOT/var/nix-export NIX_CONF_DIR=$TEST_ROOT/etc-export _NIX_TEST_SHARED=$TEST_ROOT/shared-if [[ -n $NIX_STORE ]]; then-    export _NIX_TEST_NO_SANDBOX=1-fi-export _NIX_IN_TEST=$TEST_ROOT/shared-export NIX_REMOTE=$NIX_REMOTE_-unset NIX_PATH-export TEST_HOME=$TEST_ROOT/test-home-export HOME=$TEST_HOME-unset XDG_CACHE_HOME-mkdir -p $TEST_HOME--export PATH=@bindir@:$PATH-coreutils=@coreutils@--export dot=@dot@-export xmllint="@xmllint@"-export SHELL="@bash@"-export PAGER=cat-export HAVE_SODIUM="@HAVE_SODIUM@"-export HAVE_BROTLI="@HAVE_BROTLI@"--export version=@PACKAGE_VERSION@-export system=@system@--cacheDir=$TEST_ROOT/binary-cache--readLink() {-    ls -l "$1" | sed 's/.*->\ //'-}--clearProfiles() {-    profiles="$NIX_STATE_DIR"/profiles-    rm -rf $profiles-}--clearStore() {-    echo "clearing store..."-    chmod -R +w "$NIX_STORE_DIR"-    rm -rf "$NIX_STORE_DIR"-    mkdir "$NIX_STORE_DIR"-    rm -rf "$NIX_STATE_DIR"-    mkdir "$NIX_STATE_DIR"-    nix-store --init-    clearProfiles-}--clearCache() {-    rm -rf "$cacheDir"-}--clearCacheCache() {-    rm -f $TEST_HOME/.cache/nix/binary-cache*-}--startDaemon() {-    # Start the daemon, wait for the socket to appear.  !!!-    # ‘nix-daemon’ should have an option to fork into the background.-    rm -f $NIX_STATE_DIR/daemon-socket/socket-    nix-daemon &-    for ((i = 0; i < 30; i++)); do-        if [ -e $NIX_STATE_DIR/daemon-socket/socket ]; then break; fi-        sleep 1-    done-    pidDaemon=$!-    trap "kill -9 $pidDaemon" EXIT-    export NIX_REMOTE=daemon-}--killDaemon() {-    kill -9 $pidDaemon-    wait $pidDaemon || true-    trap "" EXIT-}--canUseSandbox() {-    if [[ $(uname) != Linux ]]; then return 1; fi--    if [ ! -L /proc/self/ns/user ]; then-        echo "Kernel doesn't support user namespaces, skipping this test..."-        return 1-    fi--    if [ -e /proc/sys/kernel/unprivileged_userns_clone ]; then-        if [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" != 1 ]; then-            echo "Unprivileged user namespaces disabled by sysctl, skipping this test..."-            return 1-        fi-    fi--    return 0-}--fail() {-    echo "$1"-    exit 1-}--expect() {-    local expected res-    expected="$1"-    shift-    set +e-    "$@"-    res="$?"-    set -e-    [[ $res -eq $expected ]]-}--set -x
− data/nix/tests/config.nix
@@ -1,20 +0,0 @@-with import <nix/config.nix>;--rec {-  inherit shell;--  path = coreutils;--  system = builtins.currentSystem;--  shared = builtins.getEnv "_NIX_TEST_SHARED";--  mkDerivation = args:-    derivation ({-      inherit system;-      builder = shell;-      args = ["-e" args.builder or (builtins.toFile "builder.sh" "if [ -e .attrs.sh ]; then source .attrs.sh; fi; eval \"$buildCommand\"")];-      PATH = path;-    } // removeAttrs args ["builder" "meta"])-    // { meta = args.meta or {}; };-}
− data/nix/tests/dependencies.builder0.sh
@@ -1,16 +0,0 @@-[ "${input1: -2}" = /. ]-[ "${input2: -2}" = /. ]--mkdir $out-echo $(cat $input1/foo)$(cat $input2/bar) > $out/foobar--ln -s $input2 $out/input-2--# Self-reference.-ln -s $out $out/self--# Executable.-echo program > $out/program-chmod +x $out/program--echo FOO
− data/nix/tests/dependencies.builder1.sh
@@ -1,2 +0,0 @@-mkdir $out-echo FOO > $out/foo
− data/nix/tests/dependencies.builder2.sh
@@ -1,2 +0,0 @@-mkdir $out-echo BAR > $out/bar
− data/nix/tests/dependencies.nix
@@ -1,23 +0,0 @@-with import ./config.nix;--let {--  input1 = mkDerivation {-    name = "dependencies-input-1";-    builder = ./dependencies.builder1.sh;-  };--  input2 = mkDerivation {-    name = "dependencies-input-2";-    builder = "${./dependencies.builder2.sh}";-  };--  body = mkDerivation {-    name = "dependencies";-    builder = ./dependencies.builder0.sh + "/FOOBAR/../.";-    input1 = input1 + "/.";-    input2 = "${input2}/.";-    meta.description = "Random test package";-  };--}
− data/nix/tests/dependencies.sh
@@ -1,52 +0,0 @@-source common.sh--clearStore--drvPath=$(nix-instantiate dependencies.nix)--echo "derivation is $drvPath"--nix-store -q --tree "$drvPath" | grep '   +---.*builder1.sh'--# Test Graphviz graph generation.-nix-store -q --graph "$drvPath" > $TEST_ROOT/graph-if test -n "$dot"; then-    # Does it parse?-    $dot < $TEST_ROOT/graph-fi--outPath=$(nix-store -rvv "$drvPath") || fail "build failed"--# Test Graphviz graph generation.-nix-store -q --graph "$outPath" > $TEST_ROOT/graph-if test -n "$dot"; then-    # Does it parse?-    $dot < $TEST_ROOT/graph-fi    --nix-store -q --tree "$outPath" | grep '+---.*dependencies-input-2'--echo "output path is $outPath"--text=$(cat "$outPath"/foobar)-if test "$text" != "FOOBAR"; then exit 1; fi--deps=$(nix-store -quR "$drvPath")--echo "output closure contains $deps"--# The output path should be in the closure.-echo "$deps" | grep -q "$outPath"--# Input-1 is not retained.-if echo "$deps" | grep -q "dependencies-input-1"; then exit 1; fi--# Input-2 is retained.-input2OutPath=$(echo "$deps" | grep "dependencies-input-2")--# The referrers closure of input-2 should include outPath.-nix-store -q --referrers-closure "$input2OutPath" | grep "$outPath"--# Check that the derivers are set properly.-test $(nix-store -q --deriver "$outPath") = "$drvPath"-nix-store -q --deriver "$input2OutPath" | grep -q -- "-input-2.drv" 
− data/nix/tests/dump-db.sh
@@ -1,20 +0,0 @@-source common.sh--clearStore--path=$(nix-build dependencies.nix -o $TEST_ROOT/result)--deps="$(nix-store -qR $TEST_ROOT/result)"--nix-store --dump-db > $TEST_ROOT/dump--rm -rf $NIX_STATE_DIR/db--nix-store --load-db < $TEST_ROOT/dump--deps2="$(nix-store -qR $TEST_ROOT/result)"--[ "$deps" = "$deps2" ];--nix-store --dump-db > $TEST_ROOT/dump2-cmp $TEST_ROOT/dump $TEST_ROOT/dump2
− data/nix/tests/export-graph.nix
@@ -1,29 +0,0 @@-with import ./config.nix;--rec {--  printRefs =-    ''-      echo $exportReferencesGraph-      while read path; do-          read drv-          read nrRefs-          echo "$path has $nrRefs references"-          echo "$path" >> $out-          for ((n = 0; n < $nrRefs; n++)); do read ref; echo "ref $ref"; test -e "$ref"; done-      done < refs-    '';--  foo."bar.runtimeGraph" = mkDerivation {-    name = "dependencies";-    builder = builtins.toFile "build-graph-builder" "${printRefs}";-    exportReferencesGraph = ["refs" (import ./dependencies.nix)];-  };--  foo."bar.buildGraph" = mkDerivation {-    name = "dependencies";-    builder = builtins.toFile "build-graph-builder" "${printRefs}";-    exportReferencesGraph = ["refs" (import ./dependencies.nix).drvPath];-  };--}
− data/nix/tests/export-graph.sh
@@ -1,30 +0,0 @@-source common.sh--clearStore-clearProfiles--checkRef() {-    nix-store -q --references $TEST_ROOT/result | grep -q "$1" || fail "missing reference $1"-}--# Test the export of the runtime dependency graph.--outPath=$(nix-build ./export-graph.nix -A 'foo."bar.runtimeGraph"' -o $TEST_ROOT/result)--test $(nix-store -q --references $TEST_ROOT/result | wc -l) = 2 || fail "bad nr of references"--checkRef input-2-for i in $(cat $outPath); do checkRef $i; done--# Test the export of the build-time dependency graph.--nix-store --gc # should force rebuild of input-1--outPath=$(nix-build ./export-graph.nix -A 'foo."bar.buildGraph"' -o $TEST_ROOT/result)--checkRef input-1-checkRef input-1.drv-checkRef input-2-checkRef input-2.drv--for i in $(cat $outPath); do checkRef $i; done
− data/nix/tests/export.sh
@@ -1,36 +0,0 @@-source common.sh--clearStore--outPath=$(nix-build dependencies.nix --no-out-link)--nix-store --export $outPath > $TEST_ROOT/exp--nix-store --export $(nix-store -qR $outPath) > $TEST_ROOT/exp_all--if nix-store --export $outPath >/dev/full ; then-    echo "exporting to a bad file descriptor should fail"-    exit 1-fi---clearStore--if nix-store --import < $TEST_ROOT/exp; then-    echo "importing a non-closure should fail"-    exit 1-fi---clearStore--nix-store --import < $TEST_ROOT/exp_all--nix-store --export $(nix-store -qR $outPath) > $TEST_ROOT/exp_all2---clearStore--# Regression test: the derivers in exp_all2 are empty, which shouldn't-# cause a failure.-nix-store --import < $TEST_ROOT/exp_all2
− data/nix/tests/fetchGit.sh
@@ -1,141 +0,0 @@-source common.sh--if [[ -z $(type -p git) ]]; then-    echo "Git not installed; skipping Git tests"-    exit 99-fi--clearStore--repo=$TEST_ROOT/git--rm -rf $repo ${repo}-tmp $TEST_HOME/.cache/nix/git--git init $repo-git -C $repo config user.email "foobar@example.com"-git -C $repo config user.name "Foobar"--echo utrecht > $repo/hello-touch $repo/.gitignore-git -C $repo add hello .gitignore-git -C $repo commit -m 'Bla1'-rev1=$(git -C $repo rev-parse HEAD)--echo world > $repo/hello-git -C $repo commit -m 'Bla2' -a-rev2=$(git -C $repo rev-parse HEAD)--# Fetch the default branch.-path=$(nix eval --raw "(builtins.fetchGit file://$repo).outPath")-[[ $(cat $path/hello) = world ]]--# In pure eval mode, fetchGit without a revision should fail.-[[ $(nix eval --raw "(builtins.readFile (fetchGit file://$repo + \"/hello\"))") = world ]]-(! nix eval --pure-eval --raw "(builtins.readFile (fetchGit file://$repo + \"/hello\"))")--# Fetch using an explicit revision hash.-path2=$(nix eval --raw "(builtins.fetchGit { url = file://$repo; rev = \"$rev2\"; }).outPath")-[[ $path = $path2 ]]--# In pure eval mode, fetchGit with a revision should succeed.-[[ $(nix eval --pure-eval --raw "(builtins.readFile (fetchGit { url = file://$repo; rev = \"$rev2\"; } + \"/hello\"))") = world ]]--# Fetch again. This should be cached.-mv $repo ${repo}-tmp-path2=$(nix eval --raw "(builtins.fetchGit file://$repo).outPath")-[[ $path = $path2 ]]--[[ $(nix eval "(builtins.fetchGit file://$repo).revCount") = 2 ]]-[[ $(nix eval --raw "(builtins.fetchGit file://$repo).rev") = $rev2 ]]--# But with TTL 0, it should fail.-(! nix eval --tarball-ttl 0 "(builtins.fetchGit file://$repo)" -vvvvv)--# Fetching with a explicit hash should succeed.-path2=$(nix eval --tarball-ttl 0 --raw "(builtins.fetchGit { url = file://$repo; rev = \"$rev2\"; }).outPath")-[[ $path = $path2 ]]--path2=$(nix eval --tarball-ttl 0 --raw "(builtins.fetchGit { url = file://$repo; rev = \"$rev1\"; }).outPath")-[[ $(cat $path2/hello) = utrecht ]]--mv ${repo}-tmp $repo--# Using a clean working tree should produce the same result.-path2=$(nix eval --raw "(builtins.fetchGit $repo).outPath")-[[ $path = $path2 ]]--# Using an unclean tree should yield the tracked but uncommitted changes.-mkdir $repo/dir1 $repo/dir2-echo foo > $repo/dir1/foo-echo bar > $repo/bar-echo bar > $repo/dir2/bar-git -C $repo add dir1/foo-git -C $repo rm hello--path2=$(nix eval --raw "(builtins.fetchGit $repo).outPath")-[ ! -e $path2/hello ]-[ ! -e $path2/bar ]-[ ! -e $path2/dir2/bar ]-[ ! -e $path2/.git ]-[[ $(cat $path2/dir1/foo) = foo ]]--[[ $(nix eval --raw "(builtins.fetchGit $repo).rev") = 0000000000000000000000000000000000000000 ]]--# ... unless we're using an explicit ref or rev.-path3=$(nix eval --raw "(builtins.fetchGit { url = $repo; ref = \"master\"; }).outPath")-[[ $path = $path3 ]]--path3=$(nix eval --raw "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; }).outPath")-[[ $path = $path3 ]]--# Committing should not affect the store path.-git -C $repo commit -m 'Bla3' -a--path4=$(nix eval --tarball-ttl 0 --raw "(builtins.fetchGit file://$repo).outPath")-[[ $path2 = $path4 ]]--# tarball-ttl should be ignored if we specify a rev-echo delft > $repo/hello-git -C $repo add hello-git -C $repo commit -m 'Bla4'-rev3=$(git -C $repo rev-parse HEAD)-nix eval --tarball-ttl 3600 "(builtins.fetchGit { url = $repo; rev = \"$rev3\"; })" >/dev/null--# Update 'path' to reflect latest master-path=$(nix eval --raw "(builtins.fetchGit file://$repo).outPath")--# Check behavior when non-master branch is used-git -C $repo checkout $rev2 -b dev-echo dev > $repo/hello--# File URI uses 'master' unless specified otherwise-path2=$(nix eval --raw "(builtins.fetchGit file://$repo).outPath")-[[ $path = $path2 ]]--# Using local path with branch other than 'master' should work when clean or dirty-path3=$(nix eval --raw "(builtins.fetchGit $repo).outPath")-# (check dirty-tree handling was used)-[[ $(nix eval --raw "(builtins.fetchGit $repo).rev") = 0000000000000000000000000000000000000000 ]]--# Committing shouldn't change store path, or switch to using 'master'-git -C $repo commit -m 'Bla5' -a-path4=$(nix eval --raw "(builtins.fetchGit $repo).outPath")-[[ $(cat $path4/hello) = dev ]]-[[ $path3 = $path4 ]]--# Confirm same as 'dev' branch-path5=$(nix eval --raw "(builtins.fetchGit { url = $repo; ref = \"dev\"; }).outPath")-[[ $path3 = $path5 ]]---# Nuke the cache-rm -rf $TEST_HOME/.cache/nix/git--# Try again, but without 'git' on PATH-NIX=$(command -v nix)-# This should fail-(! PATH= $NIX eval --raw "(builtins.fetchGit { url = $repo; ref = \"dev\"; }).outPath" )--# Try again, with 'git' available.  This should work.-path5=$(nix eval --raw "(builtins.fetchGit { url = $repo; ref = \"dev\"; }).outPath")-[[ $path3 = $path5 ]]
− data/nix/tests/fetchMercurial.sh
@@ -1,93 +0,0 @@-source common.sh--if [[ -z $(type -p hg) ]]; then-    echo "Mercurial not installed; skipping Mercurial tests"-    exit 99-fi--clearStore--repo=$TEST_ROOT/hg--rm -rf $repo ${repo}-tmp $TEST_HOME/.cache/nix/hg--hg init $repo-echo '[ui]' >> $repo/.hg/hgrc-echo 'username = Foobar <foobar@example.org>' >> $repo/.hg/hgrc--echo utrecht > $repo/hello-touch $repo/.hgignore-hg add --cwd $repo hello .hgignore-hg commit --cwd $repo -m 'Bla1'-rev1=$(hg log --cwd $repo -r tip --template '{node}')--echo world > $repo/hello-hg commit --cwd $repo -m 'Bla2'-rev2=$(hg log --cwd $repo -r tip --template '{node}')--# Fetch the default branch.-path=$(nix eval --raw "(builtins.fetchMercurial file://$repo).outPath")-[[ $(cat $path/hello) = world ]]--# In pure eval mode, fetchGit without a revision should fail.-[[ $(nix eval --raw "(builtins.readFile (fetchMercurial file://$repo + \"/hello\"))") = world ]]-(! nix eval --pure-eval --raw "(builtins.readFile (fetchMercurial file://$repo + \"/hello\"))")--# Fetch using an explicit revision hash.-path2=$(nix eval --raw "(builtins.fetchMercurial { url = file://$repo; rev = \"$rev2\"; }).outPath")-[[ $path = $path2 ]]--# In pure eval mode, fetchGit with a revision should succeed.-[[ $(nix eval --pure-eval --raw "(builtins.readFile (fetchMercurial { url = file://$repo; rev = \"$rev2\"; } + \"/hello\"))") = world ]]--# Fetch again. This should be cached.-mv $repo ${repo}-tmp-path2=$(nix eval --raw "(builtins.fetchMercurial file://$repo).outPath")-[[ $path = $path2 ]]--[[ $(nix eval --raw "(builtins.fetchMercurial file://$repo).branch") = default ]]-[[ $(nix eval "(builtins.fetchMercurial file://$repo).revCount") = 1 ]]-[[ $(nix eval --raw "(builtins.fetchMercurial file://$repo).rev") = $rev2 ]]--# But with TTL 0, it should fail.-(! nix eval --tarball-ttl 0 "(builtins.fetchMercurial file://$repo)")--# Fetching with a explicit hash should succeed.-path2=$(nix eval --tarball-ttl 0 --raw "(builtins.fetchMercurial { url = file://$repo; rev = \"$rev2\"; }).outPath")-[[ $path = $path2 ]]--path2=$(nix eval --tarball-ttl 0 --raw "(builtins.fetchMercurial { url = file://$repo; rev = \"$rev1\"; }).outPath")-[[ $(cat $path2/hello) = utrecht ]]--mv ${repo}-tmp $repo--# Using a clean working tree should produce the same result.-path2=$(nix eval --raw "(builtins.fetchMercurial $repo).outPath")-[[ $path = $path2 ]]--# Using an unclean tree should yield the tracked but uncommitted changes.-mkdir $repo/dir1 $repo/dir2-echo foo > $repo/dir1/foo-echo bar > $repo/bar-echo bar > $repo/dir2/bar-hg add --cwd $repo dir1/foo-hg rm --cwd $repo hello--path2=$(nix eval --raw "(builtins.fetchMercurial $repo).outPath")-[ ! -e $path2/hello ]-[ ! -e $path2/bar ]-[ ! -e $path2/dir2/bar ]-[ ! -e $path2/.hg ]-[[ $(cat $path2/dir1/foo) = foo ]]--[[ $(nix eval --raw "(builtins.fetchMercurial $repo).rev") = 0000000000000000000000000000000000000000 ]]--# ... unless we're using an explicit rev.-path3=$(nix eval --raw "(builtins.fetchMercurial { url = $repo; rev = \"default\"; }).outPath")-[[ $path = $path3 ]]--# Committing should not affect the store path.-hg commit --cwd $repo -m 'Bla3'--path4=$(nix eval --tarball-ttl 0 --raw "(builtins.fetchMercurial file://$repo).outPath")-[[ $path2 = $path4 ]]
− data/nix/tests/fetchurl.sh
@@ -1,63 +0,0 @@-source common.sh--clearStore--# Test fetching a flat file.-hash=$(nix-hash --flat --type sha256 ./fetchurl.sh)--outPath=$(nix-build '<nix/fetchurl.nix>' --argstr url file://$(pwd)/fetchurl.sh --argstr sha256 $hash --no-out-link --hashed-mirrors '')--cmp $outPath fetchurl.sh--# Now using a base-64 hash.-clearStore--hash=$(nix hash-file --type sha512 --base64 ./fetchurl.sh)--outPath=$(nix-build '<nix/fetchurl.nix>' --argstr url file://$(pwd)/fetchurl.sh --argstr sha512 $hash --no-out-link --hashed-mirrors '')--cmp $outPath fetchurl.sh--# Test the hashed mirror feature.-clearStore--hash=$(nix hash-file --type sha512 --base64 ./fetchurl.sh)-hash32=$(nix hash-file --type sha512 --base16 ./fetchurl.sh)--mirror=$TMPDIR/hashed-mirror-rm -rf $mirror-mkdir -p $mirror/sha512-ln -s $(pwd)/fetchurl.sh $mirror/sha512/$hash32--outPath=$(nix-build '<nix/fetchurl.nix>' --argstr url file:///no-such-dir/fetchurl.sh --argstr sha512 $hash --no-out-link --hashed-mirrors "file://$mirror")--# Test unpacking a NAR.-rm -rf $TEST_ROOT/archive-mkdir -p $TEST_ROOT/archive-cp ./fetchurl.sh $TEST_ROOT/archive-chmod +x $TEST_ROOT/archive/fetchurl.sh-ln -s foo $TEST_ROOT/archive/symlink-nar=$TEST_ROOT/archive.nar-nix-store --dump $TEST_ROOT/archive > $nar--hash=$(nix-hash --flat --type sha256 $nar)--outPath=$(nix-build '<nix/fetchurl.nix>' --argstr url file://$nar --argstr sha256 $hash \-          --arg unpack true --argstr name xyzzy --no-out-link)--echo $outPath | grep -q 'xyzzy'--test -x $outPath/fetchurl.sh-test -L $outPath/symlink--nix-store --delete $outPath--# Test unpacking a compressed NAR.-narxz=$TEST_ROOT/archive.nar.xz-rm -f $narxz-xz --keep $nar-outPath=$(nix-build '<nix/fetchurl.nix>' --argstr url file://$narxz --argstr sha256 $hash \-          --arg unpack true --argstr name xyzzy --no-out-link)--test -x $outPath/fetchurl.sh-test -L $outPath/symlink
− data/nix/tests/filter-source.nix
@@ -1,12 +0,0 @@-with import ./config.nix;--mkDerivation {-  name = "filter";-  builder = builtins.toFile "builder" "ln -s $input $out";-  input =-    let filter = path: type:-      type != "symlink"-      && baseNameOf path != "foo"-      && !((import ./lang/lib.nix).hasSuffix ".bak" (baseNameOf path));-    in builtins.filterSource filter ((builtins.getEnv "TEST_ROOT") + "/filterin");-}
− data/nix/tests/filter-source.sh
@@ -1,19 +0,0 @@-source common.sh--rm -rf $TEST_ROOT/filterin-mkdir $TEST_ROOT/filterin-mkdir $TEST_ROOT/filterin/foo-touch $TEST_ROOT/filterin/foo/bar-touch $TEST_ROOT/filterin/xyzzy-touch $TEST_ROOT/filterin/b-touch $TEST_ROOT/filterin/bak-touch $TEST_ROOT/filterin/bla.c.bak-ln -s xyzzy $TEST_ROOT/filterin/link--nix-build ./filter-source.nix -o $TEST_ROOT/filterout--test ! -e $TEST_ROOT/filterout/foo/bar-test -e $TEST_ROOT/filterout/xyzzy-test -e $TEST_ROOT/filterout/bak-test ! -e $TEST_ROOT/filterout/bla.c.bak-test ! -L $TEST_ROOT/filterout/link
− data/nix/tests/fixed.builder1.sh
@@ -1,3 +0,0 @@-if test "$IMPURE_VAR1" != "foo"; then exit 1; fi-if test "$IMPURE_VAR2" != "bar"; then exit 1; fi-echo "Hello World!" > $out
− data/nix/tests/fixed.builder2.sh
@@ -1,6 +0,0 @@-echo dummy: $dummy-if test -n "$dummy"; then sleep 2; fi-mkdir $out-mkdir $out/bla-echo "Hello World!" > $out/foo-ln -s foo $out/bar
− data/nix/tests/fixed.nix
@@ -1,50 +0,0 @@-with import ./config.nix;--rec {--  f2 = dummy: builder: mode: algo: hash: mkDerivation {-    name = "fixed";-    inherit builder;-    outputHashMode = mode;-    outputHashAlgo = algo;-    outputHash = hash;-    inherit dummy;-    impureEnvVars = ["IMPURE_VAR1" "IMPURE_VAR2"];-  };--  f = f2 "";--  good = [-    (f ./fixed.builder1.sh "flat" "md5" "8ddd8be4b179a529afa5f2ffae4b9858")-    (f ./fixed.builder1.sh "flat" "sha1" "a0b65939670bc2c010f4d5d6a0b3e4e4590fb92b")-    (f ./fixed.builder2.sh "recursive" "md5" "3670af73070fa14077ad74e0f5ea4e42")-    (f ./fixed.builder2.sh "recursive" "sha1" "vw46m23bizj4n8afrc0fj19wrp7mj3c0")-  ];--  good2 = [-    # Yes, this looks fscked up: builder2 doesn't have that result.-    # But Nix sees that an output with the desired hash already-    # exists, and will refrain from building it.-    (f ./fixed.builder2.sh "flat" "md5" "8ddd8be4b179a529afa5f2ffae4b9858")-  ];--  sameAsAdd =-    f ./fixed.builder2.sh "recursive" "sha256" "1ixr6yd3297ciyp9im522dfxpqbkhcw0pylkb2aab915278fqaik";--  bad = [-    (f ./fixed.builder1.sh "flat" "md5" "0ddd8be4b179a529afa5f2ffae4b9858")-  ];--  reallyBad = [-    # Hash too short, and not base-32 either.-    (f ./fixed.builder1.sh "flat" "md5" "ddd8be4b179a529afa5f2ffae4b9858")-  ];--  # Test for building two derivations in parallel that produce the-  # same output path because they're fixed-output derivations.-  parallelSame = [-    (f2 "foo" ./fixed.builder2.sh "recursive" "md5" "3670af73070fa14077ad74e0f5ea4e42")-    (f2 "bar" ./fixed.builder2.sh "recursive" "md5" "3670af73070fa14077ad74e0f5ea4e42")-  ];--}
− data/nix/tests/fixed.sh
@@ -1,56 +0,0 @@-source common.sh--clearStore--export IMPURE_VAR1=foo-export IMPURE_VAR2=bar--path=$(nix-store -q $(nix-instantiate fixed.nix -A good.0))--echo 'testing bad...'-nix-build fixed.nix -A bad --no-out-link && fail "should fail"--# Building with the bad hash should produce the "good" output path as-# a side-effect.-[[ -e $path ]]-nix path-info --json $path | grep fixed:md5:2qk15sxzzjlnpjk9brn7j8ppcd--echo 'testing good...'-nix-build fixed.nix -A good --no-out-link--echo 'testing good2...'-nix-build fixed.nix -A good2 --no-out-link--echo 'testing reallyBad...'-nix-instantiate fixed.nix -A reallyBad && fail "should fail"--# While we're at it, check attribute selection a bit more.-echo 'testing attribute selection...'-test $(nix-instantiate fixed.nix -A good.1 | wc -l) = 1--# Test parallel builds of derivations that produce the same output.-# Only one should run at the same time.-echo 'testing parallelSame...'-clearStore-nix-build fixed.nix -A parallelSame --no-out-link -j2--# Fixed-output derivations with a recursive SHA-256 hash should-# produce the same path as "nix-store --add".-echo 'testing sameAsAdd...'-out=$(nix-build fixed.nix -A sameAsAdd --no-out-link)--# This is what fixed.builder2 produces...-rm -rf $TEST_ROOT/fixed-mkdir $TEST_ROOT/fixed-mkdir $TEST_ROOT/fixed/bla-echo "Hello World!" > $TEST_ROOT/fixed/foo-ln -s foo $TEST_ROOT/fixed/bar--out2=$(nix-store --add $TEST_ROOT/fixed)-[ "$out" = "$out2" ]--out3=$(nix-store --add-fixed --recursive sha256 $TEST_ROOT/fixed)-[ "$out" = "$out3" ]--out4=$(nix-store --print-fixed-path --recursive sha256 "1ixr6yd3297ciyp9im522dfxpqbkhcw0pylkb2aab915278fqaik" fixed)-[ "$out" = "$out4" ]
− data/nix/tests/gc-concurrent.builder.sh
@@ -1,13 +0,0 @@-mkdir $out-echo $(cat $input1/foo)$(cat $input2/bar) > $out/foobar--sleep 10--# $out should not have been GC'ed while we were sleeping, but just in-# case...-mkdir -p $out--# Check that the GC hasn't deleted the lock on our output.-test -e "$out.lock"--ln -s $input2 $out/input-2
− data/nix/tests/gc-concurrent.nix
@@ -1,27 +0,0 @@-with import ./config.nix;--rec {--  input1 = mkDerivation {-    name = "dependencies-input-1";-    builder = ./dependencies.builder1.sh;-  };--  input2 = mkDerivation {-    name = "dependencies-input-2";-    builder = ./dependencies.builder2.sh;-  };--  test1 = mkDerivation {-    name = "gc-concurrent";-    builder = ./gc-concurrent.builder.sh;-    inherit input1 input2;-  };--  test2 = mkDerivation {-    name = "gc-concurrent2";-    builder = ./gc-concurrent2.builder.sh;-    inherit input1 input2;-  };-  -}
− data/nix/tests/gc-concurrent.sh
@@ -1,58 +0,0 @@-source common.sh--clearStore--drvPath1=$(nix-instantiate gc-concurrent.nix -A test1)-outPath1=$(nix-store -q $drvPath1)--drvPath2=$(nix-instantiate gc-concurrent.nix -A test2)-outPath2=$(nix-store -q $drvPath2)--drvPath3=$(nix-instantiate simple.nix)-outPath3=$(nix-store -r $drvPath3)--(! test -e $outPath3.lock)-touch $outPath3.lock--rm -f "$NIX_STATE_DIR"/gcroots/foo*-ln -s $drvPath2 "$NIX_STATE_DIR"/gcroots/foo-ln -s $outPath3 "$NIX_STATE_DIR"/gcroots/foo2--# Start build #1 in the background.  It starts immediately.-nix-store -rvv "$drvPath1" &-pid1=$!--# Start build #2 in the background after 10 seconds.-(sleep 10 && nix-store -rvv "$drvPath2") &-pid2=$!--# Run the garbage collector while the build is running.-sleep 6-nix-collect-garbage--# Wait for build #1/#2 to finish.-echo waiting for pid $pid1 to finish...-wait $pid1-echo waiting for pid $pid2 to finish...-wait $pid2--# Check that the root of build #1 and its dependencies haven't been-# deleted.  The should not be deleted by the GC because they were-# being built during the GC.-cat $outPath1/foobar-cat $outPath1/input-2/bar--# Check that build #2 has succeeded.  It should succeed because the-# derivation is a GC root.-cat $outPath2/foobar--rm -f "$NIX_STATE_DIR"/gcroots/foo*--# The collector should have deleted lock files for paths that have-# been built previously.-(! test -e $outPath3.lock)--# If we run the collector now, it should delete outPath1/2.-nix-collect-garbage-(! test -e $outPath1)-(! test -e $outPath2)
− data/nix/tests/gc-concurrent2.builder.sh
@@ -1,7 +0,0 @@-mkdir $out-echo $(cat $input1/foo)$(cat $input2/bar)xyzzy > $out/foobar--# Check that the GC hasn't deleted the lock on our output.-test -e "$out.lock"--sleep 6
− data/nix/tests/gc-runtime.nix
@@ -1,17 +0,0 @@-with import ./config.nix;--mkDerivation {-  name = "gc-runtime";-  builder =-    # Test inline source file definitions.-    builtins.toFile "builder.sh" ''-      mkdir $out--      cat > $out/program <<EOF-      #! ${shell}-      sleep 10000-      EOF--      chmod +x $out/program-    '';-}
− data/nix/tests/gc-runtime.sh
@@ -1,38 +0,0 @@-source common.sh--case $system in-    *linux*)-        ;;-    *)-        exit 0;-esac--set -m # enable job control, needed for kill--profiles="$NIX_STATE_DIR"/profiles-rm -rf $profiles--nix-env -p $profiles/test -f ./gc-runtime.nix -i gc-runtime--outPath=$(nix-env -p $profiles/test -q --no-name --out-path gc-runtime)-echo $outPath--echo "backgrounding program..."-$profiles/test/program &-sleep 2 # hack - wait for the program to get started-child=$!-echo PID=$child--nix-env -p $profiles/test -e gc-runtime-nix-env -p $profiles/test --delete-generations old--nix-store --gc--kill -- -$child--if ! test -e $outPath; then-    echo "running program was garbage collected!"-    exit 1-fi--exit 0
− data/nix/tests/gc.sh
@@ -1,40 +0,0 @@-source common.sh--drvPath=$(nix-instantiate dependencies.nix)-outPath=$(nix-store -rvv "$drvPath")--# Set a GC root.-rm -f "$NIX_STATE_DIR"/gcroots/foo-ln -sf $outPath "$NIX_STATE_DIR"/gcroots/foo--[ "$(nix-store -q --roots $outPath)" = "$NIX_STATE_DIR"/gcroots/foo ]--nix-store --gc --print-roots | grep $outPath-nix-store --gc --print-live | grep $outPath-nix-store --gc --print-dead | grep $drvPath-if nix-store --gc --print-dead | grep $outPath; then false; fi--nix-store --gc --print-dead--inUse=$(readLink $outPath/input-2)-if nix-store --delete $inUse; then false; fi-test -e $inUse--if nix-store --delete $outPath; then false; fi-test -e $outPath--nix-collect-garbage--# Check that the root and its dependencies haven't been deleted.-cat $outPath/foobar-cat $outPath/input-2/bar--# Check that the derivation has been GC'd.-if test -e $drvPath; then false; fi--rm "$NIX_STATE_DIR"/gcroots/foo--nix-collect-garbage--# Check that the output has been GC'd.-if test -e $outPath/foobar; then false; fi
− data/nix/tests/hash-check.nix
@@ -1,29 +0,0 @@-let {--  input1 = derivation {-    name = "dependencies-input-1";-    system = "i086-msdos";-    builder = "/bar/sh";-    args = ["-e" "-x" ./dummy];-  };--  input2 = derivation {-    name = "dependencies-input-2";-    system = "i086-msdos";-    builder = "/bar/sh";-    args = ["-e" "-x" ./dummy];-    outputHashMode = "recursive";-    outputHashAlgo = "md5";-    outputHash = "ffffffffffffffffffffffffffffffff";-  };--  body = derivation {-    name = "dependencies";-    system = "i086-msdos";-    builder = "/bar/sh";-    args = ["-e" "-x" (./dummy  + "/FOOBAR/../.")];-    input1 = input1 + "/.";-    inherit input2;-  };--}
− data/nix/tests/hash.sh
@@ -1,77 +0,0 @@-source common.sh--try () {-    printf "%s" "$2" > $TEST_ROOT/vector-    hash=$(nix-hash $EXTRA --flat --type "$1" $TEST_ROOT/vector)-    if test "$hash" != "$3"; then-        echo "hash $1, expected $3, got $hash"-        exit 1-    fi-}--try md5 "" "d41d8cd98f00b204e9800998ecf8427e"-try md5 "a" "0cc175b9c0f1b6a831c399e269772661"-try md5 "abc" "900150983cd24fb0d6963f7d28e17f72"-try md5 "message digest" "f96b697d7cb7938d525a2f31aaf161d0"-try md5 "abcdefghijklmnopqrstuvwxyz" "c3fcd3d76192e4007dfb496cca67e13b"-try md5 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" "d174ab98d277d9f5a5611c2c9f419d9f"-try md5 "12345678901234567890123456789012345678901234567890123456789012345678901234567890" "57edf4a22be3c955ac49da2e2107b67a"--try sha1 "" "da39a3ee5e6b4b0d3255bfef95601890afd80709"-try sha1 "abc" "a9993e364706816aba3e25717850c26c9cd0d89d"-try sha1 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" "84983e441c3bd26ebaae4aa1f95129e5e54670f1"--try sha256 "" "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"-try sha256 "abc" "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"-try sha256 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"--try sha512 "" "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"-try sha512 "abc" "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"-try sha512 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445"--EXTRA=--base32-try sha256 "abc" "1b8m03r63zqhnjf7l5wnldhh7c134ap5vpj0850ymkq1iyzicy5s"-EXTRA=--try2 () {-    hash=$(nix-hash --type "$1" $TEST_ROOT/hash-path)-    if test "$hash" != "$2"; then-        echo "hash $1, expected $2, got $hash"-        exit 1-    fi-}--rm -rf $TEST_ROOT/hash-path-mkdir $TEST_ROOT/hash-path-echo "Hello World" > $TEST_ROOT/hash-path/hello--try2 md5 "ea9b55537dd4c7e104515b2ccfaf4100"--# Execute bit matters.-chmod +x $TEST_ROOT/hash-path/hello-try2 md5 "20f3ffe011d4cfa7d72bfabef7882836"--# Mtime and other bits don't.-touch -r . $TEST_ROOT/hash-path/hello-chmod 744 $TEST_ROOT/hash-path/hello-try2 md5 "20f3ffe011d4cfa7d72bfabef7882836"--# File type (e.g., symlink) does.-rm $TEST_ROOT/hash-path/hello-ln -s x $TEST_ROOT/hash-path/hello-try2 md5 "f78b733a68f5edbdf9413899339eaa4a"--# Conversion.-try3() {-    h64=$(nix to-base64 --type "$1" "$2")-    [ "$h64" = "$4" ]-    h32=$(nix-hash --type "$1" --to-base32 "$2")-    [ "$h32" = "$3" ]-    h16=$(nix-hash --type "$1" --to-base16 "$h32")-    [ "$h16" = "$2" ]-    h16=$(nix to-base16 --type "$1" "$h64")-    [ "$h16" = "$2" ]-}-try3 sha1 "800d59cfcd3c05e900cb4e214be48f6b886a08df" "vw46m23bizj4n8afrc0fj19wrp7mj3c0" "gA1Zz808BekAy04hS+SPa4hqCN8="-try3 sha256 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" "1b8m03r63zqhnjf7l5wnldhh7c134ap5vpj0850ymkq1iyzicy5s" "ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0="-try3 sha512 "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445" "12k9jiq29iyqm03swfsgiw5mlqs173qazm3n7daz43infy12pyrcdf30fkk3qwv4yl2ick8yipc2mqnlh48xsvvxl60lbx8vp38yji0" "IEqPxt2oLwoM7XvrjgikFlfBbvRosiioJ5vjMacDwzWW/RXBOxsH+aodO+pXeJygMa2Fx6cd1wNU7GMSOMo0RQ=="
− data/nix/tests/import-derivation.nix
@@ -1,23 +0,0 @@-with import ./config.nix;--let--  bar = mkDerivation {-    name = "bar";-    builder = builtins.toFile "builder.sh"-      ''-        echo 'builtins.add 123 456' > $out-      '';-  };--  value = import bar;--in--mkDerivation {-  name = "foo";-  builder = builtins.toFile "builder.sh"-    ''-      echo -n FOO${toString value} > $out-    '';-}
− data/nix/tests/import-derivation.sh
@@ -1,12 +0,0 @@-source common.sh--clearStore--if nix-instantiate --readonly-mode ./import-derivation.nix; then-    echo "read-only evaluation of an imported derivation unexpectedly failed"-    exit 1-fi--outPath=$(nix-build ./import-derivation.nix --no-out-link)--[ "$(cat $outPath)" = FOO579 ]
− data/nix/tests/init.sh
@@ -1,33 +0,0 @@-source common.sh--test -n "$TEST_ROOT"-if test -d "$TEST_ROOT"; then-    chmod -R u+w "$TEST_ROOT"-    rm -rf "$TEST_ROOT"-fi-mkdir "$TEST_ROOT"--mkdir "$NIX_STORE_DIR"-mkdir "$NIX_LOCALSTATE_DIR"-mkdir -p "$NIX_LOG_DIR"/drvs-mkdir "$NIX_STATE_DIR"-mkdir "$NIX_CONF_DIR"--cat > "$NIX_CONF_DIR"/nix.conf <<EOF-build-users-group =-keep-derivations = false-include nix.conf.extra-EOF--cat > "$NIX_CONF_DIR"/nix.conf.extra <<EOF-fsync-metadata = false-!include nix.conf.extra.not-there-EOF--# Initialise the database.-nix-store --init--# Did anything happen?-test -e "$NIX_STATE_DIR"/db/db.sqlite--echo 'Hello World' > ./dummy
− data/nix/tests/install-darwin.sh
@@ -1,96 +0,0 @@-#!/bin/sh--set -eux--cleanup() {-    PLIST="/Library/LaunchDaemons/org.nixos.nix-daemon.plist"-    if sudo launchctl list | grep -q nix-daemon; then-        sudo launchctl unload "$PLIST"-    fi--    if [ -f "$PLIST" ]; then-        sudo rm /Library/LaunchDaemons/org.nixos.nix-daemon.plist-    fi--    profiles=(/etc/profile /etc/bashrc /etc/zshrc)-    for profile in "${profiles[@]}"; do-        if [ -f "${profile}.backup-before-nix" ]; then-            sudo mv "${profile}.backup-before-nix" "${profile}"-        fi-    done--    for file in ~/.bash_profile ~/.bash_login ~/.profile ~/.zshenv ~/.zprofile ~/.zshrc ~/.zlogin; do-        if [ -e "$file" ]; then-            cat "$file" | grep -v nix-profile > "$file.next"-            mv "$file.next" "$file"-        fi-    done--    for i in $(seq 1 $(sysctl -n hw.ncpu)); do-        sudo /usr/bin/dscl . -delete "/Users/nixbld$i" || true-    done-    sudo /usr/bin/dscl . -delete "/Groups/nixbld" || true--    sudo rm -rf /etc/nix \-         /nix \-         /var/root/.nix-profile /var/root/.nix-defexpr /var/root/.nix-channels \-         "$USER/.nix-profile" "$USER/.nix-defexpr" "$USER/.nix-channels"-}--verify() {-    set +e-    output=$(echo "nix-shell -p bash --run 'echo toow | rev'" | bash -l)-    set -e--    test "$output" = "woot"-}--scratch=$(mktemp -d -t tmp.XXXXXXXXXX)-function finish {-    rm -rf "$scratch"-}-trap finish EXIT--# First setup Nix-cleanup-curl -o install https://nixos.org/nix/install-yes | bash ./install-verify---(-    set +e-    (-        echo "cd $(pwd)"-        echo nix-build ./release.nix -A binaryTarball.x86_64-darwin-    ) | bash -l-    set -e-    cp ./result/nix-*.tar.bz2 $scratch/nix.tar.bz2-)--(-    cd $scratch-    tar -xf ./nix.tar.bz2--    cd nix-*--    set -eux--    cleanup--    yes | ./install-    verify-    cleanup--    echo -n "" | ./install-    verify-    cleanup--    sudo mkdir -p /nix/store-    sudo touch /nix/store/.silly-hint-    echo -n "" | ALLOW_PREEXISTING_INSTALLATION=true ./install-    verify-    test -e /nix/store/.silly-hint--    cleanup-)
− data/nix/tests/lang.sh
@@ -1,70 +0,0 @@-source common.sh--export TEST_VAR=foo # for eval-okay-getenv.nix--nix-instantiate --eval -E 'builtins.trace "Hello" 123' 2>&1 | grep -q Hello-(! nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello" 123' 2>&1 | grep -q Hello)-nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello" (throw "Foo")' 2>&1 | grep -q Hello--set +x--fail=0--for i in lang/parse-fail-*.nix; do-    echo "parsing $i (should fail)";-    i=$(basename $i .nix)-    if nix-instantiate --parse - < lang/$i.nix; then-        echo "FAIL: $i shouldn't parse"-        fail=1-    fi-done--for i in lang/parse-okay-*.nix; do-    echo "parsing $i (should succeed)";-    i=$(basename $i .nix)-    if ! nix-instantiate --parse - < lang/$i.nix > lang/$i.out; then-        echo "FAIL: $i should parse"-        fail=1-    fi-done--for i in lang/eval-fail-*.nix; do-    echo "evaluating $i (should fail)";-    i=$(basename $i .nix)-    if nix-instantiate --eval lang/$i.nix; then-        echo "FAIL: $i shouldn't evaluate"-        fail=1-    fi-done--for i in lang/eval-okay-*.nix; do-    echo "evaluating $i (should succeed)";-    i=$(basename $i .nix)--    if test -e lang/$i.exp; then-        flags=-        if test -e lang/$i.flags; then-            flags=$(cat lang/$i.flags)-        fi-        if ! NIX_PATH=lang/dir3:lang/dir4 nix-instantiate $flags --eval --strict lang/$i.nix > lang/$i.out; then-            echo "FAIL: $i should evaluate"-            fail=1-        elif ! diff lang/$i.out lang/$i.exp; then-            echo "FAIL: evaluation result of $i not as expected"-            fail=1-        fi-    fi--    if test -e lang/$i.exp.xml; then-        if ! nix-instantiate --eval --xml --no-location --strict \-                lang/$i.nix > lang/$i.out.xml; then-            echo "FAIL: $i should evaluate"-            fail=1-        elif ! cmp -s lang/$i.out.xml lang/$i.exp.xml; then-            echo "FAIL: XML evaluation result of $i not as expected"-            fail=1-        fi-    fi-done--exit $fail
+ data/nix/tests/lang/binary-data view

binary file changed (absent → 1024 bytes)

− data/nix/tests/lang/eval-fail-antiquoted-path.nix
@@ -1,4 +0,0 @@-# This must fail to evaluate, since ./fnord doesn't exist.  If it did-# exist, it would produce "/nix/store/<hash>-fnord/xyzzy" (with an-# appropriate context).-"${./fnord}/xyzzy"
+ data/nix/tests/lang/eval-fail-hashfile-missing.nix view
@@ -0,0 +1,5 @@+let+  paths = [ ./this-file-is-definitely-not-there-7392097 "/and/neither/is/this/37293620" ];+in+  toString (builtins.concatLists (map (hash: map (builtins.hashFile hash) paths) ["md5" "sha1" "sha256" "sha512"]))+
data/nix/tests/lang/eval-okay-arithmetic.exp view
@@ -1,1 +1,1 @@-2188+2216
data/nix/tests/lang/eval-okay-arithmetic.nix view
@@ -26,6 +26,10 @@       (56088 / 123 / 2)       (3 + 4 * const 5 0 - 6 / id 2) +      (builtins.bitAnd 12 10) # 0b1100 & 0b1010 =  8+      (builtins.bitOr  12 10) # 0b1100 | 0b1010 = 14+      (builtins.bitXor 12 10) # 0b1100 ^ 0b1010 =  6+       (if 3 < 7 then 1 else err)       (if 7 < 3 then err else 1)       (if 3 < 3 then err else 1)
data/nix/tests/lang/eval-okay-builtins-add.exp view
@@ -1,1 +1,1 @@-[ 5 4 "int" "tt" "float" 4.0 ]+[ 5 4 "int" "tt" "float" 4 ]
+ data/nix/tests/lang/eval-okay-concatmap.exp view
@@ -0,0 +1,1 @@+[ [ 1 3 5 7 9 ] [ "a" "z" "b" "z" ] ]
+ data/nix/tests/lang/eval-okay-concatmap.nix view
@@ -0,0 +1,5 @@+with import ./lib.nix;++[ (builtins.concatMap (x: if x / 2 * 2 == x then [] else [ x ]) (range 0 10))+  (builtins.concatMap (x: [x] ++ ["z"]) ["a" "b"])+]
+ data/nix/tests/lang/eval-okay-context-introspection.exp view
@@ -0,0 +1,1 @@+true
+ data/nix/tests/lang/eval-okay-context-introspection.nix view
@@ -0,0 +1,24 @@+let+  drv = derivation {+    name = "fail";+    builder = "/bin/false";+    system = "x86_64-linux";+    outputs = [ "out" "foo" ];+  };++  path = "${./eval-okay-context-introspection.nix}";++  desired-context = {+    "${builtins.unsafeDiscardStringContext path}" = {+      path = true;+    };+    "${builtins.unsafeDiscardStringContext drv.drvPath}" = {+      outputs = [ "foo" "out" ];+      allOutputs = true;+    };+  };++  legit-context = builtins.getContext "${path}${drv.outPath}${drv.foo.outPath}${drv.drvPath}";++  constructed-context = builtins.getContext (builtins.appendContext "" desired-context);+in legit-context == constructed-context
+ data/nix/tests/lang/eval-okay-float.exp view
@@ -0,0 +1,1 @@+[ 3.4 3.5 2.5 1.5 ]
+ data/nix/tests/lang/eval-okay-float.nix view
@@ -0,0 +1,6 @@+[+  (1.1 + 2.3)+  (builtins.add (0.5 + 0.5) (2.0 + 0.5))+  ((0.5 + 0.5) * (2.0 + 0.5))+  ((1.5 + 1.5) / (0.5 * 4.0))+]
+ data/nix/tests/lang/eval-okay-fromTOML.exp view
@@ -0,0 +1,1 @@+[ { clients = { data = [ [ "gamma" "delta" ] [ 1 2 ] ]; hosts = [ "alpha" "omega" ]; }; database = { connection_max = 5000; enabled = true; ports = [ 8001 8001 8002 ]; server = "192.168.1.1"; }; owner = { name = "Tom Preston-Werner"; }; servers = { alpha = { dc = "eqdc10"; ip = "10.0.0.1"; }; beta = { dc = "eqdc10"; ip = "10.0.0.2"; }; }; title = "TOML Example"; } { "1234" = "value"; "127.0.0.1" = "value"; a = { b = { c = { }; }; }; arr1 = [ 1 2 3 ]; arr2 = [ "red" "yellow" "green" ]; arr3 = [ [ 1 2 ] [ 3 4 5 ] ]; arr4 = [ "all" "strings" "are the same" "type" ]; arr5 = [ [ 1 2 ] [ "a" "b" "c" ] ]; arr7 = [ 1 2 3 ]; arr8 = [ 1 2 ]; bare-key = "value"; bare_key = "value"; bin1 = 214; bool1 = true; bool2 = false; "character encoding" = "value"; d = { e = { f = { }; }; }; dog = { "tater.man" = { type = { name = "pug"; }; }; }; flt1 = 1; flt2 = 3.1415; flt3 = -0.01; flt4 = 5e+22; flt5 = 1e+06; flt6 = -0.02; flt7 = 6.626e-34; flt8 = 9.22462e+06; fruit = [ { name = "apple"; physical = { color = "red"; shape = "round"; }; variety = [ { name = "red delicious"; } { name = "granny smith"; } ]; } { name = "banana"; variety = [ { name = "plantain"; } ]; } ]; g = { h = { i = { }; }; }; hex1 = 3735928559; hex2 = 3735928559; hex3 = 3735928559; int1 = 99; int2 = 42; int3 = 0; int4 = -17; int5 = 1000; int6 = 5349221; int7 = 12345; j = { "ʞ" = { l = { }; }; }; key = "value"; key2 = "value"; name = "Orange"; oct1 = 342391; oct2 = 493; physical = { color = "orange"; shape = "round"; }; products = [ { name = "Hammer"; sku = 738594937; } { } { color = "gray"; name = "Nail"; sku = 284758393; } ]; "quoted \"value\"" = "value"; site = { "google.com" = true; }; str = "I'm a string. \"You can quote me\". Name\tJosé\nLocation\tSF."; table-1 = { key1 = "some string"; key2 = 123; }; table-2 = { key1 = "another string"; key2 = 456; }; x = { y = { z = { w = { animal = { type = { name = "pug"; }; }; name = { first = "Tom"; last = "Preston-Werner"; }; point = { x = 1; y = 2; }; }; }; }; }; "ʎǝʞ" = "value"; } { metadata = { "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"; "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"; "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"; "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"; }; package = [ { dependencies = [ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" ]; name = "aho-corasick"; source = "registry+https://github.com/rust-lang/crates.io-index"; version = "0.6.4"; } { name = "ansi_term"; source = "registry+https://github.com/rust-lang/crates.io-index"; version = "0.9.0"; } { dependencies = [ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" ]; name = "atty"; source = "registry+https://github.com/rust-lang/crates.io-index"; version = "0.2.10"; } ]; } { a = [ [ { b = true; } ] ]; c = [ [ { d = true; } ] ]; e = [ [ 123 ] ]; } ]
+ data/nix/tests/lang/eval-okay-fromTOML.nix view
@@ -0,0 +1,208 @@+[++  (builtins.fromTOML ''+    # This is a TOML document.++    title = "TOML Example"++    [owner]+    name = "Tom Preston-Werner"+    #dob = 1979-05-27T07:32:00-08:00 # First class dates++    [database]+    server = "192.168.1.1"+    ports = [ 8001, 8001, 8002 ]+    connection_max = 5000+    enabled = true++    [servers]++      # Indentation (tabs and/or spaces) is allowed but not required+      [servers.alpha]+      ip = "10.0.0.1"+      dc = "eqdc10"++      [servers.beta]+      ip = "10.0.0.2"+      dc = "eqdc10"++    [clients]+    data = [ ["gamma", "delta"], [1, 2] ]++    # Line breaks are OK when inside arrays+    hosts = [+      "alpha",+      "omega"+    ]+  '')++  (builtins.fromTOML ''+    key = "value"+    bare_key = "value"+    bare-key = "value"+    1234 = "value"++    "127.0.0.1" = "value"+    "character encoding" = "value"+    "ʎǝʞ" = "value"+    'key2' = "value"+    'quoted "value"' = "value"++    name = "Orange"++    physical.color = "orange"+    physical.shape = "round"+    site."google.com" = true++    # This is legal according to the spec, but cpptoml doesn't handle it.+    #a.b.c = 1+    #a.d = 2++    str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF."++    int1 = +99+    int2 = 42+    int3 = 0+    int4 = -17+    int5 = 1_000+    int6 = 5_349_221+    int7 = 1_2_3_4_5++    hex1 = 0xDEADBEEF+    hex2 = 0xdeadbeef+    hex3 = 0xdead_beef++    oct1 = 0o01234567+    oct2 = 0o755++    bin1 = 0b11010110++    flt1 = +1.0+    flt2 = 3.1415+    flt3 = -0.01+    flt4 = 5e+22+    flt5 = 1e6+    flt6 = -2E-2+    flt7 = 6.626e-34+    flt8 = 9_224_617.445_991_228_313++    bool1 = true+    bool2 = false++    # FIXME: not supported because Nix doesn't have a date/time type.+    #odt1 = 1979-05-27T07:32:00Z+    #odt2 = 1979-05-27T00:32:00-07:00+    #odt3 = 1979-05-27T00:32:00.999999-07:00+    #odt4 = 1979-05-27 07:32:00Z+    #ldt1 = 1979-05-27T07:32:00+    #ldt2 = 1979-05-27T00:32:00.999999+    #ld1 = 1979-05-27+    #lt1 = 07:32:00+    #lt2 = 00:32:00.999999++    arr1 = [ 1, 2, 3 ]+    arr2 = [ "red", "yellow", "green" ]+    arr3 = [ [ 1, 2 ], [3, 4, 5] ]+    arr4 = [ "all", 'strings', """are the same""", ''''type'''']+    arr5 = [ [ 1, 2 ], ["a", "b", "c"] ]++    arr7 = [+      1, 2, 3+    ]++    arr8 = [+      1,+      2, # this is ok+    ]++    [table-1]+    key1 = "some string"+    key2 = 123+++    [table-2]+    key1 = "another string"+    key2 = 456++    [dog."tater.man"]+    type.name = "pug"++    [a.b.c]+    [ d.e.f ]+    [ g .  h  . i ]+    [ j . "ʞ" . 'l' ]+    [x.y.z.w]++    name = { first = "Tom", last = "Preston-Werner" }+    point = { x = 1, y = 2 }+    animal = { type.name = "pug" }++    [[products]]+    name = "Hammer"+    sku = 738594937++    [[products]]++    [[products]]+    name = "Nail"+    sku = 284758393+    color = "gray"++    [[fruit]]+      name = "apple"++      [fruit.physical]+        color = "red"+        shape = "round"++      [[fruit.variety]]+        name = "red delicious"++      [[fruit.variety]]+        name = "granny smith"++    [[fruit]]+      name = "banana"++      [[fruit.variety]]+        name = "plantain"+  '')++  (builtins.fromTOML ''+    [[package]]+    name = "aho-corasick"+    version = "0.6.4"+    source = "registry+https://github.com/rust-lang/crates.io-index"+    dependencies = [+     "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",+    ]++    [[package]]+    name = "ansi_term"+    version = "0.9.0"+    source = "registry+https://github.com/rust-lang/crates.io-index"++    [[package]]+    name = "atty"+    version = "0.2.10"+    source = "registry+https://github.com/rust-lang/crates.io-index"+    dependencies = [+     "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",+     "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",+     "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",+    ]++    [metadata]+    "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"+    "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"+    "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"+    "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"+  '')++  (builtins.fromTOML ''+    a = [[{ b = true }]]+    c = [ [ { d = true } ] ]+    e = [[123]]+  '')++]
data/nix/tests/lang/eval-okay-hash.exp view
@@ -1,1 +0,0 @@-[ "d41d8cd98f00b204e9800998ecf8427e" "6c69ee7f211c640419d5366cc076ae46" "bb3438fbabd460ea6dbd27d153e2233b" "da39a3ee5e6b4b0d3255bfef95601890afd80709" "cd54e8568c1b37cf1e5badb0779bcbf382212189" "6d12e10b1d331dad210e47fd25d4f260802b7e77" "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" "900a4469df00ccbfd0c145c6d1e4b7953dd0afafadd7534e3a4019e8d38fc663" "ad0387b3bd8652f730ca46d25f9c170af0fd589f42e7f23f5a9e6412d97d7e56" "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" "9d0886f8c6b389398a16257bc79780fab9831c7fc11c8ab07fa732cb7b348feade382f92617c9c5305fefba0af02ab5fd39a587d330997ff5bd0db19f7666653" "21644b72aa259e5a588cd3afbafb1d4310f4889680f6c83b9d531596a5a284f34dbebff409d23bcc86aee6bad10c891606f075c6f4755cb536da27db5693f3a7" ]
− data/nix/tests/lang/eval-okay-hash.nix
@@ -1,4 +0,0 @@-let-  strings = [ "" "text 1" "text 2" ];-in-  builtins.concatLists (map (hash: map (builtins.hashString hash) strings) ["md5" "sha1" "sha256" "sha512"])
+ data/nix/tests/lang/eval-okay-hashfile.exp view
@@ -0,0 +1,1 @@+[ "d3b07384d113edec49eaa6238ad5ff00" "0f343b0931126a20f133d67c2b018a3b" "f1d2d2f924e986ac86fdf7b36c94bcdf32beec15" "60cacbf3d72e1e7834203da608037b1bf83b40e8" "b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c" "5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef" "0cf9180a764aba863a67b6d72f0918bc131c6772642cb2dce5a34f0a702f9470ddc2bf125c12198b1995c233c34b4afd346c54a2334c350a948a51b6e8b4e6b6" "8efb4f73c5655351c444eb109230c556d39e2c7624e9c11abc9e3fb4b9b9254218cc5085b454a9698d085cfa92198491f07a723be4574adc70617b73eb0b6461" ]
+ data/nix/tests/lang/eval-okay-hashfile.nix view
@@ -0,0 +1,4 @@+let+  paths = [ ./data ./binary-data ];+in+  builtins.concatLists (map (hash: map (builtins.hashFile hash) paths) ["md5" "sha1" "sha256" "sha512"])
+ data/nix/tests/lang/eval-okay-hashstring.exp view
@@ -0,0 +1,1 @@+[ "d41d8cd98f00b204e9800998ecf8427e" "6c69ee7f211c640419d5366cc076ae46" "bb3438fbabd460ea6dbd27d153e2233b" "da39a3ee5e6b4b0d3255bfef95601890afd80709" "cd54e8568c1b37cf1e5badb0779bcbf382212189" "6d12e10b1d331dad210e47fd25d4f260802b7e77" "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" "900a4469df00ccbfd0c145c6d1e4b7953dd0afafadd7534e3a4019e8d38fc663" "ad0387b3bd8652f730ca46d25f9c170af0fd589f42e7f23f5a9e6412d97d7e56" "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" "9d0886f8c6b389398a16257bc79780fab9831c7fc11c8ab07fa732cb7b348feade382f92617c9c5305fefba0af02ab5fd39a587d330997ff5bd0db19f7666653" "21644b72aa259e5a588cd3afbafb1d4310f4889680f6c83b9d531596a5a284f34dbebff409d23bcc86aee6bad10c891606f075c6f4755cb536da27db5693f3a7" ]
+ data/nix/tests/lang/eval-okay-hashstring.nix view
@@ -0,0 +1,4 @@+let+  strings = [ "" "text 1" "text 2" ];+in+  builtins.concatLists (map (hash: map (builtins.hashString hash) strings) ["md5" "sha1" "sha256" "sha512"])
data/nix/tests/lang/eval-okay-ind-string.exp view
@@ -1,1 +1,1 @@-"This is an indented multi-line string\nliteral.  An amount of whitespace at\nthe start of each line matching the minimum\nindentation of all lines in the string\nliteral together will be removed.  Thus,\nin this case four spaces will be\nstripped from each line, even though\n  THIS LINE is indented six spaces.\n\nAlso, empty lines don't count in the\ndetermination of the indentation level (the\nprevious empty line has indentation 0, but\nit doesn't matter).\nIf the string starts with whitespace\n  followed by a newline, it's stripped, but\n  that's not the case here. Two spaces are\n  stripped because of the \"  \" at the start. \nThis line is indented\na bit further.\nAnti-quotations, like so, are\nalso allowed.\n  The \\ is not special here.\n' can be followed by any character except another ', e.g. 'x'.\nLikewise for $, e.g. $$ or $varName.\nBut ' followed by ' is special, as is $ followed by {.\nIf you want them, use anti-quotations: '', ${.\n   Tabs are not interpreted as whitespace (since we can't guess\n   what tab settings are intended), so don't use them.\n\tThis line starts with a space and a tab, so only one\n   space will be stripped from each line.\nAlso note that if the last line (just before the closing ' ')\nconsists only of whitespace, it's ignored.  But here there is\nsome non-whitespace stuff, so the line isn't removed. \nThis shows a hacky way to preserve an empty line after the start.\nBut there's no reason to do so: you could just repeat the empty\nline.\n  Similarly you can force an indentation level,\n  in this case to 2 spaces.  This works because the anti-quote\n  is significant (not whitespace).\nstart on network-interfaces\n\nstart script\n\n  rm -f /var/run/opengl-driver\n  ln -sf 123 /var/run/opengl-driver\n\n  rm -f /var/log/slim.log\n   \nend script\n\nenv SLIM_CFGFILE=abc\nenv SLIM_THEMESDIR=def\nenv FONTCONFIG_FILE=/etc/fonts/fonts.conf  \t\t\t\t# !!! cleanup\nenv XKB_BINDIR=foo/bin         \t\t\t\t# Needed for the Xkb extension.\nenv LD_LIBRARY_PATH=libX11/lib:libXext/lib:/usr/lib/          # related to xorg-sys-opengl - needed to load libglx for (AI)GLX support (for compiz)\n\nenv XORG_DRI_DRIVER_PATH=nvidiaDrivers/X11R6/lib/modules/drivers/ \n\nexec slim/bin/slim\nEscaping of ' followed by ': ''\nEscaping of $ followed by {: ${\nAnd finally to interpret \\n etc. as in a string: \n, \r, \t.\nfoo\n'bla'\nbar\ncut -d $'\\t' -f 1\nending dollar $$\n"+"This is an indented multi-line string\nliteral.  An amount of whitespace at\nthe start of each line matching the minimum\nindentation of all lines in the string\nliteral together will be removed.  Thus,\nin this case four spaces will be\nstripped from each line, even though\n  THIS LINE is indented six spaces.\n\nAlso, empty lines don't count in the\ndetermination of the indentation level (the\nprevious empty line has indentation 0, but\nit doesn't matter).\nIf the string starts with whitespace\n  followed by a newline, it's stripped, but\n  that's not the case here. Two spaces are\n  stripped because of the \"  \" at the start. \nThis line is indented\na bit further.\nAnti-quotations, like so, are\nalso allowed.\n  The \\ is not special here.\n' can be followed by any character except another ', e.g. 'x'.\nLikewise for $, e.g. $$ or $varName.\nBut ' followed by ' is special, as is $ followed by {.\nIf you want them, use anti-quotations: '', \${.\n   Tabs are not interpreted as whitespace (since we can't guess\n   what tab settings are intended), so don't use them.\n\tThis line starts with a space and a tab, so only one\n   space will be stripped from each line.\nAlso note that if the last line (just before the closing ' ')\nconsists only of whitespace, it's ignored.  But here there is\nsome non-whitespace stuff, so the line isn't removed. \nThis shows a hacky way to preserve an empty line after the start.\nBut there's no reason to do so: you could just repeat the empty\nline.\n  Similarly you can force an indentation level,\n  in this case to 2 spaces.  This works because the anti-quote\n  is significant (not whitespace).\nstart on network-interfaces\n\nstart script\n\n  rm -f /var/run/opengl-driver\n  ln -sf 123 /var/run/opengl-driver\n\n  rm -f /var/log/slim.log\n   \nend script\n\nenv SLIM_CFGFILE=abc\nenv SLIM_THEMESDIR=def\nenv FONTCONFIG_FILE=/etc/fonts/fonts.conf  \t\t\t\t# !!! cleanup\nenv XKB_BINDIR=foo/bin         \t\t\t\t# Needed for the Xkb extension.\nenv LD_LIBRARY_PATH=libX11/lib:libXext/lib:/usr/lib/          # related to xorg-sys-opengl - needed to load libglx for (AI)GLX support (for compiz)\n\nenv XORG_DRI_DRIVER_PATH=nvidiaDrivers/X11R6/lib/modules/drivers/ \n\nexec slim/bin/slim\nEscaping of ' followed by ': ''\nEscaping of $ followed by {: \${\nAnd finally to interpret \\n etc. as in a string: \n, \r, \t.\nfoo\n'bla'\nbar\ncut -d $'\\t' -f 1\nending dollar $$\n"
+ data/nix/tests/lang/eval-okay-mapattrs.exp view
@@ -0,0 +1,1 @@+{ x = "x-foo"; y = "y-bar"; }
+ data/nix/tests/lang/eval-okay-mapattrs.nix view
@@ -0,0 +1,3 @@+with import ./lib.nix;++builtins.mapAttrs (name: value: name + "-" + value) { x = "foo"; y = "bar"; }
data/nix/tests/lang/eval-okay-search-path.nix view
@@ -1,10 +1,9 @@ with import ./lib.nix; with builtins; -assert pathExists <nix/buildenv.nix>;+assert isFunction (import <nix/fetchurl.nix>); -assert length __nixPath == 6;-assert length (filter (x: x.prefix == "nix") __nixPath) == 1;+assert length __nixPath == 5; assert length (filter (x: baseNameOf x.path == "dir4") __nixPath) == 1;  import <a.nix> + import <b.nix> + import <c.nix> + import <dir5/c.nix>
data/nix/tests/lang/eval-okay-sort.exp view
@@ -1,1 +1,1 @@-[ [ 42 77 147 249 483 526 ] [ 526 483 249 147 77 42 ] [ "bar" "fnord" "foo" "xyzzy" ] [ { key = 1; value = "foo"; } { key = 1; value = "fnord"; } { key = 2; value = "bar"; } ] ]+[ [ 42 77 147 249 483 526 ] [ 526 483 249 147 77 42 ] [ "bar" "fnord" "foo" "xyzzy" ] [ { key = 1; value = "foo"; } { key = 1; value = "fnord"; } { key = 2; value = "bar"; } ] [ [ ] [ ] [ 1 ] [ 1 4 ] [ 1 5 ] [ 1 6 ] [ 2 ] [ 2 3 ] [ 3 ] [ 3 ] ] ]
data/nix/tests/lang/eval-okay-sort.nix view
@@ -4,5 +4,17 @@   (sort (x: y: y < x) [ 483 249 526 147 42 77 ])   (sort lessThan [ "foo" "bar" "xyzzy" "fnord" ])   (sort (x: y: x.key < y.key)-    [ { key = 1; value = "foo"; } { key = 2; value = "bar"; } { key = 1; value = "fnord"; } ]) +    [ { key = 1; value = "foo"; } { key = 2; value = "bar"; } { key = 1; value = "fnord"; } ])+  (sort lessThan [+    [ 1 6 ]+    [ ]+    [ 2 3 ]+    [ 3 ]+    [ 1 5 ]+    [ 2 ]+    [ 1 ]+    [ ]+    [ 1 4 ]+    [ 3 ]+  ]) ]
data/nix/tests/lang/eval-okay-tojson.exp view
@@ -1,1 +1,1 @@-"{\"a\":123,\"b\":-456,\"c\":\"foo\",\"d\":\"foo\\n\\\"bar\\\"\",\"e\":true,\"f\":false,\"g\":[1,2,3],\"h\":[\"a\",[\"b\",{\"foo\\nbar\":{}}]],\"i\":3,\"j\":1.44}"+"{\"a\":123,\"b\":-456,\"c\":\"foo\",\"d\":\"foo\\n\\\"bar\\\"\",\"e\":true,\"f\":false,\"g\":[1,2,3],\"h\":[\"a\",[\"b\",{\"foo\\nbar\":{}}]],\"i\":3,\"j\":1.44,\"k\":\"foo\"}"
data/nix/tests/lang/eval-okay-tojson.nix view
@@ -9,4 +9,5 @@     h = [ "a" [ "b" { "foo\nbar" = {}; } ] ];     i = 1 + 2;     j = 1.44;+    k = { __toString = self: self.a; a = "foo"; };   }
data/nix/tests/lang/eval-okay-types.exp view
@@ -1,1 +1,1 @@-[ true false true false true false true false true true true true true true true true true true true false true false "int" "bool" "string" "null" "set" "list" "lambda" "lambda" "lambda" "lambda" ]+[ true false true false true false true false true true true true true true true true true true true false true true true false "int" "bool" "string" "null" "set" "list" "lambda" "lambda" "lambda" "lambda" ]
data/nix/tests/lang/eval-okay-types.nix view
@@ -20,6 +20,8 @@   (isFloat (1 - 2.0))   (isBool (true && false))   (isBool null)+  (isPath /nix/store)+  (isPath ./.)   (isAttrs { x = 123; })   (isAttrs null)   (typeOf (3 * 4))
− data/nix/tests/lang/parse-fail-dup-attrs-6.nix
@@ -1,4 +0,0 @@-{-  services.ssh.port = 23;-  services.ssh = { enable = true; };-}
+ data/nix/tests/lang/parse-fail-mixed-nested-attrs1.nix view
@@ -0,0 +1,4 @@+{ +  x.z = 3; +  x = { y = 3; z = 3; }; +}
+ data/nix/tests/lang/parse-fail-mixed-nested-attrs2.nix view
@@ -0,0 +1,4 @@+{ +  x.y.y = 3; +  x = { y.y= 3; z = 3; }; +}
+ data/nix/tests/lang/parse-fail-uft8.nix view
@@ -0,0 +1,1 @@+123 é 4
+ data/nix/tests/lang/parse-okay-dup-attrs-6.nix view
@@ -0,0 +1,4 @@+{+  services.ssh.port = 23;+  services.ssh = { enable = true; };+}
+ data/nix/tests/lang/parse-okay-mixed-nested-attrs-1.nix view
@@ -0,0 +1,4 @@+{ +  x = { y = 3; z = 3; }; +  x.q = 3; +}
+ data/nix/tests/lang/parse-okay-mixed-nested-attrs-2.nix view
@@ -0,0 +1,4 @@+{ +  x.q = 3; +  x = { y = 3; z = 3; }; +}
+ data/nix/tests/lang/parse-okay-mixed-nested-attrs-3.nix view
@@ -0,0 +1,7 @@+{+    services.ssh.enable = true;+    services.ssh = { port = 123; };+    services = {+        httpd.enable = true;+    };+}
data/nix/tests/lang/parse-okay-url.nix view
@@ -3,5 +3,6 @@   http://www2.mplayerhq.hu/MPlayer/releases/fonts/font-arial-iso-8859-1.tar.bz2   http://losser.st-lab.cs.uu.nl/~armijn/.nix/gcc-3.3.4-static-nix.tar.gz   http://fpdownload.macromedia.com/get/shockwave/flash/english/linux/7.0r25/install_flash_player_7_linux.tar.gz+  https://ftp5.gwdg.de/pub/linux/archlinux/extra/os/x86_64/unzip-6.0-14-x86_64.pkg.tar.zst   ftp://ftp.gtk.org/pub/gtk/v1.2/gtk+-1.2.10.tar.gz ]
− data/nix/tests/linux-sandbox.sh
@@ -1,27 +0,0 @@-source common.sh--clearStore--if ! canUseSandbox; then exit; fi--# Note: we need to bind-mount $SHELL into the chroot. Currently we-# only support the case where $SHELL is in the Nix store, because-# otherwise things get complicated (e.g. if it's in /bin, do we need-# /lib as well?).-if [[ ! $SHELL =~ /nix/store ]]; then exit; fi--chmod -R u+w $TEST_ROOT/store0 || true-rm -rf $TEST_ROOT/store0--export NIX_STORE_DIR=/my/store-export NIX_REMOTE=$TEST_ROOT/store0--outPath=$(nix-build dependencies.nix --no-out-link --sandbox-paths /nix/store)--[[ $outPath =~ /my/store/.*-dependencies ]]--nix path-info -r $outPath | grep input-2--nix ls-store -R -l $outPath | grep foobar--nix cat-store $outPath/foobar | grep FOOBAR
data/nix/tests/local.mk view
@@ -1,37 +1,77 @@-check:-	@echo "Warning: Nix has no 'make check'. Please install Nix and run 'make installcheck' instead."- nix_tests = \-  init.sh hash.sh lang.sh add.sh simple.sh dependencies.sh \-  gc.sh gc-concurrent.sh \+  hash.sh lang.sh add.sh simple.sh dependencies.sh \+  config.sh \+  gc.sh \+  ca/gc.sh \+  gc-concurrent.sh \+  gc-non-blocking.sh \+  gc-auto.sh \   referrers.sh user-envs.sh logging.sh nix-build.sh misc.sh fixed.sh \   gc-runtime.sh check-refs.sh filter-source.sh \-  remote-store.sh export.sh export-graph.sh \+  local-store.sh remote-store.sh export.sh export-graph.sh \+  db-migration.sh \   timeout.sh secure-drv-outputs.sh nix-channel.sh \-  multiple-outputs.sh import-derivation.sh fetchurl.sh optimise-store.sh \-  binary-cache.sh nix-profile.sh repair.sh dump-db.sh case-hack.sh \+  multiple-outputs.sh import-derivation.sh ca/import-derivation.sh fetchurl.sh optimise-store.sh \+  binary-cache.sh \+  substitute-with-invalid-ca.sh \+  binary-cache-build-remote.sh \+  nix-profile.sh repair.sh dump-db.sh case-hack.sh \   check-reqs.sh pass-as-file.sh tarball.sh restricted.sh \   placeholders.sh nix-shell.sh \   linux-sandbox.sh \   build-dry.sh \-  build-remote.sh \+  build-remote-input-addressed.sh \+  build-remote-content-addressed-fixed.sh \+  build-remote-content-addressed-floating.sh \+  ssh-relay.sh \   nar-access.sh \   structured-attrs.sh \   fetchGit.sh \+  fetchGitRefs.sh \+  fetchGitSubmodules.sh \   fetchMercurial.sh \   signing.sh \-  run.sh \+  shell.sh \   brotli.sh \+  zstd.sh \+  compression-levels.sh \   pure-eval.sh \   check.sh \   plugins.sh \-  search.sh+  search.sh \+  nix-copy-ssh.sh \+  post-hook.sh \+  ca/post-hook.sh \+  function-trace.sh \+  recursive.sh \+  describe-stores.sh \+  flakes.sh \+  flake-local-settings.sh \+  flake-searching.sh \+  build.sh \+  repl.sh ca/repl.sh \+  ca/build.sh \+  ca/build-with-garbage-path.sh \+  ca/duplicate-realisation-in-closure.sh \+  ca/substitute.sh \+  ca/signatures.sh \+  ca/nix-shell.sh \+  ca/nix-run.sh \+  ca/recursive.sh \+  ca/concurrent-builds.sh \+  ca/nix-copy.sh \+  eval-store.sh \+  readfile-context.sh   # parallel.sh +ifeq ($(HAVE_LIBCPUID), 1)+	nix_tests += compute-levels.sh+endif+ install-tests += $(foreach x, $(nix_tests), tests/$(x))  tests-environment = NIX_REMOTE= $(bash) -e -clean-files += $(d)/common.sh+clean-files += $(d)/common.sh $(d)/config.nix $(d)/ca/config.nix -installcheck: $(d)/common.sh $(d)/plugins/libplugintest.$(SO_EXT)+test-deps += tests/common.sh tests/config.nix tests/ca/config.nix tests/plugins/libplugintest.$(SO_EXT)
− data/nix/tests/logging.sh
@@ -1,15 +0,0 @@-source common.sh--clearStore--path=$(nix-build dependencies.nix --no-out-link)--# Test nix-store -l.-[ "$(nix-store -l $path)" = FOO ]--# Test compressed logs.-clearStore-rm -rf $NIX_LOG_DIR-(! nix-store -l $path)-nix-build dependencies.nix --no-out-link --compress-build-log-[ "$(nix-store -l $path)" = FOO ]
− data/nix/tests/misc.sh
@@ -1,19 +0,0 @@-source common.sh--# Tests miscellaneous commands.--# Do all commands have help?-#nix-env --help | grep -q install-#nix-store --help | grep -q realise-#nix-instantiate --help | grep -q eval-#nix-hash --help | grep -q base32--# Can we ask for the version number?-nix-env --version | grep "$version"--# Usage errors.-nix-env --foo 2>&1 | grep "no operation"-nix-env -q --foo 2>&1 | grep "unknown flag"--# Eval Errors.-nix-instantiate --eval -E 'let a = {} // a; in a.foo' 2>&1 | grep "infinite recursion encountered, at .*(string).*:1:15$"
− data/nix/tests/multiple-outputs.nix
@@ -1,68 +0,0 @@-with import ./config.nix;--rec {--  a = mkDerivation {-    name = "multiple-outputs-a";-    outputs = [ "first" "second" ];-    builder = builtins.toFile "builder.sh"-      ''-        mkdir $first $second-        test -z $all-        echo "first" > $first/file-        echo "second" > $second/file-        ln -s $first $second/link-      '';-    helloString = "Hello, world!";-  };--  b = mkDerivation {-    defaultOutput = assert a.second.helloString == "Hello, world!"; a;-    firstOutput = assert a.outputName == "first"; a.first.first;-    secondOutput = assert a.second.outputName == "second"; a.second.first.first.second.second.first.second;-    allOutputs = a.all;-    name = "multiple-outputs-b";-    builder = builtins.toFile "builder.sh"-      ''-        mkdir $out-        test "$firstOutput $secondOutput" = "$allOutputs"-        test "$defaultOutput" = "$firstOutput"-        test "$(cat $firstOutput/file)" = "first"-        test "$(cat $secondOutput/file)" = "second"-        echo "success" > $out/file-      '';-  };--  c = mkDerivation {-    name = "multiple-outputs-c";-    drv = b.drvPath;-    builder = builtins.toFile "builder.sh"-      ''-        mkdir $out-        ln -s $drv $out/drv-      '';-  };--  d = mkDerivation {-    name = "multiple-outputs-d";-    drv = builtins.unsafeDiscardOutputDependency b.drvPath;-    builder = builtins.toFile "builder.sh"-      ''-        mkdir $out-        echo $drv > $out/drv-      '';-  };--  cyclic = (mkDerivation {-    name = "cyclic-outputs";-    outputs = [ "a" "b" "c" ];-    builder = builtins.toFile "builder.sh"-      ''-        mkdir $a $b $c-        echo $a > $b/foo-        echo $b > $c/bar-        echo $c > $a/baz-      '';-  }).a;--}
− data/nix/tests/multiple-outputs.sh
@@ -1,76 +0,0 @@-source common.sh--clearStore--rm -f $TEST_ROOT/result*--# Test whether read-only evaluation works when referring to the-# ‘drvPath’ attribute.-echo "evaluating c..."-#drvPath=$(nix-instantiate multiple-outputs.nix -A c --readonly-mode)--# And check whether the resulting derivation explicitly depends on all-# outputs.-drvPath=$(nix-instantiate multiple-outputs.nix -A c)-#[ "$drvPath" = "$drvPath2" ]-grep -q 'multiple-outputs-a.drv",\["first","second"\]' $drvPath-grep -q 'multiple-outputs-b.drv",\["out"\]' $drvPath--# While we're at it, test the ‘unsafeDiscardOutputDependency’ primop.-outPath=$(nix-build multiple-outputs.nix -A d --no-out-link)-drvPath=$(cat $outPath/drv)-outPath=$(nix-store -q $drvPath)-(! [ -e "$outPath" ])--# Do a build of something that depends on a derivation with multiple-# outputs.-echo "building b..."-outPath=$(nix-build multiple-outputs.nix -A b --no-out-link)-echo "output path is $outPath"-[ "$(cat "$outPath"/file)" = "success" ]--# Test nix-build on a derivation with multiple outputs.-outPath1=$(nix-build multiple-outputs.nix -A a -o $TEST_ROOT/result)-[ -e $TEST_ROOT/result-first ]-(! [ -e $TEST_ROOT/result-second ])-nix-build multiple-outputs.nix -A a.all -o $TEST_ROOT/result-[ "$(cat $TEST_ROOT/result-first/file)" = "first" ]-[ "$(cat $TEST_ROOT/result-second/file)" = "second" ]-[ "$(cat $TEST_ROOT/result-second/link/file)" = "first" ]-hash1=$(nix-store -q --hash $TEST_ROOT/result-second)--outPath2=$(nix-build $(nix-instantiate multiple-outputs.nix -A a) --no-out-link)-[[ $outPath1 = $outPath2 ]]--outPath2=$(nix-build $(nix-instantiate multiple-outputs.nix -A a.first) --no-out-link)-[[ $outPath1 = $outPath2 ]]--outPath2=$(nix-build $(nix-instantiate multiple-outputs.nix -A a.second) --no-out-link)-[[ $(cat $outPath2/file) = second ]]--[[ $(nix-build $(nix-instantiate multiple-outputs.nix -A a.all) --no-out-link | wc -l) -eq 2 ]]--# Delete one of the outputs and rebuild it.  This will cause a hash-# rewrite.-nix-store --delete $TEST_ROOT/result-second --ignore-liveness-nix-build multiple-outputs.nix -A a.all -o $TEST_ROOT/result-[ "$(cat $TEST_ROOT/result-second/file)" = "second" ]-[ "$(cat $TEST_ROOT/result-second/link/file)" = "first" ]-hash2=$(nix-store -q --hash $TEST_ROOT/result-second)-[ "$hash1" = "$hash2" ]--# Make sure that nix-build works on derivations with multiple outputs.-echo "building a.first..."-nix-build multiple-outputs.nix -A a.first --no-out-link--# Cyclic outputs should be rejected.-echo "building cyclic..."-if nix-build multiple-outputs.nix -A cyclic --no-out-link; then-    echo "Cyclic outputs incorrectly accepted!"-    exit 1-fi--echo "collecting garbage..."-rm $TEST_ROOT/result*-nix-store --gc --keep-derivations --keep-outputs-nix-store --gc --print-roots
− data/nix/tests/nar-access.nix
@@ -1,23 +0,0 @@-with import ./config.nix;--rec {-    a = mkDerivation {-        name = "nar-index-a";-        builder = builtins.toFile "builder.sh"-      ''-        mkdir $out-        mkdir $out/foo-        touch $out/foo-x-        touch $out/foo/bar-        touch $out/foo/baz-        touch $out/qux-        mkdir $out/zyx--        cat >$out/foo/data <<EOF-        lasjdöaxnasd-asdom 12398-ä"§Æẞ¢«»”alsd-EOF-      '';-    };-}
− data/nix/tests/nar-access.sh
@@ -1,44 +0,0 @@-source common.sh--echo "building test path"-storePath="$(nix-build nar-access.nix -A a --no-out-link)"--cd "$TEST_ROOT"--# Dump path to nar.-narFile="$TEST_ROOT/path.nar"-nix-store --dump $storePath > $narFile--# Check that find and ls-nar match.-( cd $storePath; find . | sort ) > files.find-nix ls-nar -R -d $narFile "" | sort > files.ls-nar-diff -u files.find files.ls-nar--# Check that file contents of data match.-nix cat-nar $narFile /foo/data > data.cat-nar-diff -u data.cat-nar $storePath/foo/data--# Check that file contents of baz match.-nix cat-nar $narFile /foo/baz > baz.cat-nar-diff -u baz.cat-nar $storePath/foo/baz--nix cat-store $storePath/foo/baz > baz.cat-nar-diff -u baz.cat-nar $storePath/foo/baz--# Test --json.-[[ $(nix ls-nar --json $narFile /) = '{"type":"directory","entries":{"foo":{},"foo-x":{},"qux":{},"zyx":{}}}' ]]-[[ $(nix ls-nar --json -R $narFile /foo) = '{"type":"directory","entries":{"bar":{"type":"regular","size":0,"narOffset":368},"baz":{"type":"regular","size":0,"narOffset":552},"data":{"type":"regular","size":58,"narOffset":736}}}' ]]-[[ $(nix ls-nar --json -R $narFile /foo/bar) = '{"type":"regular","size":0,"narOffset":368}' ]]-[[ $(nix ls-store --json $storePath) = '{"type":"directory","entries":{"foo":{},"foo-x":{},"qux":{},"zyx":{}}}' ]]-[[ $(nix ls-store --json -R $storePath/foo) = '{"type":"directory","entries":{"bar":{"type":"regular","size":0},"baz":{"type":"regular","size":0},"data":{"type":"regular","size":58}}}' ]]-[[ $(nix ls-store --json -R $storePath/foo/bar) = '{"type":"regular","size":0}' ]]--# Test missing files.-nix ls-store --json -R $storePath/xyzzy 2>&1 | grep 'does not exist in NAR'-nix ls-store $storePath/xyzzy 2>&1 | grep 'does not exist'--# Test failure to dump.-if nix-store --dump $storePath >/dev/full ; then-    echo "dumping to /dev/full should fail"-    exit -1-fi
− data/nix/tests/nix-build.sh
@@ -1,25 +0,0 @@-source common.sh--clearStore--outPath=$(nix-build dependencies.nix -o $TEST_ROOT/result)-test "$(cat $TEST_ROOT/result/foobar)" = FOOBAR--# The result should be retained by a GC.-echo A-target=$(readLink $TEST_ROOT/result)-echo B-echo target is $target-nix-store --gc-test -e $target/foobar--# But now it should be gone.-rm $TEST_ROOT/result-nix-store --gc-if test -e $target/foobar; then false; fi--outPath2=$(nix-build $(nix-instantiate dependencies.nix) --no-out-link)-[[ $outPath = $outPath2 ]]--outPath2=$(nix-build $(nix-instantiate dependencies.nix)!out --no-out-link)-[[ $outPath = $outPath2 ]]
− data/nix/tests/nix-channel.sh
@@ -1,59 +0,0 @@-source common.sh--clearProfiles--rm -f $TEST_HOME/.nix-channels $TEST_HOME/.nix-profile--# Test add/list/remove.-nix-channel --add http://foo/bar xyzzy-nix-channel --list | grep -q http://foo/bar-nix-channel --remove xyzzy--[ -e $TEST_HOME/.nix-channels ]-[ "$(cat $TEST_HOME/.nix-channels)" = '' ]--# Create a channel.-rm -rf $TEST_ROOT/foo-mkdir -p $TEST_ROOT/foo-nix copy --to file://$TEST_ROOT/foo?compression="bzip2" $(nix-store -r $(nix-instantiate dependencies.nix))-rm -rf $TEST_ROOT/nixexprs-mkdir -p $TEST_ROOT/nixexprs-cp config.nix dependencies.nix dependencies.builder*.sh $TEST_ROOT/nixexprs/-ln -s dependencies.nix $TEST_ROOT/nixexprs/default.nix-(cd $TEST_ROOT && tar cvf - nixexprs) | bzip2 > $TEST_ROOT/foo/nixexprs.tar.bz2--# Test the update action.-nix-channel --add file://$TEST_ROOT/foo-nix-channel --update--# Do a query.-nix-env -qa \* --meta --xml --out-path > $TEST_ROOT/meta.xml-if [ "$xmllint" != false ]; then-    $xmllint --noout $TEST_ROOT/meta.xml || fail "malformed XML"-fi-grep -q 'meta.*description.*Random test package' $TEST_ROOT/meta.xml-grep -q 'item.*attrPath="foo".*name="dependencies"' $TEST_ROOT/meta.xml--# Do an install.-nix-env -i dependencies-[ -e $TEST_ROOT/var/nix/profiles/default/foobar ]--clearProfiles-rm -f $TEST_HOME/.nix-channels--# Test updating from a tarball-nix-channel --add file://$TEST_ROOT/foo/nixexprs.tar.bz2 foo-nix-channel --update--# Do a query.-nix-env -qa \* --meta --xml --out-path > $TEST_ROOT/meta.xml-if [ "$xmllint" != false ]; then-    $xmllint --noout $TEST_ROOT/meta.xml || fail "malformed XML"-fi-grep -q 'meta.*description.*Random test package' $TEST_ROOT/meta.xml-grep -q 'item.*attrPath="foo".*name="dependencies"' $TEST_ROOT/meta.xml--# Do an install.-nix-env -i dependencies-[ -e $TEST_ROOT/var/nix/profiles/default/foobar ]-
− data/nix/tests/nix-copy-closure.nix
@@ -1,64 +0,0 @@-# Test ‘nix-copy-closure’.--{ nixpkgs, system, nix }:--with import (nixpkgs + "/nixos/lib/testing.nix") { inherit system; };--makeTest (let pkgA = pkgs.cowsay; pkgB = pkgs.wget; pkgC = pkgs.hello; in {--  nodes =-    { client =-        { config, pkgs, ... }:-        { virtualisation.writableStore = true;-          virtualisation.pathsInNixDB = [ pkgA ];-          nix.package = nix;-          nix.binaryCaches = [ ];-        };--      server =-        { config, pkgs, ... }:-        { services.openssh.enable = true;-          virtualisation.writableStore = true;-          virtualisation.pathsInNixDB = [ pkgB pkgC ];-          nix.package = nix;-        };-    };--  testScript = { nodes }:-    ''-      startAll;--      # Create an SSH key on the client.-      my $key = `${pkgs.openssh}/bin/ssh-keygen -t ed25519 -f key -N ""`;-      $client->succeed("mkdir -m 700 /root/.ssh");-      $client->copyFileFromHost("key", "/root/.ssh/id_ed25519");-      $client->succeed("chmod 600 /root/.ssh/id_ed25519");--      # Install the SSH key on the server.-      $server->succeed("mkdir -m 700 /root/.ssh");-      $server->copyFileFromHost("key.pub", "/root/.ssh/authorized_keys");-      $server->waitForUnit("sshd");-      $client->waitForUnit("network.target");-      $client->succeed("ssh -o StrictHostKeyChecking=no " . $server->name() . " 'echo hello world'");--      # Copy the closure of package A from the client to the server.-      $server->fail("nix-store --check-validity ${pkgA}");-      $client->succeed("nix-copy-closure --to server --gzip ${pkgA} >&2");-      $server->succeed("nix-store --check-validity ${pkgA}");--      # Copy the closure of package B from the server to the client.-      $client->fail("nix-store --check-validity ${pkgB}");-      $client->succeed("nix-copy-closure --from server --gzip ${pkgB} >&2");-      $client->succeed("nix-store --check-validity ${pkgB}");--      # Copy the closure of package C via the SSH substituter.-      $client->fail("nix-store -r ${pkgC}");-      # FIXME-      #$client->succeed(-      #  "nix-store --option use-ssh-substituter true"-      #  . " --option ssh-substituter-hosts root\@server"-      #  . " -r ${pkgC} >&2");-      #$client->succeed("nix-store --check-validity ${pkgC}");-    '';--})
− data/nix/tests/nix-profile.sh
@@ -1,14 +0,0 @@-source common.sh--sed -e "s|@localstatedir@|$TEST_ROOT/profile-var|g" -e "s|@coreutils@|$coreutils|g" < ../scripts/nix-profile.sh.in > $TEST_ROOT/nix-profile.sh--user=$(whoami)-rm -rf $TEST_HOME $TEST_ROOT/profile-var-mkdir -p $TEST_HOME-USER=$user $SHELL -e -c ". $TEST_ROOT/nix-profile.sh; set"-USER=$user $SHELL -e -c ". $TEST_ROOT/nix-profile.sh" # test idempotency--[ -L $TEST_HOME/.nix-profile ]-[ -e $TEST_HOME/.nix-channels ]-[ -e $TEST_ROOT/profile-var/nix/gcroots/per-user/$user ]-[ -e $TEST_ROOT/profile-var/nix/profiles/per-user/$user ]
− data/nix/tests/nix-shell.sh
@@ -1,50 +0,0 @@-source common.sh--clearStore--# Test nix-shell -A-export IMPURE_VAR=foo-export NIX_BUILD_SHELL=$SHELL-output=$(nix-shell --pure shell.nix -A shellDrv --run \-    'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"')--[ "$output" = " - foo - bar" ]--# Test nix-shell on a .drv-[[ $(nix-shell --pure $(nix-instantiate shell.nix -A shellDrv) --run \-    'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"') = " - foo - bar" ]]--[[ $(nix-shell --pure $(nix-instantiate shell.nix -A shellDrv) --run \-    'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"') = " - foo - bar" ]]--# Test nix-shell on a .drv symlink--# Legacy: absolute path and .drv extension required-nix-instantiate shell.nix -A shellDrv --indirect --add-root shell.drv-[[ $(nix-shell --pure $PWD/shell.drv --run \-    'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"') = " - foo - bar" ]]--# New behaviour: just needs to resolve to a derivation in the store-nix-instantiate shell.nix -A shellDrv --indirect --add-root shell-[[ $(nix-shell --pure shell --run \-    'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"') = " - foo - bar" ]]--# Test nix-shell -p-output=$(NIX_PATH=nixpkgs=shell.nix nix-shell --pure -p foo bar --run 'echo "$(foo) $(bar)"')-[ "$output" = "foo bar" ]--# Test nix-shell shebang mode-sed -e "s|@ENV_PROG@|$(type -p env)|" shell.shebang.sh > $TEST_ROOT/shell.shebang.sh-chmod a+rx $TEST_ROOT/shell.shebang.sh--output=$($TEST_ROOT/shell.shebang.sh abc def)-[ "$output" = "foo bar abc def" ]--# Test nix-shell shebang mode for ruby-# This uses a fake interpreter that returns the arguments passed-# This, in turn, verifies the `rc` script is valid and the `load()` script (given using `-e`) is as expected.-sed -e "s|@SHELL_PROG@|$(type -p nix-shell)|" shell.shebang.rb > $TEST_ROOT/shell.shebang.rb-chmod a+rx $TEST_ROOT/shell.shebang.rb--output=$($TEST_ROOT/shell.shebang.rb abc ruby)-[ "$output" = '-e load("'"$TEST_ROOT"'/shell.shebang.rb") -- abc ruby' ]
− data/nix/tests/optimise-store.sh
@@ -1,43 +0,0 @@-source common.sh--clearStore--outPath1=$(echo 'with import ./config.nix; mkDerivation { name = "foo1"; builder = builtins.toFile "builder" "mkdir $out; echo hello > $out/foo"; }' | nix-build - --no-out-link --auto-optimise-store)-outPath2=$(echo 'with import ./config.nix; mkDerivation { name = "foo2"; builder = builtins.toFile "builder" "mkdir $out; echo hello > $out/foo"; }' | nix-build - --no-out-link --auto-optimise-store)--inode1="$(stat --format=%i $outPath1/foo)"-inode2="$(stat --format=%i $outPath2/foo)"-if [ "$inode1" != "$inode2" ]; then-    echo "inodes do not match"-    exit 1-fi--nlink="$(stat --format=%h $outPath1/foo)"-if [ "$nlink" != 3 ]; then-    echo "link count incorrect"-    exit 1-fi--outPath3=$(echo 'with import ./config.nix; mkDerivation { name = "foo3"; builder = builtins.toFile "builder" "mkdir $out; echo hello > $out/foo"; }' | nix-build - --no-out-link)--inode3="$(stat --format=%i $outPath3/foo)"-if [ "$inode1" = "$inode3" ]; then-    echo "inodes match unexpectedly"-    exit 1-fi--nix-store --optimise--inode1="$(stat --format=%i $outPath1/foo)"-inode3="$(stat --format=%i $outPath3/foo)"-if [ "$inode1" != "$inode3" ]; then-    echo "inodes do not match"-    exit 1-fi--nix-store --gc--if [ -n "$(ls $NIX_STORE_DIR/.links)" ]; then-    echo ".links directory not empty after GC"-    exit 1-fi
− data/nix/tests/parallel.builder.sh
@@ -1,29 +0,0 @@-echo "DOING $text"---# increase counter-while ! ln -s x $shared.lock 2> /dev/null; do-    sleep 1-done-test -f $shared.cur || echo 0 > $shared.cur-test -f $shared.max || echo 0 > $shared.max-new=$(($(cat $shared.cur) + 1))-if test $new -gt $(cat $shared.max); then-    echo $new > $shared.max-fi-echo $new > $shared.cur-rm $shared.lock---echo -n $(cat $inputs)$text > $out--sleep $sleepTime---# decrease counter-while ! ln -s x $shared.lock 2> /dev/null; do-    sleep 1-done-test -f $shared.cur || echo 0 > $shared.cur-echo $(($(cat $shared.cur) - 1)) > $shared.cur-rm $shared.lock
− data/nix/tests/parallel.nix
@@ -1,19 +0,0 @@-{sleepTime ? 3}:--with import ./config.nix;--let--  mkDrv = text: inputs: mkDerivation {-    name = "parallel";-    builder = ./parallel.builder.sh;-    inherit text inputs shared sleepTime;-  };--  a = mkDrv "a" [];-  b = mkDrv "b" [a];-  c = mkDrv "c" [a];-  d = mkDrv "d" [a];-  e = mkDrv "e" [b c d];--in e
− data/nix/tests/parallel.sh
@@ -1,56 +0,0 @@-source common.sh---# First, test that -jN performs builds in parallel.-echo "testing nix-build -j..."--clearStore--rm -f $_NIX_TEST_SHARED.cur $_NIX_TEST_SHARED.max--outPath=$(nix-build -j10000 parallel.nix --no-out-link)--echo "output path is $outPath"--text=$(cat "$outPath")-if test "$text" != "abacade"; then exit 1; fi--if test "$(cat $_NIX_TEST_SHARED.cur)" != 0; then fail "wrong current process count"; fi-if test "$(cat $_NIX_TEST_SHARED.max)" != 3; then fail "not enough parallelism"; fi---# Second, test that parallel invocations of nix-build perform builds-# in parallel, and don't block waiting on locks held by the others.-echo "testing multiple nix-build -j1..."--clearStore--rm -f $_NIX_TEST_SHARED.cur $_NIX_TEST_SHARED.max--drvPath=$(nix-instantiate parallel.nix --argstr sleepTime 15)--cmd="nix-store -j1 -r $drvPath"--$cmd &-pid1=$!-echo "pid 1 is $pid1"--$cmd &-pid2=$!-echo "pid 2 is $pid2"--$cmd &-pid3=$!-echo "pid 3 is $pid3"--$cmd &-pid4=$!-echo "pid 4 is $pid4"--wait $pid1 || fail "instance 1 failed: $?"-wait $pid2 || fail "instance 2 failed: $?"-wait $pid3 || fail "instance 3 failed: $?"-wait $pid4 || fail "instance 4 failed: $?"--if test "$(cat $_NIX_TEST_SHARED.cur)" != 0; then fail "wrong current process count"; fi-if test "$(cat $_NIX_TEST_SHARED.max)" != 3; then fail "not enough parallelism"; fi
− data/nix/tests/pass-as-file.sh
@@ -1,17 +0,0 @@-source common.sh--clearStore--outPath=$(nix-build --no-out-link -E "-with import ./config.nix;--mkDerivation {-  name = \"pass-as-file\";-  passAsFile = [ \"foo\" ];-  foo = [ \"xyzzy\" ];-  builder = builtins.toFile \"builder.sh\" ''-    [ \"\$(cat \$fooPath)\" = xyzzy ]-    touch \$out-  '';-}-")
− data/nix/tests/placeholders.sh
@@ -1,22 +0,0 @@-source common.sh--clearStore--nix-build --no-out-link -E '-  with import ./config.nix;--  mkDerivation {-    name = "placeholders";-    outputs = [ "out" "bin" "dev" ];-    buildCommand = "-      echo foo1 > $out-      echo foo2 > $bin-      echo foo3 > $dev-      [[ $(cat ${placeholder "out"}) = foo1 ]]-      [[ $(cat ${placeholder "bin"}) = foo2 ]]-      [[ $(cat ${placeholder "dev"}) = foo3 ]]-    ";-  }-'--echo XYZZY
− data/nix/tests/plugins.sh
@@ -1,7 +0,0 @@-source common.sh--set -o pipefail--res=$(nix eval '(builtins.anotherNull)' --option setting-set true --option plugin-files $PWD/plugins/libplugintest*)--[ "$res"x = "nullx" ]
− data/nix/tests/plugins/local.mk
@@ -1,9 +0,0 @@-libraries += libplugintest--libplugintest_DIR := $(d)--libplugintest_SOURCES := $(d)/plugintest.cc--libplugintest_ALLOW_UNDEFINED := 1--libplugintest_EXCLUDE_FROM_LIBRARY_LIST := 1
− data/nix/tests/plugins/plugintest.cc
@@ -1,19 +0,0 @@-#include "globals.hh"-#include "primops.hh"--using namespace nix;--static BaseSetting<bool> settingSet{false, "setting-set",-        "Whether the plugin-defined setting was set"};--static RegisterSetting rs(&settingSet);--static void prim_anotherNull (EvalState & state, const Pos & pos, Value ** args, Value & v)-{-    if (settingSet)-        mkNull(v);-    else-        mkBool(v, false);-}--static RegisterPrimOp rp("anotherNull", 0, prim_anotherNull);
− data/nix/tests/pure-eval.nix
@@ -1,3 +0,0 @@-{-  x = 123;-}
− data/nix/tests/pure-eval.sh
@@ -1,18 +0,0 @@-source common.sh--clearStore--nix eval --pure-eval '(assert 1 + 2 == 3; true)'--[[ $(nix eval '(builtins.readFile ./pure-eval.sh)') =~ clearStore ]]--(! nix eval --pure-eval '(builtins.readFile ./pure-eval.sh)')--(! nix eval --pure-eval '(builtins.currentTime)')-(! nix eval --pure-eval '(builtins.currentSystem)')--(! nix-instantiate --pure-eval ./simple.nix)--[[ $(nix eval "((import (builtins.fetchurl { url = file://$(pwd)/pure-eval.nix; })).x)") == 123 ]]-(! nix eval --pure-eval "((import (builtins.fetchurl { url = file://$(pwd)/pure-eval.nix; })).x)")-nix eval --pure-eval "((import (builtins.fetchurl { url = file://$(pwd)/pure-eval.nix; sha256 = \"$(nix hash-file pure-eval.nix --type sha256)\"; })).x)"
− data/nix/tests/referrers.sh
@@ -1,36 +0,0 @@-source common.sh--clearStore--max=500--reference=$NIX_STORE_DIR/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-touch $reference-(echo $reference && echo && echo 0) | nix-store --register-validity --echo "making registration..."--set +x-for ((n = 0; n < $max; n++)); do-    storePath=$NIX_STORE_DIR/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-$n-    echo -n > $storePath-    ref2=$NIX_STORE_DIR/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-$((n+1))-    if test $((n+1)) = $max; then-        ref2=$reference-    fi-    echo $storePath; echo; echo 2; echo $reference; echo $ref2-done > $TEST_ROOT/reg_info-set -x--echo "registering..."--nix-store --register-validity < $TEST_ROOT/reg_info--echo "collecting garbage..."-ln -sfn $reference "$NIX_STATE_DIR"/gcroots/ref-nix-store --gc--if [ -n "$(type -p sqlite3)" -a "$(sqlite3 $NIX_STATE_DIR/db/db.sqlite 'select count(*) from Refs')" -ne 0 ]; then-    echo "referrers not cleaned up"-    exit 1-fi
− data/nix/tests/remote-builds.nix
@@ -1,108 +0,0 @@-# Test Nix's remote build feature.--{ nixpkgs, system, nix }:--with import (nixpkgs + "/nixos/lib/testing.nix") { inherit system; };--makeTest (--let--  # The configuration of the build slaves.-  slave =-    { config, pkgs, ... }:-    { services.openssh.enable = true;-      virtualisation.writableStore = true;-      nix.package = nix;-      nix.useSandbox = true;-    };--  # Trivial Nix expression to build remotely.-  expr = config: nr: pkgs.writeText "expr.nix"-    ''-      let utils = builtins.storePath ${config.system.build.extraUtils}; in-      derivation {-        name = "hello-${toString nr}";-        system = "i686-linux";-        PATH = "''${utils}/bin";-        builder = "''${utils}/bin/sh";-        args = [ "-c" "if [ ${toString nr} = 5 ]; then echo FAIL; exit 1; fi; echo Hello; mkdir $out $foo; cat /proc/sys/kernel/hostname > $out/host; ln -s $out $foo/bar; sleep 10" ];-        outputs = [ "out" "foo" ];-      }-    '';--in--{--  nodes =-    { slave1 = slave;-      slave2 = slave;--      client =-        { config, pkgs, ... }:-        { nix.maxJobs = 0; # force remote building-          nix.distributedBuilds = true;-          nix.buildMachines =-            [ { hostName = "slave1";-                sshUser = "root";-                sshKey = "/root/.ssh/id_ed25519";-                system = "i686-linux";-                maxJobs = 1;-              }-              { hostName = "slave2";-                sshUser = "root";-                sshKey = "/root/.ssh/id_ed25519";-                system = "i686-linux";-                maxJobs = 1;-              }-            ];-          virtualisation.writableStore = true;-          virtualisation.pathsInNixDB = [ config.system.build.extraUtils ];-          nix.package = nix;-          nix.binaryCaches = [ ];-          programs.ssh.extraConfig = "ConnectTimeout 30";-        };-    };--  testScript = { nodes }:-    ''-      startAll;--      # Create an SSH key on the client.-      my $key = `${pkgs.openssh}/bin/ssh-keygen -t ed25519 -f key -N ""`;-      $client->succeed("mkdir -p -m 700 /root/.ssh");-      $client->copyFileFromHost("key", "/root/.ssh/id_ed25519");-      $client->succeed("chmod 600 /root/.ssh/id_ed25519");--      # Install the SSH key on the slaves.-      $client->waitForUnit("network.target");-      foreach my $slave ($slave1, $slave2) {-          $slave->succeed("mkdir -p -m 700 /root/.ssh");-          $slave->copyFileFromHost("key.pub", "/root/.ssh/authorized_keys");-          $slave->waitForUnit("sshd");-          $client->succeed("ssh -o StrictHostKeyChecking=no " . $slave->name() . " 'echo hello world'");-      }--      # Perform a build and check that it was performed on the slave.-      my $out = $client->succeed(-        "nix-build ${expr nodes.client.config 1} 2> build-output",-        "grep -q Hello build-output"-      );-      $slave1->succeed("test -e $out");--      # And a parallel build.-      my ($out1, $out2) = split /\s/,-          $client->succeed('nix-store -r $(nix-instantiate ${expr nodes.client.config 2})\!out $(nix-instantiate ${expr nodes.client.config 3})\!out');-      $slave1->succeed("test -e $out1 -o -e $out2");-      $slave2->succeed("test -e $out1 -o -e $out2");--      # And a failing build.-      $client->fail("nix-build ${expr nodes.client.config 5}");--      # Test whether the build hook automatically skips unavailable slaves.-      $slave1->block;-      $client->succeed("nix-build ${expr nodes.client.config 4}");-    '';--})
− data/nix/tests/remote-store.sh
@@ -1,15 +0,0 @@-source common.sh--clearStore--startDaemon--storeCleared=1 $SHELL ./user-envs.sh--nix-store --dump-db > $TEST_ROOT/d1-NIX_REMOTE= nix-store --dump-db > $TEST_ROOT/d2-cmp $TEST_ROOT/d1 $TEST_ROOT/d2--nix-store --gc --max-freed 1K--killDaemon
− data/nix/tests/repair.sh
@@ -1,77 +0,0 @@-source common.sh--clearStore--path=$(nix-build dependencies.nix -o $TEST_ROOT/result)-path2=$(nix-store -qR $path | grep input-2)--nix-store --verify --check-contents -v--hash=$(nix-hash $path2)--# Corrupt a path and check whether nix-build --repair can fix it.-chmod u+w $path2-touch $path2/bad--if nix-store --verify --check-contents -v; then-    echo "nix-store --verify succeeded unexpectedly" >&2-    exit 1-fi--# The path can be repaired by rebuilding the derivation.-nix-store --verify --check-contents --repair--nix-store --verify-path $path2--# Re-corrupt and delete the deriver. Now --verify --repair should-# not work.-chmod u+w $path2-touch $path2/bad--nix-store --delete $(nix-store -qd $path2)--if nix-store --verify --check-contents --repair; then-    echo "nix-store --verify --repair succeeded unexpectedly" >&2-    exit 1-fi--nix-build dependencies.nix -o $TEST_ROOT/result --repair--if [ "$(nix-hash $path2)" != "$hash" -o -e $path2/bad ]; then-    echo "path not repaired properly" >&2-    exit 1-fi--# Corrupt a path that has a substitute and check whether nix-store-# --verify can fix it.-clearCache--nix copy --to file://$cacheDir $path--chmod u+w $path2-rm -rf $path2--nix-store --verify --check-contents --repair --substituters "file://$cacheDir" --no-require-sigs--if [ "$(nix-hash $path2)" != "$hash" -o -e $path2/bad ]; then-    echo "path not repaired properly" >&2-    exit 1-fi--# Check --verify-path and --repair-path.-nix-store --verify-path $path2--chmod u+w $path2-rm -rf $path2--if nix-store --verify-path $path2; then-    echo "nix-store --verify-path succeeded unexpectedly" >&2-    exit 1-fi--nix-store --repair-path $path2 --substituters "file://$cacheDir" --no-require-sigs--if [ "$(nix-hash $path2)" != "$hash" -o -e $path2/bad ]; then-    echo "path not repaired properly" >&2-    exit 1-fi
− data/nix/tests/restricted.nix
@@ -1,1 +0,0 @@-1 + 2
− data/nix/tests/restricted.sh
@@ -1,40 +0,0 @@-source common.sh--clearStore--nix-instantiate --restrict-eval --eval -E '1 + 2'-(! nix-instantiate --restrict-eval ./restricted.nix)-(! nix-instantiate --eval --restrict-eval <(echo '1 + 2'))-nix-instantiate --restrict-eval ./simple.nix -I src=.-nix-instantiate --restrict-eval ./simple.nix -I src1=simple.nix -I src2=config.nix -I src3=./simple.builder.sh--(! nix-instantiate --restrict-eval --eval -E 'builtins.readFile ./simple.nix')-nix-instantiate --restrict-eval --eval -E 'builtins.readFile ./simple.nix' -I src=..--(! nix-instantiate --restrict-eval --eval -E 'builtins.readDir ../src/nix-channel')-nix-instantiate --restrict-eval --eval -E 'builtins.readDir ../src/nix-channel' -I src=../src--(! nix-instantiate --restrict-eval --eval -E 'let __nixPath = [ { prefix = "foo"; path = ./.; } ]; in <foo>')-nix-instantiate --restrict-eval --eval -E 'let __nixPath = [ { prefix = "foo"; path = ./.; } ]; in <foo>' -I src=.--p=$(nix eval --raw "(builtins.fetchurl file://$(pwd)/restricted.sh)" --restrict-eval --allowed-uris "file://$(pwd)")-cmp $p restricted.sh--(! nix eval --raw "(builtins.fetchurl file://$(pwd)/restricted.sh)" --restrict-eval)--(! nix eval --raw "(builtins.fetchurl file://$(pwd)/restricted.sh)" --restrict-eval --allowed-uris "file://$(pwd)/restricted.sh/")--nix eval --raw "(builtins.fetchurl file://$(pwd)/restricted.sh)" --restrict-eval --allowed-uris "file://$(pwd)/restricted.sh"--(! nix eval --raw "(builtins.fetchurl https://github.com/NixOS/patchelf/archive/master.tar.gz)" --restrict-eval)-(! nix eval --raw "(builtins.fetchTarball https://github.com/NixOS/patchelf/archive/master.tar.gz)" --restrict-eval)-(! nix eval --raw "(fetchGit git://github.com/NixOS/patchelf.git)" --restrict-eval)--ln -sfn $(pwd)/restricted.nix $TEST_ROOT/restricted.nix-[[ $(nix-instantiate --eval $TEST_ROOT/restricted.nix) == 3 ]]-(! nix-instantiate --eval --restrict-eval $TEST_ROOT/restricted.nix)-(! nix-instantiate --eval --restrict-eval $TEST_ROOT/restricted.nix -I $TEST_ROOT)-(! nix-instantiate --eval --restrict-eval $TEST_ROOT/restricted.nix -I .)-nix-instantiate --eval --restrict-eval $TEST_ROOT/restricted.nix -I $TEST_ROOT -I .--[[ $(nix eval --raw --restrict-eval -I . '(builtins.readFile "${import ./simple.nix}/hello")') == 'Hello World!' ]]
− data/nix/tests/run.nix
@@ -1,17 +0,0 @@-with import ./config.nix;--{-  hello = mkDerivation {-    name = "hello";-    buildCommand =-      ''-        mkdir -p $out/bin-        cat > $out/bin/hello <<EOF-        #! ${shell}-        who=\$1-        echo "Hello \''${who:-World} from $out/bin/hello"-        EOF-        chmod +x $out/bin/hello-      '';-  };-}
− data/nix/tests/run.sh
@@ -1,28 +0,0 @@-source common.sh--clearStore-clearCache--nix run -f run.nix hello -c hello | grep 'Hello World'-nix run -f run.nix hello -c hello NixOS | grep 'Hello NixOS'--if ! canUseSandbox; then exit; fi--chmod -R u+w $TEST_ROOT/store0 || true-rm -rf $TEST_ROOT/store0--clearStore--path=$(nix eval --raw -f run.nix hello)--# Note: we need the sandbox paths to ensure that the shell is-# visible in the sandbox.-nix run --sandbox-build-dir /build-tmp \-    --sandbox-paths '/nix? /bin? /lib? /lib64? /usr?' \-    --store $TEST_ROOT/store0 -f run.nix hello -c hello | grep 'Hello World'--path2=$(nix run --sandbox-paths '/nix? /bin? /lib? /lib64? /usr?' --store $TEST_ROOT/store0 -f run.nix hello -c $SHELL -c 'type -p hello')--[[ $path/bin/hello = $path2 ]]--[[ -e $TEST_ROOT/store0/nix/store/$(basename $path)/bin/hello ]]
− data/nix/tests/search.nix
@@ -1,25 +0,0 @@-with import ./config.nix;--{-  hello = mkDerivation rec {-    name = "hello-${version}";-    version = "0.1";-    buildCommand = "touch $out";-    meta.description = "Empty file";-  };-  foo = mkDerivation rec {-    name = "foo-5";-    buildCommand = ''-      mkdir -p $out-      echo ${name} > $out/${name}-    '';-  };-  bar = mkDerivation rec {-    name = "bar-3";-    buildCommand = ''-      echo "Does not build successfully"-      exit 1-    '';-    meta.description = "broken bar";-  };-}
− data/nix/tests/search.sh
@@ -1,43 +0,0 @@-source common.sh--clearStore-clearCache--# No packages-(( $(NIX_PATH= nix search -u|wc -l) == 0 ))--# Haven't updated cache, still nothing-(( $(nix search -f search.nix hello|wc -l) == 0 ))-(( $(nix search -f search.nix |wc -l) == 0 ))--# Update cache, search should work-(( $(nix search -f search.nix -u hello|wc -l) > 0 ))--# Use cache-(( $(nix search -f search.nix foo|wc -l) > 0 ))-(( $(nix search foo|wc -l) > 0 ))--# Test --no-cache works-# No results from cache-(( $(nix search --no-cache foo |wc -l) == 0 ))-# Does find results from file pointed at-(( $(nix search -f search.nix --no-cache foo |wc -l) > 0 ))--# Check descriptions are searched-(( $(nix search broken | wc -l) > 0 ))--# Check search that matches nothing-(( $(nix search nosuchpackageexists | wc -l) == 0 ))--# Search for multiple arguments-(( $(nix search hello empty | wc -l) == 5 ))--# Multiple arguments will not exist-(( $(nix search hello broken | wc -l) == 0 ))--## Search expressions--# Check that empty search string matches all-nix search|grep -q foo-nix search|grep -q bar-nix search|grep -q hello
− data/nix/tests/secure-drv-outputs.nix
@@ -1,23 +0,0 @@-with import ./config.nix;--{--  good = mkDerivation {-    name = "good";-    builder = builtins.toFile "builder"-      ''-        mkdir $out-        echo > $out/good-      '';-  };--  bad = mkDerivation {-    name = "good";-    builder = builtins.toFile "builder"-      ''-        mkdir $out-        echo > $out/bad-      '';-  };--}
− data/nix/tests/secure-drv-outputs.sh
@@ -1,36 +0,0 @@-# Test that users cannot register specially-crafted derivations that-# produce output paths belonging to other derivations.  This could be-# used to inject malware into the store.--source common.sh--clearStore--startDaemon--# Determine the output path of the "good" derivation.-goodOut=$(nix-store -q $(nix-instantiate ./secure-drv-outputs.nix -A good))--# Instantiate the "bad" derivation.-badDrv=$(nix-instantiate ./secure-drv-outputs.nix -A bad)-badOut=$(nix-store -q $badDrv)--# Rewrite the bad derivation to produce the output path of the good-# derivation.-rm -f $TEST_ROOT/bad.drv-sed -e "s|$badOut|$goodOut|g" < $badDrv > $TEST_ROOT/bad.drv--# Add the manipulated derivation to the store and build it.  This-# should fail.-if badDrv2=$(nix-store --add $TEST_ROOT/bad.drv); then-    nix-store -r "$badDrv2"-fi--# Now build the good derivation.-goodOut2=$(nix-build ./secure-drv-outputs.nix -A good --no-out-link)-test "$goodOut" = "$goodOut2"--if ! test -e "$goodOut"/good; then-    echo "Bad derivation stole the output path of the good derivation!"-    exit 1-fi
− data/nix/tests/setuid.nix
@@ -1,108 +0,0 @@-# Verify that Linux builds cannot create setuid or setgid binaries.--{ nixpkgs, system, nix }:--with import (nixpkgs + "/nixos/lib/testing.nix") { inherit system; };--makeTest {--  machine =-    { config, lib, pkgs, ... }:-    { virtualisation.writableStore = true;-      nix.package = nix;-      nix.binaryCaches = [ ];-      nix.nixPath = [ "nixpkgs=${lib.cleanSource pkgs.path}" ];-      virtualisation.pathsInNixDB = [ pkgs.stdenv pkgs.pkgsi686Linux.stdenv ];-    };--  testScript = { nodes }:-    ''-      startAll;--      # Copying to /tmp should succeed.-      $machine->succeed('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" {} "-        mkdir -p $out-        cp ${pkgs.coreutils}/bin/id /tmp/id-      ")\' ');--      $machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]');--      $machine->succeed("rm /tmp/id");--      # Creating a setuid binary should fail.-      $machine->fail('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" {} "-        mkdir -p $out-        cp ${pkgs.coreutils}/bin/id /tmp/id-        chmod 4755 /tmp/id-      ")\' ');--      $machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]');--      $machine->succeed("rm /tmp/id");--      # Creating a setgid binary should fail.-      $machine->fail('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" {} "-        mkdir -p $out-        cp ${pkgs.coreutils}/bin/id /tmp/id-        chmod 2755 /tmp/id-      ")\' ');--      $machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]');--      $machine->succeed("rm /tmp/id");--      # The checks should also work on 32-bit binaries.-      $machine->fail('nix-build --no-sandbox -E \'(with import <nixpkgs> { system = "i686-linux"; }; runCommand "foo" {} "-        mkdir -p $out-        cp ${pkgs.coreutils}/bin/id /tmp/id-        chmod 2755 /tmp/id-      ")\' ');--      $machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]');--      $machine->succeed("rm /tmp/id");--      # The tests above use fchmodat(). Test chmod() as well.-      $machine->succeed('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "-        mkdir -p $out-        cp ${pkgs.coreutils}/bin/id /tmp/id-        perl -e \"chmod 0666, qw(/tmp/id) or die\"-      ")\' ');--      $machine->succeed('[[ $(stat -c %a /tmp/id) = 666 ]]');--      $machine->succeed("rm /tmp/id");--      $machine->fail('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "-        mkdir -p $out-        cp ${pkgs.coreutils}/bin/id /tmp/id-        perl -e \"chmod 04755, qw(/tmp/id) or die\"-      ")\' ');--      $machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]');--      $machine->succeed("rm /tmp/id");--      # And test fchmod().-      $machine->succeed('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "-        mkdir -p $out-        cp ${pkgs.coreutils}/bin/id /tmp/id-        perl -e \"my \\\$x; open \\\$x, qw(/tmp/id); chmod 01750, \\\$x or die\"-      ")\' ');--      $machine->succeed('[[ $(stat -c %a /tmp/id) = 1750 ]]');--      $machine->succeed("rm /tmp/id");--      $machine->fail('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "-        mkdir -p $out-        cp ${pkgs.coreutils}/bin/id /tmp/id-        perl -e \"my \\\$x; open \\\$x, qw(/tmp/id); chmod 04777, \\\$x or die\"-      ")\' ');--      $machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]');--      $machine->succeed("rm /tmp/id");-    '';--}
− data/nix/tests/shell.nix
@@ -1,56 +0,0 @@-{ }:--with import ./config.nix;--let pkgs = rec {-  setupSh = builtins.toFile "setup" ''-    export VAR_FROM_STDENV_SETUP=foo-    for pkg in $buildInputs; do-      export PATH=$PATH:$pkg/bin-    done-  '';--  stdenv = mkDerivation {-    name = "stdenv";-    buildCommand = ''-      mkdir -p $out-      ln -s ${setupSh} $out/setup-    '';-  };--  shellDrv = mkDerivation {-    name = "shellDrv";-    builder = "/does/not/exist";-    VAR_FROM_NIX = "bar";-    inherit stdenv;-  };--  # Used by nix-shell -p-  runCommand = name: args: buildCommand: mkDerivation (args // {-    inherit name buildCommand stdenv;-  });--  foo = runCommand "foo" {} ''-    mkdir -p $out/bin-    echo 'echo foo' > $out/bin/foo-    chmod a+rx $out/bin/foo-    ln -s ${shell} $out/bin/bash-  '';--  bar = runCommand "bar" {} ''-    mkdir -p $out/bin-    echo 'echo bar' > $out/bin/bar-    chmod a+rx $out/bin/bar-  '';--  bash = shell;--  # ruby "interpreter" that outputs "$@"-  ruby = runCommand "ruby" {} ''-    mkdir -p $out/bin-    echo 'printf -- "$*"' > $out/bin/ruby-    chmod a+rx $out/bin/ruby-  '';--  inherit pkgs;-}; in pkgs
− data/nix/tests/shell.shebang.rb
@@ -1,7 +0,0 @@-#! @SHELL_PROG@-#! ruby-#! nix-shell -I nixpkgs=shell.nix --no-substitute-#! nix-shell --pure -p ruby -i ruby--# Contents doesn't matter.-abort("This shouldn't be executed.")
− data/nix/tests/shell.shebang.sh
@@ -1,4 +0,0 @@-#! @ENV_PROG@ nix-shell-#! nix-shell -I nixpkgs=shell.nix --no-substitute-#! nix-shell --pure -i bash -p foo bar-echo "$(foo) $(bar) $@"
− data/nix/tests/signing.sh
@@ -1,101 +0,0 @@-source common.sh--clearStore-clearCache--nix-store --generate-binary-cache-key cache1.example.org $TEST_ROOT/sk1 $TEST_ROOT/pk1-pk1=$(cat $TEST_ROOT/pk1)-nix-store --generate-binary-cache-key cache2.example.org $TEST_ROOT/sk2 $TEST_ROOT/pk2-pk2=$(cat $TEST_ROOT/pk2)--# Build a path.-outPath=$(nix-build dependencies.nix --no-out-link --secret-key-files "$TEST_ROOT/sk1 $TEST_ROOT/sk2")--# Verify that the path got signed.-info=$(nix path-info --json $outPath)-[[ $info =~ '"ultimate":true' ]]-[[ $info =~ 'cache1.example.org' ]]-[[ $info =~ 'cache2.example.org' ]]--# Test "nix verify".-nix verify -r $outPath--expect 2 nix verify -r $outPath --sigs-needed 1--nix verify -r $outPath --sigs-needed 1 --trusted-public-keys $pk1--expect 2 nix verify -r $outPath --sigs-needed 2 --trusted-public-keys $pk1--nix verify -r $outPath --sigs-needed 2 --trusted-public-keys "$pk1 $pk2"--nix verify --all --sigs-needed 2 --trusted-public-keys "$pk1 $pk2"--# Build something unsigned.-outPath2=$(nix-build simple.nix --no-out-link)--nix verify -r $outPath--# Verify that the path did not get signed but does have the ultimate bit.-info=$(nix path-info --json $outPath2)-[[ $info =~ '"ultimate":true' ]]-(! [[ $info =~ 'signatures' ]])--# Test "nix verify".-nix verify -r $outPath2--expect 2 nix verify -r $outPath2 --sigs-needed 1--expect 2 nix verify -r $outPath2 --sigs-needed 1 --trusted-public-keys $pk1--# Test "nix sign-paths".-nix sign-paths --key-file $TEST_ROOT/sk1 $outPath2--nix verify -r $outPath2 --sigs-needed 1 --trusted-public-keys $pk1--# Build something content-addressed.-outPathCA=$(IMPURE_VAR1=foo IMPURE_VAR2=bar nix-build ./fixed.nix -A good.0 --no-out-link)--[[ $(nix path-info --json $outPathCA) =~ '"ca":"fixed:md5:' ]]--# Content-addressed paths don't need signatures, so they verify-# regardless of --sigs-needed.-nix verify $outPathCA-nix verify $outPathCA --sigs-needed 1000--# Copy to a binary cache.-nix copy --to file://$cacheDir $outPath2--# Verify that signatures got copied.-info=$(nix path-info --store file://$cacheDir --json $outPath2)-(! [[ $info =~ '"ultimate":true' ]])-[[ $info =~ 'cache1.example.org' ]]-(! [[ $info =~ 'cache2.example.org' ]])--# Verify that adding a signature to a path in a binary cache works.-nix sign-paths --store file://$cacheDir --key-file $TEST_ROOT/sk2 $outPath2-info=$(nix path-info --store file://$cacheDir --json $outPath2)-[[ $info =~ 'cache1.example.org' ]]-[[ $info =~ 'cache2.example.org' ]]--# Copying to a diverted store should fail due to a lack of valid signatures.-chmod -R u+w $TEST_ROOT/store0 || true-rm -rf $TEST_ROOT/store0-(! nix copy --to $TEST_ROOT/store0 $outPath)--# But succeed if we supply the public keys.-nix copy --to $TEST_ROOT/store0 $outPath --trusted-public-keys $pk1--expect 2 nix verify --store $TEST_ROOT/store0 -r $outPath--nix verify --store $TEST_ROOT/store0 -r $outPath --trusted-public-keys $pk1-nix verify --store $TEST_ROOT/store0 -r $outPath --sigs-needed 2 --trusted-public-keys "$pk1 $pk2"--# It should also succeed if we disable signature checking.-(! nix copy --to $TEST_ROOT/store0 $outPath2)-nix copy --to $TEST_ROOT/store0?require-sigs=false $outPath2--# But signatures should still get copied.-nix verify --store $TEST_ROOT/store0 -r $outPath2 --trusted-public-keys $pk1--# Content-addressed stuff can be copied without signatures.-nix copy --to $TEST_ROOT/store0 $outPathCA
− data/nix/tests/simple.builder.sh
@@ -1,11 +0,0 @@-echo "PATH=$PATH"--# Verify that the PATH is empty.-if mkdir foo 2> /dev/null; then exit 1; fi--# Set a PATH (!!! impure).-export PATH=$goodPath--mkdir $out--echo "Hello World!" > $out/hello
− data/nix/tests/simple.nix
@@ -1,8 +0,0 @@-with import ./config.nix;--mkDerivation {-  name = "simple";-  builder = ./simple.builder.sh;-  PATH = "";-  goodPath = path;-}
− data/nix/tests/simple.sh
@@ -1,25 +0,0 @@-source common.sh--drvPath=$(nix-instantiate simple.nix)--test "$(nix-store -q --binding system "$drvPath")" = "$system"--echo "derivation is $drvPath"--outPath=$(nix-store -rvv "$drvPath")--echo "output path is $outPath"--text=$(cat "$outPath"/hello)-if test "$text" != "Hello World!"; then exit 1; fi--# Directed delete: $outPath is not reachable from a root, so it should-# be deleteable.-nix-store --delete $outPath-if test -e $outPath/hello; then false; fi--outPath="$(NIX_REMOTE=local?store=/foo\&real=$TEST_ROOT/real-store nix-instantiate --readonly-mode hash-check.nix)"-if test "$outPath" != "/foo/lfy1s6ca46rm5r6w4gg9hc0axiakjcnm-dependencies.drv"; then-    echo "hashDerivationModulo appears broken, got $outPath"-    exit 1-fi
− data/nix/tests/structured-attrs.nix
@@ -1,66 +0,0 @@-with import ./config.nix;--let--  dep = mkDerivation {-    name = "dep";-    buildCommand = ''-      mkdir $out; echo bla > $out/bla-    '';-  };--in--mkDerivation {-  name = "structured";--  __structuredAttrs = true;--  buildCommand = ''-    set -x--    [[ $int = 123456789 ]]-    [[ -z $float ]]-    [[ -n $boolTrue ]]-    [[ -z $boolFalse ]]-    [[ -n ''${hardening[format]} ]]-    [[ -z ''${hardening[fortify]} ]]-    [[ ''${#buildInputs[@]} = 7 ]]-    [[ ''${buildInputs[2]} = c ]]-    [[ -v nothing ]]-    [[ -z $nothing ]]--    mkdir ''${outputs[out]}-    echo bar > $dest--    json=$(cat .attrs.json)-    [[ $json =~ '"narHash":"sha256:1r7yc43zqnzl5b0als5vnyp649gk17i37s7mj00xr8kc47rjcybk"' ]]-    [[ $json =~ '"narSize":288' ]]-    [[ $json =~ '"closureSize":288' ]]-    [[ $json =~ '"references":[]' ]]-  '';--  buildInputs = [ "a" "b" "c" 123 "'" "\"" null ];--  hardening.format = true;-  hardening.fortify = false;--  outer.inner = [ 1 2 3 ];--  int = 123456789;--  float = 123.456;--  boolTrue = true;-  boolFalse = false;--  nothing = null;--  dest = "${placeholder "out"}/foo";--  "foo bar" = "BAD";-  "1foobar" = "BAD";-  "foo$" = "BAD";--  exportReferencesGraph.refs = [ dep ];-}
− data/nix/tests/structured-attrs.sh
@@ -1,7 +0,0 @@-source common.sh--clearStore--outPath=$(nix-build structured-attrs.nix --no-out-link)--[[ $(cat $outPath/foo) = bar ]]
− data/nix/tests/tarball.sh
@@ -1,28 +0,0 @@-source common.sh--clearStore--rm -rf $TEST_HOME--tarroot=$TEST_ROOT/tarball-rm -rf $tarroot-mkdir -p $tarroot-cp dependencies.nix $tarroot/default.nix-cp config.nix dependencies.builder*.sh $tarroot/--tarball=$TEST_ROOT/tarball.tar.xz-(cd $TEST_ROOT && tar c tarball) | xz > $tarball--nix-env -f file://$tarball -qa --out-path | grep -q dependencies--nix-build -o $TEST_ROOT/result file://$tarball--nix-build -o $TEST_ROOT/result '<foo>' -I foo=file://$tarball--nix-build -o $TEST_ROOT/result -E "import (fetchTarball file://$tarball)"--nix-instantiate --eval -E '1 + 2' -I fnord=file://no-such-tarball.tar.xz-nix-instantiate --eval -E 'with <fnord/xyzzy>; 1 + 2' -I fnord=file://no-such-tarball.tar.xz-(! nix-instantiate --eval -E '<fnord/xyzzy> 1' -I fnord=file://no-such-tarball.tar.xz)--nix-instantiate --eval -E '<fnord/config.nix>' -I fnord=file://no-such-tarball.tar.xz -I fnord=.
− data/nix/tests/timeout.nix
@@ -1,31 +0,0 @@-with import ./config.nix;--{--  infiniteLoop = mkDerivation {-    name = "timeout";-    buildCommand = ''-      touch $out-      echo "'timeout' builder entering an infinite loop"-      while true ; do echo -n .; done-    '';-  };--  silent = mkDerivation {-    name = "silent";-    buildCommand = ''-      touch $out-      sleep 60-    '';-  };--  closeLog = mkDerivation {-    name = "silent";-    buildCommand = ''-      touch $out-      exec > /dev/null 2>&1-      sleep 1000000000-    '';-  };--}
− data/nix/tests/timeout.sh
@@ -1,36 +0,0 @@-# Test the `--timeout' option.--source common.sh--failed=0-messages="`nix-build -Q timeout.nix -A infiniteLoop --timeout 2 2>&1 || failed=1`"-if [ $failed -ne 0 ]; then-    echo "error: 'nix-store' succeeded; should have timed out"-    exit 1-fi--if ! echo "$messages" | grep -q "timed out"; then-    echo "error: build may have failed for reasons other than timeout; output:"-    echo "$messages" >&2-    exit 1-fi--if nix-build -Q timeout.nix -A infiniteLoop --max-build-log-size 100; then-    echo "build should have failed"-    exit 1-fi--if nix-build timeout.nix -A silent --max-silent-time 2; then-    echo "build should have failed"-    exit 1-fi--if nix-build timeout.nix -A closeLog; then-    echo "build should have failed"-    exit 1-fi--if nix build -f timeout.nix silent --max-silent-time 2; then-    echo "build should have failed"-    exit 1-fi
− data/nix/tests/user-envs.builder.sh
@@ -1,5 +0,0 @@-mkdir $out-mkdir $out/bin-echo "#! $shell" > $out/bin/$progName-echo "echo $name" >> $out/bin/$progName-chmod +x $out/bin/$progName
− data/nix/tests/user-envs.nix
@@ -1,29 +0,0 @@-# Some dummy arguments...-{ foo ? "foo"-}:--with import ./config.nix;--assert foo == "foo";--let--  makeDrv = name: progName: (mkDerivation {-    inherit name progName system;-    builder = ./user-envs.builder.sh;-  } // {-    meta = {-      description = "A silly test package";-    };-  });--in--  [-    (makeDrv "foo-1.0" "foo")-    (makeDrv "foo-2.0pre1" "foo")-    (makeDrv "bar-0.1" "bar")-    (makeDrv "foo-2.0" "foo")-    (makeDrv "bar-0.1.1" "bar")-    (makeDrv "foo-0.1" "foo" // { meta.priority = 10; })-  ]
− data/nix/tests/user-envs.sh
@@ -1,181 +0,0 @@-source common.sh--if [ -z "$storeCleared" ]; then-    clearStore-fi--clearProfiles--# Query installed: should be empty.-test "$(nix-env -p $profiles/test -q '*' | wc -l)" -eq 0--mkdir -p $TEST_HOME-nix-env --switch-profile $profiles/test--# Query available: should contain several.-test "$(nix-env -f ./user-envs.nix -qa '*' | wc -l)" -eq 6-outPath10=$(nix-env -f ./user-envs.nix -qa --out-path --no-name '*' | grep foo-1.0)-drvPath10=$(nix-env -f ./user-envs.nix -qa --drv-path --no-name '*' | grep foo-1.0)-[ -n "$outPath10" -a -n "$drvPath10" ]--# Query descriptions.-nix-env -f ./user-envs.nix -qa '*' --description | grep -q silly-rm -f $HOME/.nix-defexpr-ln -s $(pwd)/user-envs.nix $HOME/.nix-defexpr-nix-env -qa '*' --description | grep -q silly--# Query the system.-nix-env -qa '*' --system | grep -q $system--# Install "foo-1.0".-nix-env -i foo-1.0--# Query installed: should contain foo-1.0 now (which should be-# executable).-test "$(nix-env -q '*' | wc -l)" -eq 1-nix-env -q '*' | grep -q foo-1.0-test "$($profiles/test/bin/foo)" = "foo-1.0"--# Test nix-env -qc to compare installed against available packages, and vice versa.-nix-env -qc '*' | grep -q '< 2.0'-nix-env -qac '*' | grep -q '> 1.0'--# Test the -b flag to filter out source-only packages.-[ "$(nix-env -qab | wc -l)" -eq 1 ]--# Test the -s flag to get package status.-nix-env -qas | grep -q 'IP-  foo-1.0'-nix-env -qas | grep -q -- '---  bar-0.1'--# Disable foo.-nix-env --set-flag active false foo-(! [ -e "$profiles/test/bin/foo" ])--# Enable foo.-nix-env --set-flag active true foo-[ -e "$profiles/test/bin/foo" ]--# Store the path of foo-1.0.-outPath10_=$(nix-env -q --out-path --no-name '*' | grep foo-1.0)-echo "foo-1.0 = $outPath10"-[ "$outPath10" = "$outPath10_" ]--# Install "foo-2.0pre1": should remove foo-1.0.-nix-env -i foo-2.0pre1--# Query installed: should contain foo-2.0pre1 now.-test "$(nix-env -q '*' | wc -l)" -eq 1-nix-env -q '*' | grep -q foo-2.0pre1-test "$($profiles/test/bin/foo)" = "foo-2.0pre1"--# Upgrade "foo": should install foo-2.0.-NIX_PATH=nixpkgs=./user-envs.nix:$NIX_PATH nix-env -f '<nixpkgs>' -u foo--# Query installed: should contain foo-2.0 now.-test "$(nix-env -q '*' | wc -l)" -eq 1-nix-env -q '*' | grep -q foo-2.0-test "$($profiles/test/bin/foo)" = "foo-2.0"--# Store the path of foo-2.0.-outPath20=$(nix-env -q --out-path --no-name '*' | grep foo-2.0)-test -n "$outPath20"--# Install bar-0.1, uninstall foo.-nix-env -i bar-0.1-nix-env -e foo--# Query installed: should only contain bar-0.1 now.-if nix-env -q '*' | grep -q foo; then false; fi-nix-env -q '*' | grep -q bar--# Rollback: should bring "foo" back.-oldGen="$(nix-store -q --resolve $profiles/test)"-nix-env --rollback-[ "$(nix-store -q --resolve $profiles/test)" != "$oldGen" ]-nix-env -q '*' | grep -q foo-2.0-nix-env -q '*' | grep -q bar--# Rollback again: should remove "bar".-nix-env --rollback-nix-env -q '*' | grep -q foo-2.0-if nix-env -q '*' | grep -q bar; then false; fi--# Count generations.-nix-env --list-generations-test "$(nix-env --list-generations | wc -l)" -eq 7--# Doing the same operation twice results in the same generation, which triggers-# "lazy" behaviour and does not create a new symlink.--nix-env -i foo-nix-env -i foo--# Count generations.-nix-env --list-generations-test "$(nix-env --list-generations | wc -l)" -eq 8--# Switch to a specified generation.-nix-env --switch-generation 7-[ "$(nix-store -q --resolve $profiles/test)" = "$oldGen" ]--# Install foo-1.0, now using its store path.-nix-env -i "$outPath10"-nix-env -q '*' | grep -q foo-1.0-nix-store -qR $profiles/test | grep "$outPath10"-nix-store -q --referrers-closure $profiles/test | grep "$(nix-store -q --resolve $profiles/test)"-[ "$(nix-store -q --deriver "$outPath10")" = $drvPath10 ]--# Uninstall foo-1.0, using a symlink to its store path.-ln -sfn $outPath10/bin/foo $TEST_ROOT/symlink-nix-env -e $TEST_ROOT/symlink-if nix-env -q '*' | grep -q foo; then false; fi-(! nix-store -qR $profiles/test | grep "$outPath10")--# Install foo-1.0, now using a symlink to its store path.-nix-env -i $TEST_ROOT/symlink-nix-env -q '*' | grep -q foo--# Delete all old generations.-nix-env --delete-generations old--# Run the garbage collector.  This should get rid of foo-2.0 but not-# foo-1.0.-nix-collect-garbage-test -e "$outPath10"-(! [ -e "$outPath20" ])--# Uninstall everything-nix-env -e '*'-test "$(nix-env -q '*' | wc -l)" -eq 0--# Installing "foo" should only install the newest foo.-nix-env -i foo-test "$(nix-env -q '*' | grep foo- | wc -l)" -eq 1-nix-env -q '*' | grep -q foo-2.0--# On the other hand, this should install both (and should fail due to-# a collision).-nix-env -e '*'-(! nix-env -i foo-1.0 foo-2.0)--# Installing "*" should install one foo and one bar.-nix-env -e '*'-nix-env -i '*'-test "$(nix-env -q '*' | wc -l)" -eq 2-nix-env -q '*' | grep -q foo-2.0-nix-env -q '*' | grep -q bar-0.1.1--# Test priorities: foo-0.1 has a lower priority than foo-1.0, so it-# should be possible to install both without a collision.  Also test-# ‘--set-flag priority’ to manually override the declared priorities.-nix-env -e '*'-nix-env -i foo-0.1 foo-1.0-[ "$($profiles/test/bin/foo)" = "foo-1.0" ]-nix-env --set-flag priority 1 foo-0.1-[ "$($profiles/test/bin/foo)" = "foo-0.1" ]--# Test nix-env --set.-nix-env --set $outPath10-[ "$(nix-store -q --resolve $profiles/test)" = $outPath10 ]-nix-env --set $drvPath10-[ "$(nix-store -q --resolve $profiles/test)" = $outPath10 ]
− data/nix/version
@@ -1,1 +0,0 @@-2.1
hnix.cabal view
@@ -1,735 +1,565 @@--- This file has been generated from package.yaml by hpack version 0.27.0.------ see: https://github.com/sol/hpack------ hash: ba0f61f8a049f6970ff03fd924cfed6fc1251eceb90547c1be8051226c453632--name:           hnix-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/haskell-nix/hnix#readme-bug-reports:    https://github.com/haskell-nix/hnix/issues-author:         John Wiegley-maintainer:     johnw@newartisans.com-license:        BSD3-license-file:   LICENSE-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/haskell-nix/hnix--flag optimize-  description: Enable all optimization flags-  manual: True-  default: False--flag profiling-  description: Enable profiling-  manual: True-  default: False--flag tracing-  description: Enable full debug tracing-  manual: True-  default: False--library-  exposed-modules:-      Nix-      Nix.Atoms-      Nix.Builtins-      Nix.Cache-      Nix.Context-      Nix.Convert-      Nix.Effects-      Nix.Eval-      Nix.Exec-      Nix.Expr-      Nix.Expr.Shorthands-      Nix.Expr.Types-      Nix.Expr.Types.Annotated-      Nix.Frames-      Nix.Lint-      Nix.Normal-      Nix.Options-      Nix.Parser-      Nix.Pretty-      Nix.Reduce-      Nix.Render-      Nix.Render.Frame-      Nix.Scope-      Nix.Strings-      Nix.TH-      Nix.Thunk-      Nix.Type.Assumption-      Nix.Type.Env-      Nix.Type.Infer-      Nix.Type.Type-      Nix.Utils-      Nix.Value-      Nix.XML-  other-modules:-      Paths_hnix-  hs-source-dirs:-      src-  ghc-options: -Wall-  build-depends:-      aeson-    , ansi-wl-pprint-    , array >=0.4 && <0.6-    , base >=4.9 && <5-    , binary-    , bytestring-    , containers-    , data-fix-    , deepseq >=1.4.2 && <1.5-    , deriving-compat >=0.3 && <0.6-    , directory-    , exceptions-    , filepath-    , hashing-    , http-client-    , http-client-tls-    , http-types-    , interpolate-    , lens-family-th-    , logict-    , megaparsec >=6.5 && <7.0-    , monadlist-    , mtl-    , optparse-applicative-    , process-    , regex-tdfa-    , regex-tdfa-text-    , scientific-    , semigroups >=0.18 && <0.19-    , split-    , syb-    , template-haskell-    , text-    , these-    , time-    , transformers-    , unix-    , 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-  main-is: Main.hs-  other-modules:-      Repl-      Paths_hnix-  hs-source-dirs:-      main-  ghc-options: -Wall-  build-depends:-      aeson-    , ansi-wl-pprint-    , base >=4.9 && <5-    , bytestring-    , containers-    , data-fix-    , deepseq >=1.4.2 && <1.5-    , exceptions-    , filepath-    , hashing-    , haskeline-    , hnix-    , mtl-    , optparse-applicative-    , pretty-show-    , repline-    , 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-  type: exitcode-stdio-1.0-  main-is: Main.hs-  other-modules:-      EvalTests-      NixLanguageTests-      ParserTests-      PrettyParseTests-      PrettyTests-      ReduceExprTests-      TestCommon-      Paths_hnix-  hs-source-dirs:-      tests-  ghc-options: -Wall -threaded-  build-depends:-      Diff-    , Glob-    , ansi-wl-pprint-    , base >=4.9 && <5-    , bytestring-    , containers-    , data-fix-    , deepseq >=1.4.2 && <1.5-    , directory-    , exceptions-    , filepath-    , generic-random-    , hashing-    , hedgehog-    , hnix-    , interpolate-    , megaparsec-    , mtl-    , optparse-applicative-    , pretty-show-    , process-    , split-    , tasty-    , tasty-hedgehog-    , tasty-hunit-    , tasty-quickcheck-    , tasty-th-    , template-haskell-    , text-    , time-    , 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-  main-is: Main.hs-  other-modules:-      ParserBench-      Paths_hnix-  hs-source-dirs:-      benchmarks-  ghc-options: -Wall-  build-depends:-      ansi-wl-pprint-    , base >=4.9 && <5-    , bytestring-    , containers-    , criterion-    , data-fix-    , deepseq >=1.4.2 && <1.5-    , exceptions-    , filepath-    , hashing-    , hnix-    , mtl-    , optparse-applicative-    , 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+cabal-version:  2.2+name:           hnix+version:        0.17.0+synopsis:       Haskell implementation of the Nix language+description:    Haskell implementation of the Nix language.+category:       System, Data, Nix+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:        BSD-3-Clause+license-file:   License+build-type:     Simple+data-dir:       data/+extra-source-files:+  ChangeLog.md+  ReadMe.md+  License+  data/nix/tests/lang/binary-data+  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-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-hashfile-missing.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-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-attrs.exp+  data/nix/tests/lang/eval-okay-attrs.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-concatmap.exp+  data/nix/tests/lang/eval-okay-concatmap.nix+  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-introspection.exp+  data/nix/tests/lang/eval-okay-context-introspection.nix+  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.exp+  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.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-float.exp+  data/nix/tests/lang/eval-okay-float.nix+  data/nix/tests/lang/eval-okay-fromjson.exp+  data/nix/tests/lang/eval-okay-fromjson.nix+  data/nix/tests/lang/eval-okay-fromTOML.exp+  data/nix/tests/lang/eval-okay-fromTOML.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.exp+  data/nix/tests/lang/eval-okay-getattrpos.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-getenv.exp+  data/nix/tests/lang/eval-okay-getenv.nix+  data/nix/tests/lang/eval-okay-hash.exp+  data/nix/tests/lang/eval-okay-hashfile.exp+  data/nix/tests/lang/eval-okay-hashfile.nix+  data/nix/tests/lang/eval-okay-hashstring.exp+  data/nix/tests/lang/eval-okay-hashstring.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-mapattrs.exp+  data/nix/tests/lang/eval-okay-mapattrs.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-pathexists.exp+  data/nix/tests/lang/eval-okay-pathexists.nix+  data/nix/tests/lang/eval-okay-path.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-toxml2.exp+  data/nix/tests/lang/eval-okay-toxml2.nix+  data/nix/tests/lang/eval-okay-toxml.exp+  data/nix/tests/lang/eval-okay-toxml.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/imported2.nix+  data/nix/tests/lang/imported.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-7.nix+  data/nix/tests/lang/parse-fail-dup-formals.nix+  data/nix/tests/lang/parse-fail-mixed-nested-attrs1.nix+  data/nix/tests/lang/parse-fail-mixed-nested-attrs2.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-uft8.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-dup-attrs-6.nix+  data/nix/tests/lang/parse-okay-mixed-nested-attrs-1.nix+  data/nix/tests/lang/parse-okay-mixed-nested-attrs-2.nix+  data/nix/tests/lang/parse-okay-mixed-nested-attrs-3.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/local.mk+  data/nixpkgs-all-packages.nix+  data/let-comments.nix+  data/let-comments-multiline.nix+  data/simple-pretty.nix+  data/simple.nix+  data/nixpkgs-all-packages-pretty.nix+  data/let.nix+  tests/eval-compare/builtins.appendContext.nix+  tests/eval-compare/builtins.eq-bottom-00.nix+  tests/eval-compare/builtins.fetchurl-01.nix+  tests/eval-compare/builtins.fromJSON-01.nix+  tests/eval-compare/builtins.getContext.nix+  tests/eval-compare/builtins.lessThan-01.nix+  tests/eval-compare/builtins.mapAttrs-01.nix+  tests/eval-compare/builtins.pathExists.nix+  tests/eval-compare/builtins.replaceStrings-01.nix+  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/builtins.string.store.nix+  tests/eval-compare/builtins.toJSON.nix+  tests/eval-compare/current-system.nix+  tests/eval-compare/ellipsis.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+  tests/eval-compare/paths-01.nix+  tests/eval-compare/placeholder.nix+  tests/files/attrs.nix+  tests/files/callLibs.nix+  tests/files/eighty.nix+  tests/files/file.nix+  tests/files/file2.nix+  tests/files/findFile.nix+  tests/files/force.nix+  tests/files/goodbye.nix+  tests/files/hello.nix+  tests/files/hello2.nix+  tests/files/if-then.nix+  tests/files/lint.nix+  tests/files/loop.nix+  tests/files/test.nix+  tests/files/with.nix++source-repository head+  type: git+  location: https://github.com/haskell-nix/hnix++flag optimize+  description: Enable all optimization flags+  manual: True+  default: True++flag profiling+  description: Enable profiling+  manual: True+  default: False++common shared+  default-language: Haskell2010+  default-extensions:+      NoImplicitPrelude+    , OverloadedStrings+    , DeriveGeneric+    , DeriveDataTypeable+    , DeriveFunctor+    , DeriveFoldable+    , DeriveTraversable+    , DeriveLift+    , FlexibleContexts+    , FlexibleInstances+    , ScopedTypeVariables+    , StandaloneDeriving+    , TypeApplications+    , TypeSynonymInstances+    , InstanceSigs+    , MultiParamTypeClasses+    , TupleSections+    , LambdaCase+    , BangPatterns+    , ViewPatterns+  build-depends:+      base >= 4.12 && < 5+    , data-fix >= 0.3.0 && < 0.4+    , exceptions >= 0.10.0 && < 0.11+    , filepath >= 1.4.2 && < 1.5+    , optparse-applicative >= 0.14.3 && < 0.19+    , relude >= 1.0.0 && < 1.3+    , serialise >= 0.2.1 && < 0.3+    , template-haskell >= 2.13 && < 2.22+    , time >= 1.8.0 && < 1.9 || >= 1.9.3 && < 1.13+  ghc-options:+    -Wall+    -Wno-incomplete-uni-patterns+    -fprint-potential-instances+  if flag(optimize)+    default-extensions:+      ApplicativeDo+    ghc-options:+      -O2+      -fexpose-all-unfoldings+      -fspecialise-aggressively+  -- if !flag(profiling)+  --   build-depends:+  --       ghc-datasize++library+  import: shared+  exposed-modules:+    Nix+    Nix.Prelude+    Nix.Utils+    Nix.Atoms+    Nix.Builtins+    Nix.Cache+    Nix.Cited+    Nix.Cited.Basic+    Nix.Context+    Nix.Convert+    Nix.Effects+    Nix.Effects.Basic+    Nix.Effects.Derivation+    Nix.Eval+    Nix.Exec+    Nix.Expr+    Nix.Expr.Shorthands+    Nix.Expr.Strings+    Nix.Expr.Types+    Nix.Expr.Types.Annotated+    Nix.Frames+    Nix.Fresh+    Nix.Fresh.Basic+    Nix.Json+    Nix.Lint+    Nix.Normal+    Nix.Options+    Nix.Options.Parser+    Nix.Parser+    Nix.Pretty+    Nix.Reduce+    Nix.Render+    Nix.Render.Frame+    Nix.Scope+    Nix.Standard+    Nix.String+    Nix.String.Coerce+    Nix.TH+    Nix.Thunk+    Nix.Thunk.Basic+    Nix.Type.Assumption+    Nix.Type.Env+    Nix.Type.Infer+    Nix.Type.Type+    Nix.Utils.Fix1+    Nix.Value+    Nix.Value.Equal+    Nix.Value.Monad+    Nix.Var+    Nix.XML+  other-modules:+    Paths_hnix+    Nix.Unused+  autogen-modules:+    Paths_hnix+  hs-source-dirs:+    src+  build-depends:+      aeson >= 1.4.2 && < 1.6 || >= 2.0 && < 2.2+    , array >= 0.4 && < 0.6+    , base16-bytestring >= 0.1.1 && < 1.1+    , binary >= 0.8.5 && < 0.9+    , bytestring >= 0.10.8 && < 0.12+    , cryptonite+    , comonad >= 5.0.4 && < 5.1+    , containers >= 0.5.11.0 && < 0.7+    , deepseq >= 1.4.3 && <1.6+    , deriving-compat >= 0.3 && < 0.7+    , directory >= 1.3.1 && < 1.4+    , extra >= 1.7 && < 1.8+    , free >= 5.1 && < 5.2+    , gitrev >= 1.1.0 && < 1.4+    , hashable >= 1.2.5 && < 1.5+    , hashing >= 0.1.0 && < 0.2+    , hnix-store-core >= 0.6.0 && < 0.8+    , hnix-store-remote >= 0.6.0 && < 0.7+    , http-client >= 0.5.14 && < 0.6 || >= 0.6.4 && < 0.8+    , http-client-tls >= 0.3.5 && < 0.4+    , http-types >= 0.12.2 && < 0.13+    , lens-family >= 1.2.2 && < 2.2+    , lens-family-core >= 1.2.2 && < 2.2+    , lens-family-th >= 0.5.0 && < 0.6+    , logict >= 0.6.0 && < 0.7 || >= 0.7.0.2 && < 0.9+    , megaparsec >= 7.0 && < 9.6+    , monad-control >= 1.0.2 && < 1.1+    , monadlist >= 0.0.2 && < 0.1+    , mtl >= 2.2.2 && < 2.4+    , neat-interpolation >= 0.4 && < 0.6+    , parser-combinators >= 1.0.1 && < 1.4+    , pretty-show >= 1.9.5 && < 1.11+    , prettyprinter >= 1.7.0 && < 1.8+    , process >= 1.6.3 && < 1.7+    , ref-tf >= 0.5 && < 0.6+    , regex-tdfa >= 1.2.3 && < 1.4+    , scientific >= 0.3.6 && < 0.4+    , semialign >= 1.2 && < 1.4+    , some >= 1.0.1 && < 1.1+    , split >= 0.2.3 && < 0.3+    , syb >= 0.7 && < 0.8+    -- provides:+    --   * compat instances for old versions of TH for old GHCs+    --   * orphan instances for TH missing instances+    -- aka Lift Text, Bytestring, Vector, Containers,+    -- we use Lift Text particulrarly for GHC 8.6+    , th-lift-instances >= 0.1 && < 0.2+    , text >= 1.2.3 && < 2.2+    , these >= 1.0.1 && < 1.3+    , transformers >= 0.5.5 && < 0.7+    , transformers-base >= 0.4.5 && < 0.5+    , unix-compat >= 0.4.3 && < 0.8+    , unordered-containers >= 0.2.14 && < 0.3+    , vector >= 0.12.0 && < 0.14+    , xml >= 1.3.14 && < 1.4++executable hnix+  import: shared+  hs-source-dirs:+    main+  main-is: Main.hs+  other-modules:+    Repl+    Paths_hnix+  autogen-modules:+    Paths_hnix+  build-depends:+      hnix+    , aeson+    , comonad+    , containers+    , deepseq+    , free+    , haskeline >= 0.8.0.0 && < 0.9+    , pretty-show+    , prettyprinter+    , ref-tf+    , repline >= 0.4.0.0 && < 0.5+  if impl(ghc < 8.10)+    -- GHC < 8.10 comes with haskeline < 0.8, which we don't support.+    -- To simplify CI, we just disable the component.+    buildable: False++test-suite hnix-tests+  import: shared+  type: exitcode-stdio-1.0+  main-is: Main.hs+  other-modules:+    EvalTests+    NixLanguageTests+    ParserTests+    PrettyParseTests+    PrettyTests+    ReduceExprTests+    TestCommon+  hs-source-dirs:+    tests+  build-depends:+      hnix+    , Diff+    , Glob+    , containers+    , directory+    , hedgehog+    , megaparsec+    , neat-interpolation+    , pretty-show+    , prettyprinter+    , process+    , split+    , tasty+    , tasty-hedgehog+    , tasty-hunit+    , tasty-th+    , unix-compat++benchmark hnix-benchmarks+  import: shared+  type: exitcode-stdio-1.0+  main-is: Main.hs+  other-modules:+    ParserBench+  hs-source-dirs:+    benchmarks+  build-depends:+    hnix+    , criterion
main/Main.hs view
@@ -1,221 +1,314 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE TypeApplications #-}+{-# language MultiWayIf #-}+{-# language TypeFamilies #-}+{-# language RecordWildCards #-} -module Main where+module Main ( main ) where -import qualified Control.DeepSeq as Deep-import qualified Control.Exception as Exc-import           Control.Monad+import           Nix.Prelude+import           Relude                        as Prelude ( force )+import           Control.Comonad                ( extract )+import qualified Control.Exception             as Exception+import           GHC.Err                        ( errorWithoutStackTrace )+import           Control.Monad.Free+import           Control.Monad.Ref              ( MonadRef(readRef) ) import           Control.Monad.Catch-import           Control.Monad.IO.Class--- import           Control.Monad.ST-import qualified Data.Aeson.Encoding as A-import qualified Data.Aeson.Text as A-import qualified Data.HashMap.Lazy as M-import qualified Data.Map as Map-import           Data.List (sortOn)-import           Data.Maybe (fromJust)+import           System.IO                      ( hPutStrLn )+import qualified Data.HashMap.Lazy             as M+import qualified Data.Map                      as Map import           Data.Time-import qualified Data.Text as Text-import qualified Data.Text.IO as Text-import qualified Data.Text.Lazy.Encoding as TL-import qualified Data.Text.Lazy.IO as TL-import           Nix+import qualified Data.Text.IO                  as Text+import           Text.Show.Pretty               ( ppShow )+import           Nix                     hiding ( force ) import           Nix.Convert-import qualified Nix.Eval as Eval--- import           Nix.Lint+import           Nix.Json import           Nix.Options.Parser-import qualified Nix.Type.Env as Env-import qualified Nix.Type.Infer as HM-import           Nix.Utils-import           Options.Applicative hiding (ParserResult(..))+import           Nix.Standard+import           Nix.Thunk.Basic+import           Nix.Type.Env                   ( Env(..) )+import           Nix.Type.Type                  ( Scheme )+import qualified Nix.Type.Infer                as HM+import           Nix.Value.Monad+import           Options.Applicative     hiding ( ParserResult(..) )+import           Prettyprinter           hiding ( list )+import           Prettyprinter.Render.Text      ( renderIO ) import qualified Repl-import           System.FilePath-import           System.IO-import           Text.PrettyPrint.ANSI.Leijen hiding ((<$>))-import qualified Text.Show.Pretty as PS+import           Nix.Eval  main :: IO ()-main = do-    time <- liftIO getCurrentTime-    opts <- execParser (nixOptionsInfo time)-    runLazyM opts $ case readFrom opts of-        Just path -> do-            let file = addExtension (dropExtension path) "nix"-            process opts (Just file) =<< liftIO (readCache path)-        Nothing -> case expression opts of-            Just s -> handleResult opts Nothing (parseNixTextLoc s)-            Nothing  -> case fromFile opts of-                Just "-" ->-                    mapM_ (processFile opts)-                        =<< (lines <$> liftIO getContents)-                Just path ->-                    mapM_ (processFile opts)-                        =<< (lines <$> liftIO (readFile path))-                Nothing -> case filePaths opts of-                    [] -> Repl.shell (pure ())-                    ["-"] ->-                        handleResult opts Nothing . parseNixTextLoc-                            =<< liftIO Text.getContents-                    paths ->-                        mapM_ (processFile opts) paths-  where-    processFile opts path = do-        eres <- parseNixFileLoc path-        handleResult opts (Just path) eres+main =+  do+    currentTime <- getCurrentTime+    opts <- execParser $ nixOptionsInfo currentTime -    handleResult opts mpath = \case-        Failure err ->-            (if ignoreErrors opts-             then liftIO . hPutStrLn stderr-             else errorWithoutStackTrace) $ "Parse failed: " ++ show err+    main' opts -        Success expr -> do-            when (check opts) $ do-                expr' <- liftIO (reduceExpr mpath expr)-                case HM.inferTop Env.empty [("it", stripAnnotation expr')] of-                    Left err ->-                        errorWithoutStackTrace $ "Type error: " ++ PS.ppShow err-                    Right ty ->-                        liftIO $ putStrLn $ "Type of expression: "-                            ++ PS.ppShow (fromJust (Map.lookup "it" (Env.types ty)))+main' :: Options -> IO ()+main' opts@Options{..} = runWithBasicEffectsIO opts execContentsFilesOrRepl+ where+  --  2021-07-15: NOTE: This logic should be weaved stronger through CLI options logic (OptParse-Applicative code)+  -- As this logic is not stated in the CLI documentation, for example. So user has no knowledge of these.+  execContentsFilesOrRepl :: StdIO+  execContentsFilesOrRepl =+    fromMaybe+      loadFromCliFilePathList+      $ loadBinaryCacheFile <|>+        loadLiteralExpression <|>+        loadExpressionFromFile+   where+    -- | The base case: read expressions from the last CLI directive (@[FILE]@) listed on the command line.+    loadFromCliFilePathList :: StdIO+    loadFromCliFilePathList =+      case getFilePaths of+        []     -> runRepl+        ["-"]  -> readExpressionFromStdin+        _paths -> processSeveralFiles (coerce _paths)+     where+      -- | Fall back to running the REPL+      runRepl = withEmptyNixContext Repl.main -                -- liftIO $ putStrLn $ runST $-                --     runLintM opts . renderSymbolic =<< lint opts expr+      readExpressionFromStdin =+        processExpr =<< liftIO Text.getContents -            catch (process opts mpath expr) $ \case-                NixException frames ->-                    errorWithoutStackTrace . show-                        =<< renderFrames @(NThunk (Lazy IO)) frames+    processSeveralFiles :: [Path] -> StdIO+    processSeveralFiles = traverse_ processFile+     where+      processFile path = handleResult (pure path) =<< parseNixFileLoc path -            when (repl opts) $ Repl.shell (pure ())+    -- |  The `--read` option: load expression from a serialized file.+    loadBinaryCacheFile :: Maybe StdIO+    loadBinaryCacheFile =+      (\ (binaryCacheFile :: Path) ->+        do+          let file = replaceExtension binaryCacheFile "nixc"+          processCLIOptions (pure file) =<< liftIO (readCache binaryCacheFile)+      ) <$> getReadFrom -    process opts mpath expr-        | evaluate opts, tracing opts =-              evaluateExpression mpath-                  Nix.nixTracingEvalExprLoc printer expr+    -- | The `--expr` option: read expression from the argument string+    loadLiteralExpression :: Maybe StdIO+    loadLiteralExpression = processExpr <$> getExpression -        | evaluate opts, Just path <- reduce opts =-              evaluateExpression mpath (reduction path) printer expr+    -- | The `--file` argument: read expressions from the files listed in the argument file+    loadExpressionFromFile :: Maybe StdIO+    loadExpressionFromFile =+      -- We can start use Text as in the base case, requires changing Path -> Text+      -- But that is a gradual process:+      -- https://github.com/haskell-nix/hnix/issues/912+      (processSeveralFiles . (coerce . toString <$>) . lines <=< liftIO) .+        (\case+          "-" -> Text.getContents+          _fp -> readFile _fp+        ) <$> getFromFile -        | evaluate opts, not (null (arg opts) && null (argstr opts)) =-              evaluateExpression mpath-                  Nix.nixEvalExprLoc printer expr+  processExpr :: Text -> StdIO+  processExpr = handleResult mempty . parseNixTextLoc -        | evaluate opts =-              processResult printer =<< Nix.nixEvalExprLoc mpath expr+  withEmptyNixContext = withNixContext mempty -        | xml opts =-              error "Rendering expression trees to XML is not yet implemented"+  --  2021-07-15: NOTE: @handleResult@ & @process@ - have atrocious size & compexity, they need to be decomposed & refactored.+  handleResult mpath =+    either+      (\ err ->+        bool+          errorWithoutStackTrace+          (liftIO . hPutStrLn stderr)+          isIgnoreErrors+          $ "Parse failed: " <> show err+      ) -        | json opts =-              liftIO $ TL.putStrLn $-                  A.encodeToLazyText (stripAnnotation expr)+      (\ expr ->+        do+          when isCheck $+            do+              expr' <- liftIO $ reduceExpr mpath expr+              either+                (\ err -> errorWithoutStackTrace $ "Type error: " <> ppShow err)+                (liftIO . putStrLn . (<>) "Type of expression: " .+                  ppShow . maybeToMonoid . Map.lookup @VarName @[Scheme] "it" . coerce+                )+                $ HM.inferTop mempty $ curry one "it" $ stripAnnotation expr' -        | verbose opts >= DebugInfo =-              liftIO $ putStr $ PS.ppShow $ stripAnnotation expr+                -- liftIO $ putStrLn $ runST $+                --     runLintM opts . renderSymbolic =<< lint opts expr -        | cache opts, Just path <- mpath =-              liftIO $ writeCache (addExtension (dropExtension path) "nixc") expr+          catch (processCLIOptions mpath expr) $+            \case+              NixException frames ->+                errorWithoutStackTrace . show =<<+                  renderFrames+                    @StdVal+                    @StdThun+                    frames -        | parseOnly opts =-              void $ liftIO $ Exc.evaluate $ Deep.force expr+          when isRepl $+            withEmptyNixContext $+              bool+                Repl.main+                ((Repl.main' . pure) =<< nixEvalExprLoc (coerce mpath) expr)+                isEvaluate+      ) -        | otherwise =-              liftIO $ displayIO stdout-                  . renderPretty 0.4 80-                  . prettyNix-                  . stripAnnotation $ expr-      where-        printer :: forall e m. (MonadNix e m, MonadIO m, Typeable m)-                => NValue m -> m ()-        printer-            | finder opts =-              fromValue @(AttrSet (NThunk m)) >=> findAttrs-            | xml opts =-              liftIO . putStrLn . toXML <=< normalForm-            | json opts =-              liftIO . TL.putStrLn-                     . TL.decodeUtf8-                     . A.encodingToLazyByteString-                     . toEncodingSorted-                     <=< fromNix-            | strict opts =-              liftIO . print . prettyNValueNF <=< normalForm-            | values opts  =-              liftIO . print <=< prettyNValueProv-            | otherwise  =-              liftIO . print <=< prettyNValue-          where-            findAttrs = go ""-              where-                go prefix s = do-                    xs <- forM (sortOn fst (M.toList s))-                        $ \(k, nv@(NThunk _ t)) -> case t of-                            Value v -> pure (k, Just v)-                            Thunk _ _ ref -> do-                                let path = prefix ++ Text.unpack k-                                    (_, descend) = filterEntry path k-                                val <- readVar ref-                                case val of-                                    Computed _ -> pure (k, Nothing)-                                    _ | descend   -> (k,) <$> forceEntry path nv-                                      | otherwise -> pure (k, Nothing)+  --  2021-07-15: NOTE: Logic of CLI Option processing is scattered over several functions, needs to be consolicated.+  processCLIOptions :: Maybe Path -> NExprLoc -> StdIO+  processCLIOptions mpath expr+    | isEvaluate =+      if+        | isTrace                       -> evaluateExprWith nixTracingEvalExprLoc expr+        | Just path <- getReduce        -> evaluateExprWith (reduction path . coerce) expr+        | null getArg || null getArgstr -> evaluateExprWith nixEvalExprLoc expr+        | otherwise                     -> processResult printer <=< nixEvalExprLoc (coerce mpath) $ expr+    | isXml                        = fail "Rendering expression trees to XML is not yet implemented"+    | isJson                       = fail "Rendering expression trees to JSON is not implemented"+    | getVerbosity >= DebugInfo    = liftIO . putStr . ppShow . stripAnnotation $ expr+    | isCache , Just path <- mpath = liftIO . writeCache (replaceExtension path "nixc") $ expr+    | isParseOnly                  = void . liftIO . Exception.evaluate . force $ expr+    | otherwise                    =+      liftIO .+        renderIO+          stdout+          . layoutPretty (LayoutOptions $ AvailablePerLine 80 0.4)+          . prettyNix+          . stripAnnotation+          $ expr+   where+    evaluateExprWith evaluator = evaluateExpression (coerce mpath) evaluator printer -                    forM_ xs $ \(k, mv) -> do-                        let path = prefix ++ Text.unpack k-                            (report, descend) = filterEntry path k-                        when report $ do-                            liftIO $ putStrLn path-                            when descend $ case mv of-                                Nothing -> return ()-                                Just v -> case v of-                                    NVSet s' _ -> go (path ++ ".") s'-                                    _ -> return ()-                  where-                    filterEntry path k = case (path, k) of-                        ("stdenv", "stdenv")           -> (True,  True)-                        (_,        "stdenv")           -> (False, False)-                        (_,        "out")              -> (True,  False)-                        (_,        "src")              -> (True,  False)-                        (_,        "mirrorsFile")      -> (True,  False)-                        (_,        "buildPhase")       -> (True,  False)-                        (_,        "builder")          -> (False,  False)-                        (_,        "drvPath")          -> (False,  False)-                        (_,        "outPath")          -> (False,  False)-                        (_,        "__impureHostDeps") -> (False,  False)-                        (_,        "__sandboxProfile") -> (False,  False)-                        ("pkgs",   "pkgs")             -> (True,  True)-                        (_,        "pkgs")             -> (False, False)-                        (_,        "drvAttrs")         -> (False, False)-                        _ -> (True, True)+    printer+      :: StdVal+      -> StdIO+    printer+      | isFinder    = findAttrs <=< fromValue @(AttrSet StdVal)+      | otherwise = printer'+     where+      -- 2021-05-27: NOTE: With naive fix of the #941+      -- This is overall a naive printer implementation, as options should interact/respect one another.+      -- A nice question: "Should respect one another to what degree?": Go full combinator way, for which+      -- old Nix CLI is nototrious for (and that would mean to reimplement the old Nix CLI),+      -- OR: https://github.com/haskell-nix/hnix/issues/172 and have some sane standart/default behaviour for (most) keys.+      printer'+        | isXml     = out (ignoreContext . toXML)                    normalForm+        | isJson    = out (ignoreContext . mempty . toJSONNixString) normalForm+        | isStrict  = out (show . prettyNValue)                      normalForm+        | isValues  = out (show . prettyNValueProv)                  removeEffects+        | otherwise = out (show . prettyNValue)                      removeEffects+       where+        out+          :: (b -> Text)+          -> (a -> StandardIO b)+          -> a+          -> StdIO+        out transform val = liftIO . Text.putStrLn . transform <=< val -                    forceEntry k v = catch (Just <$> force v pure)-                        $ \(NixException frames) -> do-                              liftIO . putStrLn-                                     . ("Exception forcing " ++)-                                     . (k ++)-                                     . (": " ++) . show-                                  =<< renderFrames @(NThunk (Lazy IO)) frames-                              return Nothing+      findAttrs+        :: AttrSet StdVal+        -> StdIO+      findAttrs = go mempty+       where+        go :: Text -> AttrSet StdVal -> StdIO+        go prefix s =+          traverse_+            (\ (k, mv) ->+              do+                let+                  path              = prefix <> k+                  (report, descend) = filterEntry path k+                when report $+                  do+                    liftIO $ Text.putStrLn path+                    when descend $+                      maybe+                        stub+                        (\case+                          NVSet _ s' -> go (path <> ".") s'+                          _          -> stub+                        )+                        mv+            )+            =<< traverse+                (\ (k, nv) ->+                  (k, ) <$>+                  free+                    (\ (StdThunk (extract -> Thunk _ _ ref)) ->+                      do+                        let+                          path         = prefix <> k+                          (_, descend) = filterEntry path k -    reduction path mp x = do-        eres <- Nix.withNixContext mp $-            Nix.reducingEvalExpr (Eval.eval . annotated . getCompose) mp x-        handleReduced path eres+                        val <- readRef @StandardIO ref+                        bool+                          (pure Nothing)+                          (forceEntry path nv)+                          (descend &&+                            deferred+                              (const False)+                              (const True)+                              val+                          )+                    )+                    (pure . pure . Free)+                    nv+                )+                (sortWith fst $ M.toList $ M.mapKeys coerce s)+         where+          filterEntry path k = case (path, k) of+            ("stdenv", "stdenv"          ) -> (True , True )+            (_       , "stdenv"          ) -> (False, False)+            (_       , "out"             ) -> (True , False)+            (_       , "src"             ) -> (True , False)+            (_       , "mirrorsFile"     ) -> (True , False)+            (_       , "buildPhase"      ) -> (True , False)+            (_       , "builder"         ) -> (False, False)+            (_       , "drvPath"         ) -> (False, False)+            (_       , "outPath"         ) -> (False, False)+            (_       , "__impureHostDeps") -> (False, False)+            (_       , "__sandboxProfile") -> (False, False)+            ("pkgs"  , "pkgs"            ) -> (True , True )+            (_       , "pkgs"            ) -> (False, False)+            (_       , "drvAttrs"        ) -> (False, False)+            _                              -> (True , True ) -    handleReduced :: (MonadThrow m, MonadIO m)-                  => FilePath-                  -> (NExprLoc, Either SomeException (NValue m))-                  -> m (NValue m)-    handleReduced path (expr', eres) = do-        liftIO $ do-            putStrLn $ "Wrote winnowed expression tree to " ++ path-            writeFile path $ show $ prettyNix (stripAnnotation expr')-        case eres of-            Left err -> throwM err-            Right v  -> return v+          forceEntry+            :: MonadValue a StandardIO+            => Text+            -> a+            -> StandardIO (Maybe a)+          forceEntry k v =+            catch+              (pure <$> demand v)+              fun+           where+            fun :: NixException -> StandardIO (Maybe a)+            fun (coerce -> frames) =+              do+                liftIO+                  . Text.putStrLn+                  . (("Exception forcing " <> k <> ": ") <>)+                  . show =<<+                    renderFrames+                      @StdVal+                      @StdThun+                      frames+                pure Nothing++  reduction path mpathToContext annExpr =+    do+      eres <-+        withNixContext+          mpathToContext+          $ reducingEvalExpr+              evalContent+              mpathToContext+              annExpr+      handleReduced path eres++  handleReduced+    :: (MonadThrow m, MonadIO m)+    => Path+    -> (NExprLoc, Either SomeException (NValue t f m))+    -> m (NValue t f m)+  handleReduced (coerce -> path) (expr', eres) =+    do+      liftIO $+        do+          putStrLn $ "Wrote sifted expression tree to " <> path+          writeFile path $ show $ prettyNix $ stripAnnotation expr'+      either throwM pure eres
main/Repl.hs view
@@ -7,190 +7,589 @@    directory for more details. -} -{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MultiWayIf #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeSynonymInstances #-}--{-# OPTIONS_GHC -Wno-unused-matches #-}-{-# OPTIONS_GHC -Wno-unused-imports #-}+{-# language MultiWayIf #-} -module Repl where+module Repl+  ( main+  , main'+  ) where -import           Nix-import           Nix.Convert-import           Nix.Eval+import           Nix.Prelude             hiding ( state )+import           Nix                     hiding ( exec ) import           Nix.Scope-import qualified Nix.Type.Env as Env-import           Nix.Type.Infer-import           Nix.Utils+import           Nix.Value.Monad                ( demand ) -import qualified Data.HashMap.Lazy as M-import           Data.List (isPrefixOf, foldl')-import qualified Data.Map as Map-import           Data.Monoid-import           Data.Text (unpack, pack)-import qualified Data.Text as Text-import qualified Data.Text.IO as Text+import qualified Data.HashMap.Lazy             as M+import           Data.Char                      ( isSpace )+import           Data.List                      ( dropWhileEnd )+import qualified Data.Text                     as Text+import qualified Data.Text.IO                  as Text+import           Data.Version                   ( showVersion )+import           Paths_hnix                     ( version ) -import           Control.Monad.Identity-import           Control.Monad.Reader-import           Control.Monad.State.Strict+import           Control.Monad.Catch -import           System.Console.Haskeline.MonadException-import           System.Console.Repline-import           System.Environment-import           System.Exit+import           Prettyprinter                  ( Doc+                                                , space+                                                )+import qualified Prettyprinter+import qualified Prettyprinter.Render.Text     as Prettyprinter ----------------------------------------------------------------------------------- Types--------------------------------------------------------------------------------+import           System.Console.Haskeline.Completion+                                                ( Completion(isFinished)+                                                , completeWordWithPrev+                                                , simpleCompletion+                                                , listFiles+                                                )+import           System.Console.Repline         ( Cmd+                                                , CompletionFunc+                                                , CompleterStyle(Prefix)+                                                , MultiLine(SingleLine, MultiLine)+                                                , ExitDecision(Exit)+                                                , HaskelineT+                                                , evalRepl+                                                )+import qualified System.Console.Repline        as Console+import qualified System.Exit                   as Exit+import qualified System.IO.Error               as Error -data TermEnv+-- | Repl entry point+main :: (MonadNix e t f m, MonadIO m, MonadMask m) =>  m ()+main = main' Nothing -data IState = IState-  { -- tyctx :: Env.Env  -- Type environment-  -- ,-    tmctx :: TermEnv  -- Value environment+-- | Principled version allowing to pass initial value for context.+--+-- Passed value is stored in context with "input" key.+main' :: (MonadNix e t f m, MonadIO m, MonadMask m) => Maybe (NValue t f m) -> m ()+main' iniVal =+  do+    s <- initState iniVal++    evalStateT+      (evalRepl+        banner+        (cmd . fromString)+        options+        (pure commandPrefix)+        (pure "paste")+        completion+        (rcFile *> greeter)+        finalizer+      )+      s+ where+  commandPrefix = ':'++  banner = pure . \case+    SingleLine -> "hnix> "+    MultiLine  -> "| "++  greeter =+    liftIO $+      putStrLn $+        "Welcome to hnix "+        <> showVersion version+        <> ". For help type :help\n"+  finalizer = do+    liftIO $ putStrLn "Goodbye."+    pure Exit++  rcFile =+    do+      f <- liftIO $ readFile ".hnixrc" `catch` handleMissing++      traverse_+        (\case+          (prefixedCommand : xs) | Text.head prefixedCommand == commandPrefix ->+            do+              let+                arguments = unwords xs+                command = Text.tail prefixedCommand+              optMatcher command options arguments+          x -> cmd $ unwords x+        )+        (words <$> lines f)++  handleMissing e+    | Error.isDoesNotExistError e = stub+    | otherwise = throwM e++  -- Replicated and slightly adjusted `optMatcher` from `System.Console.Repline`+  -- which doesn't export it.+  --  * @MonadIO m@ instead of @MonadHaskeline m@+  --  * @putStrLn@ instead of @outputStrLn@+  optMatcher :: MonadIO m+             => Text+             -> Console.Options m+             -> Text+             -> m ()+  optMatcher s [] _ = liftIO $ Text.putStrLn $ "No such command :" <> s+  optMatcher s ((x, m) : xs) args+    | s `Text.isPrefixOf` fromString x = m $ toString args+    | otherwise = optMatcher s xs args+++-- * Types++data IState t f m = IState+  { replIt  :: Maybe NExprLoc        -- ^ Last expression entered+  , replCtx :: Scope (NValue t f m)  -- ^ Scope. Value environment.+  , replCfg :: ReplConfig            -- ^ REPL configuration+  } deriving (Eq, Show)++data ReplConfig = ReplConfig+  { cfgDebug  :: Bool+  , cfgStrict :: Bool+  , cfgValues :: Bool+  } deriving (Eq, Show)++defReplConfig :: ReplConfig+defReplConfig = ReplConfig+  { cfgDebug  = False+  , cfgStrict = False+  , cfgValues = False   } -initState :: IState-initState = IState {-Env.empty-} undefined+-- | Create initial IState for REPL+initState :: MonadNix e t f m => Maybe (NValue t f m) -> m (IState t f m)+initState mIni = do -type Repl e m a = HaskelineT (StateT IState m) a-hoistErr :: MonadIO m => Result a -> Repl e m a-hoistErr (Success val) = return val-hoistErr (Failure err) = do-  liftIO $ print err-  abort+  builtins <- evalText "builtins" ----------------------------------------------------------------------------------- Execution--------------------------------------------------------------------------------+  let+    scope = coerce $+      M.fromList $+      ("builtins", builtins) : fmap ("input",) (maybeToList mIni) -exec :: forall e m. (MonadNix e m, MonadIO m, MonadException m)-     => Bool -> Text.Text -> Repl e m ()-exec update source = do-  -- Get the current interpreter state-  st <- get+  opts <- askOptions -  -- Parser ( returns AST )-  expr <- hoistErr $ parseNixTextLoc source+  pure $+    IState+      Nothing+      scope+      defReplConfig+        { cfgStrict = isStrict opts+        , cfgValues = isValues opts+        }+  where+    evalText :: (MonadNix e t f m) => Text -> m (NValue t f m)+    evalText expr =+      either+        (\ e -> fail $ toString $ "Impossible happened: Unable to parse expression - '" <> expr <> "' fail was " <> show e)+        evalExprLoc+        (parseNixTextLoc expr) -  -- Type Inference ( returns Typing Environment )-  -- tyctx' <- hoistErr $ inferTop (tyctx st) expr+type Repl e t f m = HaskelineT (StateT (IState t f m) m) -  -- Create the new environment-  let st' = st { tmctx = tmctx st -- foldl' evalDef (tmctx st) expr-               -- , tyctx = tyctx' <> tyctx st-               } -  -- Update the interpreter state-  when update (put st')+-- * Execution -  -- If a value is entered, print it.-  lift $ lift $ do-    -- jww (2018-04-12): Once the user is able to establish definitions in-    -- the repl, they should be passed here.-    pushScope @(NThunk m) M.empty $ catch (go expr) $ \case-      NixException frames -> do-        liftIO . print =<< renderFrames @(NThunk m) frames+exec+  :: forall e t f m+   . (MonadNix e t f m, MonadIO m)+  => Bool+  -> Text+  -> Repl e t f m (Maybe (NValue t f m))+exec update source =+  do+    -- Get the current interpreter state+    state <- get++    when (cfgDebug $ replCfg state) $ liftIO $ print state++    -- Parser ( returns AST as `NExprLoc` )+    case parseExprOrBinding source of+      (Left err, _) ->+        do+          liftIO $ print err+          pure Nothing+      (Right expr, isBinding) ->+        do++          -- Type Inference ( returns Typing Environment )+          --+          -- import qualified Nix.Type.Env                  as Env+          -- import           Nix.Type.Infer+          --+          -- let tyctx' = inferTop mempty [("repl", stripAnnotation expr)]+          -- liftIO $ print tyctx'++          mVal <- lift $ lift $ try $ pushScope (replCtx state) (evalExprLoc expr)++          either+            (\ (NixException frames) ->+              do+                lift $ lift $ liftIO . print =<< renderFrames @(NValue t f m) @t frames+                pure Nothing+            )+            (\ val ->+              do+                -- Update the interpreter state+                when (update && isBinding) $ do+                  -- Set `replIt` to last entered expression+                  put state { replIt = pure expr }++                  -- If the result value is a set, update our context with it+                  case val of+                    NVSet _ (coerce -> scope) -> put state { replCtx = scope <> replCtx state }+                    _          -> stub++                pure $ pure val+            )+            mVal  where-  go expr = do-    val <- evalExprLoc expr-    opts :: Nix.Options <- asks (view hasLens)-    if | strict opts ->-         liftIO . print . prettyNValueNF =<< normalForm val-       | values opts ->-         liftIO . print =<< prettyNValueProv val-       | otherwise ->-         liftIO . print =<< prettyNValue val+  -- If parsing fails, turn the input into singleton attribute set+  -- and try again.+  --+  -- This allows us to handle assignments like @a = 42@+  -- which get turned into @{ a = 42; }@+  parseExprOrBinding i =+    either+      (\ e    ->+        either+          (const (Left e, False)) -- return the first parsing failure+          (\ e' -> (pure e', True))+          (parseNixTextLoc $ toAttrSet i))+      (\ expr -> (pure expr, False))+      (parseNixTextLoc i) -cmd :: (MonadNix e m, MonadIO m, MonadException m) => String -> Repl e m ()-cmd source = exec True (Text.pack source)+  toAttrSet i =+    "{" <> i <> whenFalse ";" (Text.isSuffixOf ";" i) <> "}" ----------------------------------------------------------------------------------- Commands--------------------------------------------------------------------------------+cmd+  :: (MonadNix e t f m, MonadIO m)+  => Text+  -> Repl e t f m ()+cmd source =+  do+    mVal <- exec True source+    maybe+      stub+      printValue+      mVal --- :browse command-browse :: MonadNix e m => [String] -> Repl e m ()-browse _ = do-  st <- get-  undefined-  -- liftIO $ mapM_ putStrLn $ ppenv (tyctx st)+printValue :: (MonadNix e t f m, MonadIO m)+           => NValue t f m+           -> Repl e t f m ()+printValue val = do+  cfg <- replCfg <$> get+  let+    g :: MonadIO m => Doc ann0 -> m ()+    g = liftIO . print --- :load command-load :: (MonadNix e m, MonadIO m, MonadException m) => [String] -> Repl e m ()-load args = do-  contents <- liftIO $ Text.readFile (unwords args)-  exec True contents+  lift $ lift $+    (if+      | cfgStrict cfg -> g . prettyNValue     <=< normalForm+      | cfgValues cfg -> g . prettyNValueProv <=< removeEffects+      | otherwise     -> g . prettyNValue     <=< removeEffects+    ) val --- :type command--- typeof :: [String] -> Repl e m ()--- typeof args = do---   st <- get---   let arg = unwords args---   case Env.lookup (pack arg) (tyctx st) of---     Just val -> liftIO $ putStrLn $ undefined -- ppsignature (arg, val)---     Nothing -> exec False (Text.pack arg) --- :quit command-quit :: (MonadNix e m, MonadIO m) => a -> Repl e m ()-quit _ = liftIO exitSuccess+-- * Commands ----------------------------------------------------------------------------------- Interactive Shell--------------------------------------------------------------------------------+-- | @:browse@ command+browse :: (MonadNix e t f m, MonadIO m)+       => Text+       -> Repl e t f m ()+browse _ =+  do+    state <- get+    traverse_+      (\(k, v) ->+        do+          liftIO $ Text.putStr $ coerce k <> " = "+          printValue v+      )+      (M.toList $ coerce $ replCtx state) --- Prefix tab completer+-- | @:load@ command+load+  :: (MonadNix e t f m, MonadIO m)+  => Path+  -> Repl e t f m ()+load path =+  do+    contents <- liftIO $ readFile $+       trim path+    void $ exec True contents+ where+  trim :: Path -> Path+  trim = coerce . dropWhileEnd isSpace . dropWhile isSpace . coerce++-- | @:type@ command+typeof+  :: (MonadNix e t f m, MonadIO m)+  => Text+  -> Repl e t f m ()+typeof src = do+  state <- get+  mVal <-+    maybe+      (exec False src)+      (pure . pure)+      (M.lookup (coerce src) (coerce $ replCtx state))++  traverse_ printValueType mVal++ where+  printValueType = liftIO . Text.putStrLn <=< lift . lift . showValueType+++-- | @:quit@ command+quit :: (MonadNix e t f m, MonadIO m) => a -> Repl e t f m ()+quit _ = liftIO Exit.exitSuccess++-- | @:set@ command+setConfig :: (MonadNix e t f m, MonadIO m) => Text -> Repl e t f m ()+setConfig args =+  handlePresence+    (liftIO $ Text.putStrLn "No option to set specified")+    (\ (x:_xs)  ->+      case filter ((==x) . helpSetOptionName) helpSetOptions of+        [opt] -> modify (\s -> s { replCfg = helpSetOptionFunction opt (replCfg s) })+        _     -> liftIO $ Text.putStrLn "No such option"+    )+    $ words args+++-- * Interactive Shell++-- | Prefix tab completer defaultMatcher :: MonadIO m => [(String, CompletionFunc m)]-defaultMatcher = [-    (":load"  , fileCompleter)-  --, (":type"  , values)-  ]+defaultMatcher =+  one (":load", Console.fileCompleter) --- Default tab completer-comp :: (Monad m, MonadState IState m) => WordCompleter m-comp n = do-  let cmds = [":load", ":type", ":browse", ":quit"]-  -- Env.TypeEnv ctx <- gets tyctx-  -- let defs = map unpack $ Map.keys ctx-  return $ filter (isPrefixOf n) (cmds {-++ defs-})+completion+  :: (MonadNix e t f m, MonadIO m)+  => CompleterStyle (StateT (IState t f m) m)+completion =+  System.Console.Repline.Prefix+    (completeWordWithPrev (pure '\\') separators completeFunc)+    defaultMatcher+ where+  separators :: String+  separators = " \t[(,=+*&|}#?>:" -options :: (MonadNix e m, MonadIO m, MonadException m)-        => [(String, [String] -> Repl e m ())]-options = [-    ("load"   , load)-  , ("browse" , browse)-  , ("quit"   , quit)-  -- , ("type"   , Repl.typeof)+-- | Main completion function+--+-- Heavily inspired by Dhall Repl, with `algebraicComplete`+-- adjusted to monadic variant able to `demand` thunks.+completeFunc+  :: forall e t f m . (MonadNix e t f m, MonadIO m)+  -- 2021-04-02: So far conversiton to Text here is not productive,+  -- since Haskeline uses String of all this.+  => String+  -> String+  -> (StateT (IState t f m) m) [Completion]+completeFunc reversedPrev word+  -- Commands+  | reversedPrev == ":" =+    pure . listCompletion $+      toString . helpOptionName <$>+        (helpOptions :: HelpOptions e t f m)++  -- Files+  | any (`isPrefixOf` word) [ "/", "./", "../", "~/" ] =+    listFiles word++  -- Attributes of sets in REPL context+  | var : subFields <- Text.split (== '.') (fromString word) , isPresent subFields =+    do+      state <- get+      maybe+        stub+        (\ binding ->+          do+            candidates <- lift $ algebraicComplete subFields binding+            pure $+              notFinished <$>+                listCompletion+                  (toString . (var <>) <$>+                    candidates+                  )+        )+        (M.lookup (coerce var) $ coerce $ replCtx state)++  -- Builtins, context variables+  | otherwise =+    do+      state <- get+      let+          scopeHashMap :: HashMap VarName (NValue t f m)+          scopeHashMap = coerce $ replCtx state+          contextKeys :: [VarName]+          contextKeys = M.keys scopeHashMap+          builtins :: AttrSet (NValue t f m)+          (Just (NVSet _ builtins)) = M.lookup "builtins" scopeHashMap+          shortBuiltins :: [VarName]+          shortBuiltins = M.keys builtins++      pure $ listCompletion $ toString <$>+        one "__includes"+          <> contextKeys+          <> shortBuiltins++  where+    listCompletion = fmap simpleCompletion . filter (word `isPrefixOf`)++    notFinished x = x { isFinished = False }++    algebraicComplete+      :: (MonadNix e t f m)+      => [Text]+      -> NValue t f m+      -> m [Text]+    algebraicComplete subFields val =+      let+        keys = fmap ("." <>) . M.keys++        withMap m =+          case subFields of+            [] -> pure $ keys m+            -- Stop on last subField (we care about the keys at this level)+            [_] -> pure $ keys m+            f:fs ->+              maybe+                stub+                ((<<$>>)+                   (("." <> f) <>)+                   . algebraicComplete fs <=< demand+                )+                (M.lookup (coerce f) m)+      in+      case val of+        NVSet _ xs -> withMap (M.mapKeys coerce xs)+        _          -> stub++-- | HelpOption inspired by Dhall Repl+-- with `Doc` instead of String for syntax and doc+data HelpOption e t f m = HelpOption+  { helpOptionName     :: Text+  , helpOptionSyntax   :: Doc ()+  , helpOptionDoc      :: Doc ()+  , helpOptionFunction :: Cmd (Repl e t f m)+  }++type HelpOptions e t f m = [HelpOption e t f m]++helpOptions :: (MonadNix e t f m, MonadIO m) => HelpOptions e t f m+helpOptions =+  [ HelpOption+      "help"+      mempty+      "Print help text"+      (help helpOptions . fromString)+  , HelpOption+      "paste"+      mempty+      "Enter multi-line mode"+      (error "Unreachable")+  , HelpOption+      "load"+      "FILENAME"+      "Load .nix file into scope"+      (load . fromString)+  , HelpOption+      "browse"+      mempty+      "Browse bindings in interpreter context"+      (browse . fromString)+  , HelpOption+      "type"+      "EXPRESSION"+      "Evaluate expression or binding from context and print the type of the result value"+      (typeof . fromString)+  , HelpOption+      "quit"+      mempty+      "Quit interpreter"+      quit+  , HelpOption+      "set"+      mempty+      ("Set REPL option"+        <> Prettyprinter.line+        <> "Available options:"+        <> Prettyprinter.line+        <> renderSetOptions helpSetOptions+      )+      (setConfig . fromString)   ] ----------------------------------------------------------------------------------- Entry Point--------------------------------------------------------------------------------+-- | Options for :set+data HelpSetOption = HelpSetOption+  { helpSetOptionName     :: Text+  , helpSetOptionSyntax   :: Doc ()+  , helpSetOptionDoc      :: Doc ()+  , helpSetOptionFunction :: ReplConfig -> ReplConfig+  } -completer :: (MonadNix e m, MonadIO m) => CompleterStyle (StateT IState m)-completer = Prefix (wordCompleter comp) defaultMatcher+helpSetOptions :: [HelpSetOption]+helpSetOptions =+  [ HelpSetOption+      "strict"+      mempty+      "Enable strict evaluation of REPL expressions"+      (\x -> x { cfgStrict = True})+  , HelpSetOption+      "lazy"+      mempty+      "Disable strict evaluation of REPL expressions"+      (\x -> x { cfgStrict = False})+  , HelpSetOption+      "values"+      mempty+      "Enable printing of value provenance information"+      (\x -> x { cfgValues = True})+  , HelpSetOption+      "novalues"+      mempty+      "Disable printing of value provenance information"+      (\x -> x { cfgValues = False})+  , HelpSetOption+      "debug"+      mempty+      "Enable printing of REPL debug information"+      (\x -> x { cfgDebug = True})+  , HelpSetOption+      "nodebug"+      mempty+      "Disable REPL debugging"+      (\x -> x { cfgDebug = False})+  ] -shell :: (MonadNix e m, MonadIO m, MonadException m) => Repl e m a -> m ()-shell pre = flip evalStateT initState $-    evalRepl "hnix> " cmd options completer pre+renderSetOptions :: [HelpSetOption] -> Doc ()+renderSetOptions so =+  Prettyprinter.indent 4 $+    Prettyprinter.vsep $+      (\h ->+        Prettyprinter.pretty (helpSetOptionName h) <> space+        <> helpSetOptionSyntax h+        <> Prettyprinter.line+        <> Prettyprinter.indent 4 (helpSetOptionDoc h)+      ) <$> so ----------------------------------------------------------------------------------- Toplevel--------------------------------------------------------------------------------+help :: (MonadNix e t f m, MonadIO m)+     => HelpOptions e t f m+     -> Text+     -> Repl e t f m ()+help hs _ = do+  liftIO $ putStrLn "Available commands:\n"+  traverse_+    (\h ->+      liftIO .+        Text.putStrLn .+          Prettyprinter.renderStrict .+            Prettyprinter.layoutPretty Prettyprinter.defaultLayoutOptions $+              ":"+              <> Prettyprinter.pretty (helpOptionName h) <> space+              <> helpOptionSyntax h+              <> Prettyprinter.line+              <> Prettyprinter.indent 4 (helpOptionDoc h)+    )+    hs --- main :: IO ()--- main = do---   args <- getArgs---   case args of---     []      -> shell (return ())---     [fname] -> shell (load [fname])---     ["test", fname] -> shell (load [fname] >> browse [] >> quit ())---     _ -> putStrLn "invalid arguments"+options+  :: (MonadNix e t f m, MonadIO m)+  => Console.Options (Repl e t f m)+options = (\ h -> (toString $ helpOptionName h, helpOptionFunction h)) <$> helpOptions
− package.yaml
@@ -1,214 +0,0 @@-name:       hnix-version:    0.5.2-synopsis:   Haskell implementation of the Nix language-github:     haskell-nix/hnix-author:     John Wiegley-maintainer: johnw@newartisans.com-category:   System, Data, Nix-license:    BSD3--description:-  Haskell implementation of the Nix language.--extra-source-files:-  - LICENSE-  - README.md-  - 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:-    description: Enable full debug tracing-    manual: True-    default: False--  profiling:-    description: Enable profiling-    manual: True-    default: False--  optimize:-    description: Enable all optimization 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:-      - -fexpose-all-unfoldings-      - -fspecialise-aggressively-      - -O2--  - 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-    - binary-    - deriving-compat           >= 0.3   && < 0.6-    - directory-    - http-types-    - http-client-    - http-client-tls-    - interpolate-    - lens-family-th-    - logict-    - megaparsec                >= 6.5   && < 7.0-    - monadlist-    - process-    - regex-tdfa-    - regex-tdfa-text-    - scientific-    - semigroups                >= 0.18  && < 0.19-    - split-    - syb-    - these-    - unix-    - vector-    - xml-  when:-    - 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-    main: Main.hs-    dependencies:-      - hnix-      - aeson-      - 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-      - directory-      - interpolate-      - process-      - split-      - tasty-      - tasty-hedgehog-      - tasty-hunit-      - tasty-th-      - unix-      - hedgehog-      - generic-random-      - Diff-      - megaparsec-      - tasty-quickcheck-      - pretty-show-    when:-      - condition: "impl(ghcjs)"-        then:-          buildable: false-        else:-          buildable: true--benchmarks:-  hnix-benchmarks:-    source-dirs: benchmarks-    main: Main.hs-    dependencies:-      - hnix-      - criterion-    when:-      - condition: "impl(ghcjs)"-        then:-          buildable: false-        else:-          buildable: true
src/Nix.hs view
@@ -1,86 +1,87 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE ViewPatterns #-}--module Nix (module Nix.Cache,-            module Nix.Exec,-            module Nix.Expr,-            module Nix.Frames,-            module Nix.Render.Frame,-            module Nix.Normal,-            module Nix.Options,-            module Nix.Parser,-            module Nix.Pretty,-            module Nix.Reduce,-            module Nix.Thunk,-            module Nix.Value,-            module Nix.XML,-            withNixContext,-            nixEvalExpr, nixEvalExprLoc, nixTracingEvalExprLoc,-            evaluateExpression, processResult) where+module Nix+  ( module Nix.Cache+  , module Nix.Exec+  , module Nix.Expr.Types+  , module Nix.Expr.Shorthands+  , module Nix.Expr.Types.Annotated+  , module Nix.Frames+  , module Nix.Render.Frame+  , module Nix.Normal+  , module Nix.Options+  , module Nix.String+  , module Nix.Parser+  , module Nix.Pretty+  , module Nix.Reduce+  , module Nix.Thunk+  , module Nix.Value+  , module Nix.XML+  , withNixContext+  , nixEvalExpr+  , nixEvalExprLoc+  , nixTracingEvalExprLoc+  , evaluateExpression+  , processResult+  )+where -import           Control.Applicative-import           Control.Arrow (second)-import           Control.Monad.Reader-import           Data.Fix-import qualified Data.HashMap.Lazy as M-import qualified Data.Text as Text-import qualified Data.Text.Read as Text+import           Nix.Prelude+import           Relude.Unsafe                  ( (!!) )+import           GHC.Err                        ( errorWithoutStackTrace )+import           Data.Fix                       ( Fix )+import qualified Data.HashMap.Lazy             as M+import qualified Data.Text                     as Text+import qualified Data.Text.Read                as Text import           Nix.Builtins import           Nix.Cache-import qualified Nix.Eval as Eval+import qualified Nix.Eval                      as Eval import           Nix.Exec-import           Nix.Expr+import           Nix.Expr.Types+import           Nix.Expr.Shorthands+import           Nix.Expr.Types.Annotated import           Nix.Frames+import           Nix.String import           Nix.Normal import           Nix.Options import           Nix.Parser import           Nix.Pretty import           Nix.Reduce import           Nix.Render.Frame-import           Nix.Scope import           Nix.Thunk-import           Nix.Utils import           Nix.Value+import           Nix.Value.Monad import           Nix.XML --- | Evaluate a nix expression in the default context-withNixContext :: forall e m r. (MonadNix e m, Has e Options)-               => Maybe FilePath -> m r -> m r-withNixContext mpath action = do-    base <- builtins-    opts :: Options <- asks (view hasLens)-    let i = value @(NValue m) @(NThunk m) @m $ nvList $-            map (value @(NValue m) @(NThunk m) @m-                     . flip nvStr mempty . Text.pack) (include opts)-    pushScope (M.singleton "__includes" i) $-        pushScopes base $ case mpath of-            Nothing -> action-            Just path -> do-                traceM $ "Setting __cur_file = " ++ show path-                let ref = value @(NValue m) @(NThunk m) @m $ nvPath path-                pushScope (M.singleton "__cur_file" ref) action- -- | This is the entry point for all evaluations, whatever the expression tree --   type. It sets up the common Nix environment and applies the --   transformations, allowing them to be easily composed.-nixEval :: (MonadNix e m, Has e Options, Functor f)-        => Maybe FilePath -> Transform f (m a) -> Alg f (m a) -> Fix f -> m a-nixEval mpath xform alg = withNixContext mpath . adi alg xform+nixEval+  :: (MonadNix e t f m, Has e Options, Functor g)+  => Transform g (m a)+  -> Alg g (m a)+  -> Maybe Path+  -> Fix g+  -> m a+nixEval transform alg mpath = withNixContext mpath . adi transform alg  -- | Evaluate a nix expression in the default context-nixEvalExpr :: forall e m. (MonadNix e m, Has e Options)-            => Maybe FilePath -> NExpr -> m (NValue m)-nixEvalExpr mpath = nixEval mpath id Eval.eval+nixEvalExpr+  :: (MonadNix e t f m, Has e Options)+  => Maybe Path+  -> NExpr+  -> m (NValue t f m)+nixEvalExpr = nixEval id Eval.eval  -- | Evaluate a nix expression in the default context-nixEvalExprLoc :: forall e m. (MonadNix e m, Has e Options)-               => Maybe FilePath -> NExprLoc -> m (NValue m)-nixEvalExprLoc mpath =-    nixEval mpath (Eval.addStackFrames @(NThunk m) . Eval.addSourcePositions)-            (Eval.eval . annotated . getCompose)+nixEvalExprLoc+  :: forall e t f m+   . (MonadNix e t f m, Has e Options)+  => Maybe Path+  -> NExprLoc+  -> m (NValue t f m)+nixEvalExprLoc =+  nixEval+    Eval.addMetaInfo+    Eval.evalContent  -- | Evaluate a nix expression with tracing in the default context. Note that --   this function doesn't do any tracing itself, but 'evalExprLoc' will be@@ -88,64 +89,71 @@ --   'MonadNix'). All this function does is provide the right type class --   context. nixTracingEvalExprLoc-    :: forall e m. (MonadNix e m, Has e Options, MonadIO m, Alternative m)-    => Maybe FilePath -> NExprLoc -> m (NValue m)+  :: (MonadNix e t f m, Has e Options, MonadIO m, Alternative m)+  => Maybe Path+  -> NExprLoc+  -> m (NValue t f m) nixTracingEvalExprLoc mpath = withNixContext mpath . evalExprLoc  evaluateExpression-    :: (MonadNix e m, Has e Options)-    => Maybe FilePath-    -> (Maybe FilePath -> NExprLoc -> m (NValue m))-    -> (NValue m -> m a)-    -> NExprLoc-    -> m a-evaluateExpression mpath evaluator handler expr = do-    opts :: Options <- asks (view hasLens)-    args <- traverse (traverse eval') $-        map (second parseArg) (arg opts) ++-        map (second mkStr) (argstr opts)-    compute evaluator expr (argmap args) handler-  where-    parseArg s = case parseNixText s of-        Success x -> x-        Failure err -> errorWithoutStackTrace (show err)--    eval' = (normalForm =<<) . nixEvalExpr mpath--    argmap args = embed $ Fix $ NVSetF (M.fromList args) mempty+  :: (MonadNix e t f m, Has e Options)+  => Maybe Path+  -> (Maybe Path -> NExprLoc -> m (NValue t f m))+  -> (NValue t f m -> m a)+  -> NExprLoc+  -> m a+evaluateExpression mpath evaluator handler expr =+  do+    opts <- askOptions+    (coerce -> args) <-+      (traverse . traverse)+        eval'+        $  (second parseArg <$> getArg    opts)+        <> (second mkStr    <$> getArgstr opts)+    f <- evaluator mpath expr+    f' <- demand f+    val <-+      case f' of+        NVClosure _ g -> g $ NVSet mempty $ M.fromList args+        _             -> pure f+    processResult handler val+ where+  parseArg s =+    either+      (errorWithoutStackTrace . show)+      id+      (parseNixText s) -    compute ev x args p = do-         f <- ev mpath x-         processResult p =<< case f of-             NVClosure _ g -> g args-             _ -> pure f+  eval' = normalForm <=< nixEvalExpr mpath -processResult :: forall e m a. (MonadNix e m, Has e Options)-              => (NValue m -> m a) -> NValue m -> m a-processResult h val = do-    opts :: Options <- asks (view hasLens)-    case attr opts of-        Nothing -> h val-        Just (Text.splitOn "." -> keys) -> go keys val-  where-    go :: [Text.Text] -> NValue m -> m a-    go [] v = h v-    go ((Text.decimal -> Right (n,"")):ks) v = case v of-        NVList xs -> case ks of-            [] -> force @(NValue m) @(NThunk m) (xs !! n) h-            _  -> force (xs !! n) (go ks)-        _ -> errorWithoutStackTrace $-                "Expected a list for selector '" ++ show n-                    ++ "', but got: " ++ show v-    go (k:ks) v = case v of-        NVSet xs _ -> case M.lookup k xs of-            Nothing ->-                errorWithoutStackTrace $-                    "Set does not contain key '"-                        ++ Text.unpack k ++ "'"-            Just v' -> case ks of-                [] -> force v' h-                _  -> force v' (go ks)-        _ -> errorWithoutStackTrace $-            "Expected a set for selector '" ++ Text.unpack k-                ++ "', but got: " ++ show v+processResult+  :: forall e t f m a+   . (MonadNix e t f m, Has e Options)+  => (NValue t f m -> m a)+  -> NValue t f m+  -> m a+processResult h val =+  do+    opts <- askOptions+    maybe+      (h val)+      (\ (coerce . Text.splitOn "." -> keys) -> processKeys keys val)+      (getAttr opts)+ where+  processKeys :: [VarName] -> NValue t f m -> m a+  processKeys kys v =+    handlePresence+      (h v)+      (\ ((k : ks) :: [VarName]) ->+        do+          v' <- demand v+          case (k, v') of+            (Text.decimal . coerce -> Right (n,""), NVList xs) -> processKeys ks $ xs !! n+            (_,         NVSet _ xs) ->+              maybe+                (errorWithoutStackTrace $ "Set does not contain key ''" <> show k <> "''.")+                (processKeys ks)+                (M.lookup k xs)+            (_, _) -> errorWithoutStackTrace $ "Expected a set or list for selector '" <> show k <> "', but got: " <> show v+      )+      kys
src/Nix/Atoms.hs view
@@ -1,43 +1,70 @@-{-# LANGUAGE CPP            #-}-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE OverloadedStrings #-}+{-# language CPP               #-}+{-# language DeriveAnyClass    #-}  module Nix.Atoms where -#ifdef MIN_VERSION_serialise-import Codec.Serialise-#endif-import Control.DeepSeq-import Data.Data-import Data.Hashable-import Data.Text (Text, pack)-import GHC.Generics+import           Nix.Prelude+import           Codec.Serialise                ( Serialise ) --- | Atoms are values that evaluate to themselves. This means that+import           Data.Data                      ( Data)+import           Data.Fixed                     ( mod' )+import           Data.Binary                    ( Binary )+import           Data.Aeson.Types               ( FromJSON+                                                , ToJSON+                                                )+--  2021-08-01: NOTE: Check the order effectiveness of NAtom constructors.++-- | Atoms are values that evaluate to themselves.+-- In other words - this is a constructors that are literals in Nix.+-- This means that -- they appear in both the parsed AST (in the form of literals) and--- the evaluated form.+-- the evaluated form as themselves.+-- Once HNix parsed or evaluated into atom - that is a literal+-- further after, for any further evaluation it is in all cases stays+-- constantly itself.+-- "atom", Ancient Greek \( atomos \) - "indivisible" particle,+-- indivisible expression. data NAtom+  -- | An URI like @https://example.com@.+  = NURI Text   -- | An integer. The c nix implementation currently only supports   -- integers that fit in the range of 'Int64'.-  = NInt Integer+  | NInt Integer   -- | A floating point number   | NFloat Float-  -- | Booleans.+  -- | Booleans. @false@ or @true@.   | NBool Bool-  -- | Null values. There's only one of this variant.+  -- | Null values. There's only one of this variant: @null@.   | NNull-  deriving (Eq, Ord, Generic, Typeable, Data, Show, Read, NFData,-            Hashable)+  deriving+    ( Eq+    , Ord+    , Generic+    , Typeable+    , Data+    , Show+    , Read+    , NFData+    , Hashable+    ) -#ifdef MIN_VERSION_serialise instance Serialise NAtom-#endif --- | Translate an atom into its nix representation.+instance Binary NAtom+instance ToJSON NAtom+instance FromJSON NAtom++-- | Translate an atom into its Nix representation. atomText :: NAtom -> Text-atomText (NInt i)   = pack (show i)-atomText (NFloat f) = pack (show f)-atomText (NBool b)  = if b then "true" else "false"+atomText (NURI   t) = t+atomText (NInt   i) = show i+atomText (NFloat f) = showNixFloat f+ where+  showNixFloat :: Float -> Text+  showNixFloat x =+    bool+      (show x)+      (show (truncate x :: Int))+      (x `mod'` 1 == 0)+atomText (NBool  b) = if b then "true" else "false" atomText NNull      = "null"
src/Nix/Builtins.hs view
@@ -1,1048 +1,2122 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE MultiWayIf #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE PackageImports #-}-{-# LANGUAGE PartialTypeSignatures #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE ViewPatterns #-}--{-# OPTIONS_GHC -Wno-missing-signatures #-}-{-# OPTIONS_GHC -fno-warn-name-shadowing #-}--module Nix.Builtins (builtins) where--import           Control.Monad-import           Control.Monad.Catch-import           Control.Monad.ListM (sortByM)-import           Control.Monad.Reader (asks)---- 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 qualified Data.ByteString.Lazy as LBS-import           Data.Char (isDigit)-import           Data.Coerce-import           Data.Fix-import           Data.Foldable (foldrM)-import qualified Data.HashMap.Lazy as M-import           Data.List-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-import qualified Data.Text.Lazy as LazyText-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           Nix.Atoms-import           Nix.Convert-import           Nix.Effects-import qualified Nix.Eval as Eval-import           Nix.Exec-import           Nix.Expr.Types-import           Nix.Expr.Types.Annotated-import           Nix.Frames-import           Nix.Normal-import           Nix.Options-import           Nix.Parser-import           Nix.Render-import           Nix.Scope-import           Nix.Thunk-import           Nix.Utils-import           Nix.Value-import           Nix.XML-import           System.FilePath-import           System.Posix.Files-import           Text.Regex.TDFA--builtins :: (MonadNix e m, Scoped e (NThunk m) m)-         => m (Scopes m (NThunk m))-builtins = do-    ref <- thunk $ flip nvSet M.empty <$> buildMap-    lst <- ([("builtins", ref)] ++) <$> topLevelBuiltins-    pushScope (M.fromList lst) currentScopes-  where-    buildMap = M.fromList . map mapping <$> builtinsList-    topLevelBuiltins = map mapping <$> fullBuiltinsList--    fullBuiltinsList = map go <$> builtinsList-      where-        go b@(Builtin TopLevel _) = b-        go (Builtin Normal (name, builtin)) =-            Builtin TopLevel ("__" <> name, builtin)--data BuiltinType = Normal | TopLevel-data Builtin m = Builtin-    { _kind   :: BuiltinType-    , mapping :: (Text, NThunk m)-    }--valueThunk :: forall e m. MonadNix e m => NValue m -> NThunk m-valueThunk = value @_ @_ @m--force' :: forall e m. MonadNix e m => NThunk m -> m (NValue m)-force' = force ?? pure--builtinsList :: forall e m. MonadNix e m => m [ Builtin m ]-builtinsList = sequence [-      do version <- toValue ("2.0" :: Text)-         pure $ Builtin Normal ("nixVersion", version)--    , do version <- toValue (5 :: Int)-         pure $ Builtin Normal ("langVersion", version)--    , add0 Normal   "nixPath"                    nixPath-    , add  TopLevel "abort"                      throw_ -- for now-    , add2 Normal   "add"                        add_-    , add2 Normal   "all"                        all_-    , add2 Normal   "any"                        any_-    , add  Normal   "attrNames"                  attrNames-    , add  Normal   "attrValues"                 attrValues-    , add  TopLevel "baseNameOf"                 baseNameOf-    , add2 Normal   "catAttrs"                   catAttrs-    , add2 Normal   "compareVersions"            compareVersions_-    , add  Normal   "concatLists"                concatLists-    , add' Normal   "concatStringsSep"           (arity2 Text.intercalate)-    , add0 Normal   "currentSystem"              currentSystem-    , add0 Normal   "currentTime"                currentTime_-    , add2 Normal   "deepSeq"                    deepSeq--    , 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_-    , add2 Normal   "elem"                       elem_-    , add2 Normal   "elemAt"                     elemAt_-    , add  Normal   "exec"                       exec_-    , add0 Normal   "false"                      (return $ nvConstant $ NBool False)-    , add  Normal   "fetchTarball"               fetchTarball-    , add  Normal   "fetchurl"                   fetchurl-    , add2 Normal   "filter"                     filter_-    , add3 Normal   "foldl'"                     foldl'_-    , add  Normal   "fromJSON"                   fromJSON-    , add  Normal   "functionArgs"               functionArgs-    , add2 Normal   "genList"                    genList-    , add  Normal   "genericClosure"             genericClosure-    , add2 Normal   "getAttr"                    getAttr-    , add  Normal   "getEnv"                     getEnv_-    , add2 Normal   "hasAttr"                    hasAttr-    , add  Normal   "hasContext"                 hasContext-    , add' Normal   "hashString"                 hashString-    , add  Normal   "head"                       head_-    , add  TopLevel "import"                     import_-    , add2 Normal   "intersectAttrs"             intersectAttrs-    , add  Normal   "isAttrs"                    isAttrs-    , add  Normal   "isBool"                     isBool-    , add  Normal   "isFloat"                    isFloat-    , add  Normal   "isFunction"                 isFunction-    , add  Normal   "isInt"                      isInt-    , add  Normal   "isList"                     isList-    , add  TopLevel "isNull"                     isNull-    , add  Normal   "isString"                   isString-    , add  Normal   "length"                     length_-    , add2 Normal   "lessThan"                   lessThan-    , add  Normal   "listToAttrs"                listToAttrs-    , add2 TopLevel "map"                        map_-    , add2 Normal   "match"                      match_-    , add2 Normal   "mul"                        mul_-    , add0 Normal   "null"                       (return $ nvConstant NNull)-    , add  Normal   "parseDrvName"               parseDrvName-    , add2 Normal   "partition"                  partition_-    , add  Normal   "pathExists"                 pathExists_-    , 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-    , add2 Normal   "seq"                        seq_-    , add2 Normal   "sort"                       sort_-    , add2 Normal   "split"                      split_-    , add  Normal   "splitVersion"               splitVersion_-    , add0 Normal   "storeDir"                   (return $ nvPath "/nix/store")-    , add' Normal   "stringLength"               (arity1 Text.length)-    , add' Normal   "sub"                        (arity2 ((-) @Integer))-    , add' Normal   "substring"                  substring-    , add  Normal   "tail"                       tail_-    , add0 Normal   "true"                       (return $ nvConstant $ NBool True)-    , add  TopLevel "throw"                      throw_-    , 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_-    , add2 TopLevel "trace"                      trace_-    , add  Normal   "tryEval"                    tryEval-    , add  Normal   "typeOf"                     typeOf-    , add  Normal   "unsafeDiscardStringContext" unsafeDiscardStringContext-    , add2 Normal   "unsafeGetAttrPos"           unsafeGetAttrPos-    , add  Normal   "valueSize"                  getRecursiveSize-  ]-  where-    wrap t n f = Builtin t (n, f)--    arity1 f = Prim . pure . f-    arity2 f = ((Prim . pure) .) . f--    mkThunk n = thunk . withFrame Info-        (ErrorCall $ "While calling builtin " ++ Text.unpack n ++ "\n")--    add0 t n v = wrap t n <$> mkThunk n v-    add  t n v = wrap t n <$> mkThunk n (builtin  (Text.unpack n) v)-    add2 t n v = wrap t n <$> mkThunk n (builtin2 (Text.unpack n) v)-    add3 t n v = wrap t n <$> mkThunk n (builtin3 (Text.unpack n) v)--    add' :: ToBuiltin m a => BuiltinType -> Text -> a -> m (Builtin m)-    add' t n v = wrap t n <$> mkThunk n (toBuiltin (Text.unpack n) v)---- Primops--foldNixPath :: forall e m r. MonadNix e m-            => (FilePath -> Maybe String -> r -> m r) -> r -> m r-foldNixPath f z = do-    mres <- lookupVar @_ @(NThunk m) "__includes"-    dirs <- case mres of-        Nothing -> return []-        Just v  -> fromNix @[Text] v-    menv <- getEnvVar "NIX_PATH"-    foldrM go z $ dirs ++ case menv of-        Nothing -> []-        Just str -> Text.splitOn ":" (Text.pack str)-  where-    go x rest = case Text.splitOn "=" x of-        [p]    -> f (Text.unpack p) Nothing rest-        [n, p] -> f (Text.unpack p) (Just (Text.unpack n)) rest-        _ -> throwError $ ErrorCall $ "Unexpected entry in NIX_PATH: " ++ show x--nixPath :: MonadNix e m => m (NValue m)-nixPath = fmap nvList $ flip foldNixPath [] $ \p mn rest ->-    pure $ valueThunk-        (flip nvSet mempty $ M.fromList-            [ ("path",   valueThunk $ nvPath p)-            , ("prefix", valueThunk $-                   nvStr (Text.pack (fromMaybe "" mn)) mempty) ]) : rest--toString :: MonadNix e m => m (NValue m) -> m (NValue m)-toString str = str >>= coerceToString False >>= toNix . Text.pack--hasAttr :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)-hasAttr x y =-    fromValue @Text x >>= \key ->-    fromValue @(AttrSet (NThunk m), AttrSet SourcePos) y >>= \(aset, _) ->-        toNix $ M.member key aset--attrsetGet :: MonadNix e m => Text -> AttrSet t -> m t-attrsetGet k s = case M.lookup k s of-    Just v -> pure v-    Nothing ->-        throwError $ ErrorCall $ "Attribute '" ++ Text.unpack k ++ "' required"--hasContext :: MonadNix e m => m (NValue m) -> m (NValue m)-hasContext =-    toNix . not . null . (appEndo ?? []) . snd <=< fromValue @(Text, DList Text)--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 key _, NVSet _ apos) -> case M.lookup 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--- of the list.-length_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-length_ = toValue . (length :: [NThunk m] -> Int) <=< fromValue--add_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)-add_ x y = x >>= \x' -> y >>= \y' -> case (x', y') of-    (NVConstant (NInt x),   NVConstant (NInt y))   ->-        toNix ( x + y :: 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)-    (_, _) ->-        throwError $ Addition x' y'--mul_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)-mul_ x y = x >>= \x' -> y >>= \y' -> case (x', y') of-    (NVConstant (NInt x),   NVConstant (NInt y))   ->-        toNix ( x * y :: 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)-    (_, _) ->-        throwError $ Multiplication x' y'--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))   | y /= 0 ->-        toNix (floor (fromInteger x / fromInteger y :: Double) :: Integer)-    (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'--anyM :: Monad m => (a -> m Bool) -> [a] -> m Bool-anyM _ []       = return False-anyM p (x:xs)   = do-        q <- p x-        if q then return True-             else anyM p xs--any_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)-any_ fun xs = fun >>= \f ->-    toNix <=< anyM fromValue <=< mapM ((f `callFunc`) . force')-          <=< fromValue $ xs--allM :: Monad m => (a -> m Bool) -> [a] -> m Bool-allM _ []       = return True-allM p (x:xs)   = do-        q <- p x-        if q then allM p xs-             else return False--all_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)-all_ fun xs = fun >>= \f ->-    toNix <=< allM fromValue <=< mapM ((f `callFunc`) . force')-          <=< fromValue $ xs--foldl'_ :: forall e m. MonadNix e m-        => m (NValue m) -> m (NValue m) -> m (NValue m) -> m (NValue m)-foldl'_ fun z xs =-    fun >>= \f -> fromValue @[NThunk m] xs >>= foldl' (go f) z-  where-    go f b a = f `callFunc` b >>= (`callFunc` force' a)--head_ :: MonadNix e m => m (NValue m) -> m (NValue m)-head_ = fromValue >=> \case-    [] -> throwError $ ErrorCall "builtins.head: empty list"-    h:_ -> force' h--tail_ :: MonadNix e m => m (NValue m) -> m (NValue m)-tail_ = fromValue >=> \case-    [] -> throwError $ ErrorCall "builtins.tail: empty list"-    _:t -> return $ nvList t--data VersionComponent-   = VersionComponent_Pre -- ^ The string "pre"-   | VersionComponent_String Text -- ^ A string other than "pre"-   | VersionComponent_Number Integer -- ^ A number-   deriving (Show, Read, Eq, Ord)--versionComponentToString :: VersionComponent -> Text-versionComponentToString = \case-  VersionComponent_Pre -> "pre"-  VersionComponent_String s -> s-  VersionComponent_Number n -> Text.pack $ show n---- | Based on https://github.com/NixOS/nix/blob/4ee4fda521137fed6af0446948b3877e0c5db803/src/libexpr/names.cc#L44-versionComponentSeparators :: String-versionComponentSeparators = ".-"--splitVersion :: Text -> [VersionComponent]-splitVersion s = case Text.uncons s of-    Nothing -> []-    Just (h, t)-      | h `elem` versionComponentSeparators -> splitVersion t-      | isDigit h ->-          let (digits, rest) = Text.span isDigit s-          in VersionComponent_Number (read $ Text.unpack digits) : splitVersion rest-      | otherwise ->-          let (chars, rest) = Text.span (\c -> not $ isDigit c || c `elem` versionComponentSeparators) s-              thisComponent = case chars of-                  "pre" -> VersionComponent_Pre-                  x -> VersionComponent_String x-          in thisComponent : splitVersion rest--splitVersion_ :: MonadNix e m => m (NValue m) -> m (NValue m)-splitVersion_ = fromValue >=> \s -> do-    let vals = flip map (splitVersion s) $ \c ->-            valueThunk $ nvStr (versionComponentToString c) mempty-    return $ nvList vals--compareVersions :: Text -> Text -> Ordering-compareVersions s1 s2 =-    mconcat $ alignWith f (splitVersion s1) (splitVersion s2)-  where-    z = VersionComponent_String ""-    f = uncurry compare . fromThese z z--compareVersions_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)-compareVersions_ t1 t2 =-    fromValue t1 >>= \s1 ->-    fromValue t2 >>= \s2 ->-        return $ nvConstant $ NInt $ case compareVersions s1 s2 of-            LT -> -1-            EQ -> 0-            GT -> 1--splitDrvName :: Text -> (Text, Text)-splitDrvName s =-    let sep = "-"-        pieces = Text.splitOn sep s-        isFirstVersionPiece p = case Text.uncons p of-            Just (h, _) | isDigit h -> True-            _ -> False-        -- Like 'break', but always puts the first item into the first result-        -- list-        breakAfterFirstItem :: (a -> Bool) -> [a] -> ([a], [a])-        breakAfterFirstItem f = \case-            h : t ->-                let (a, b) = break f t-                in (h : a, b)-            [] -> ([], [])-        (namePieces, versionPieces) =-          breakAfterFirstItem isFirstVersionPiece pieces-    in (Text.intercalate sep namePieces, Text.intercalate sep versionPieces)--parseDrvName :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-parseDrvName = fromValue >=> \(s :: Text) -> do-    let (name :: Text, version :: Text) = splitDrvName s-    -- jww (2018-04-15): There should be an easier way to write this.-    (toValue =<<) $ sequence $ M.fromList-        [ ("name" :: Text, thunk (toValue @_ @_ @(NValue m) name))-        , ("version",     thunk (toValue version)) ]--match_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)-match_ pat str =-    fromValue pat >>= \p ->-    fromValue str >>= \s -> do-        let re = makeRegex (encodeUtf8 p) :: Regex-        case matchOnceText re (encodeUtf8 s) of-            Just ("", sarr, "") -> do-                let s = map fst (elems sarr)-                nvList <$> traverse (toValue . decodeUtf8)-                    (if length s > 1 then tail s else s)-            _ -> pure $ nvConstant NNull--split_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)-split_ pat str =-    fromValue pat >>= \p ->-    fromValue str >>= \s -> do-        let re = makeRegex (encodeUtf8 p) :: Regex-            haystack = encodeUtf8 s-        return $ nvList $-            splitMatches 0 (map elems $ matchAllText re haystack) haystack--splitMatches-  :: forall e m. MonadNix e m-  => Int-  -> [[(ByteString, (Int, Int))]]-  -> ByteString-  -> [NThunk m]-splitMatches _ [] haystack = [thunkStr haystack]-splitMatches _ ([]:_) _ = error "Error in splitMatches: this should never happen!"-splitMatches numDropped (((_,(start,len)):captures):mts) haystack =-    thunkStr before : caps : splitMatches (numDropped + relStart + len) mts (B.drop len rest)-  where-    relStart = max 0 start - numDropped-    (before,rest) = B.splitAt relStart haystack-    caps = valueThunk $ nvList (map f captures)-    f (a,(s,_)) = if s < 0 then valueThunk (nvConstant NNull) else thunkStr a--thunkStr s = valueThunk (nvStr (decodeUtf8 s) mempty)--substring :: MonadNix e m => Int -> Int -> Text -> Prim m Text-substring start len str = Prim $-    if start < 0 --NOTE: negative values of 'len' are OK-    then throwError $ ErrorCall $ "builtins.substring: negative start position: " ++ show start-    else pure $ Text.take len $ Text.drop start str--attrNames :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-attrNames = fromValue @(ValueSet m) >=> toNix . sort . M.keys--attrValues :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-attrValues = fromValue @(ValueSet m) >=>-    toValue . fmap snd . sortOn (fst @Text @(NThunk m)) . M.toList--map_ :: forall e m. MonadNix e m-     => m (NValue m) -> m (NValue m) -> m (NValue m)-map_ fun xs = fun >>= \f ->-    toNix <=< traverse (thunk . withFrame Debug-                                    (ErrorCall "While applying f in map:\n")-                              . (f `callFunc`) . force')-          <=< fromValue @[NThunk m] $ xs--filter_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)-filter_ fun xs = fun >>= \f ->-    toNix <=< filterM (fromValue <=< callFunc f . force')-          <=< fromValue @[NThunk m] $ xs--catAttrs :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)-catAttrs attrName xs =-    fromValue @Text attrName >>= \n ->-    fromValue @[NThunk m] xs >>= \l ->-        fmap (nvList . catMaybes) $-            forM l $ fmap (M.lookup n) . fromValue--baseNameOf :: MonadNix e m => m (NValue m) -> m (NValue m)-baseNameOf x = x >>= \case-    NVStr path ctx -> pure $ nvStr (Text.pack $ takeFileName $ Text.unpack path) ctx-    NVPath path -> pure $ nvPath $ takeFileName path-    v -> throwError $ ErrorCall $ "dirOf: expected string or path, got " ++ show v--dirOf :: MonadNix e m => m (NValue m) -> m (NValue m)-dirOf x = x >>= \case-    NVStr path ctx -> pure $ nvStr (Text.pack $ takeDirectory $ Text.unpack path) ctx-    NVPath path -> pure $ nvPath $ takeDirectory path-    v -> throwError $ ErrorCall $ "dirOf: expected string or path, got " ++ show v---- jww (2018-04-28): This should only be a string argument, and not coerced?-unsafeDiscardStringContext :: MonadNix e m => m (NValue m) -> m (NValue m)-unsafeDiscardStringContext = fromValue @Text >=> toNix--seq_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)-seq_ a b = a >> b--deepSeq :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)-deepSeq a b = do-    -- We evaluate 'a' only for its effects, so data cycles are ignored.-    _ <- normalFormBy (forceEffects . coerce . _baseThunk) 0 =<< a--    -- Then we evaluate the other argument to deepseq, thus this function-    -- should always produce a result (unlike applying 'deepseq' on infinitely-    -- recursive data structures in Haskell).-    b--elem_ :: forall e m. MonadNix e m-      => m (NValue m) -> m (NValue m) -> m (NValue m)-elem_ x xs = x >>= \x' ->-    toValue <=< anyM (valueEq x' <=< force') <=< fromValue @[NThunk m] $ xs--elemAt :: [a] -> Int -> Maybe a-elemAt ls i = case drop i ls of-   [] -> Nothing-   a:_ -> Just a--elemAt_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)-elemAt_ xs n = fromValue n >>= \n' -> fromValue xs >>= \xs' ->-    case elemAt xs' n' of-      Just a -> force' a-      Nothing -> throwError $ ErrorCall $ "builtins.elem: Index " ++ show n'-          ++ " too large for list of length " ++ show (length xs')--genList :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)-genList generator = fromValue @Integer >=> \n ->-    if n >= 0-    then generator >>= \f ->-        toNix =<< forM [0 .. n - 1] (\i -> thunk $ f `callFunc` toNix i)-    else throwError $ ErrorCall $ "builtins.genList: Expected a non-negative number, got "-             ++ show n--genericClosure :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-genericClosure = fromValue @(AttrSet (NThunk m)) >=> \s ->-    case (M.lookup "startSet" s, M.lookup "operator" s) of-      (Nothing, Nothing) ->-          throwError $ ErrorCall $-              "builtins.genericClosure: "-                  ++ "Attributes 'startSet' and 'operator' required"-      (Nothing, Just _) ->-          throwError $ ErrorCall $-              "builtins.genericClosure: Attribute 'startSet' required"-      (Just _, Nothing) ->-          throwError $ ErrorCall $-              "builtins.genericClosure: Attribute 'operator' required"-      (Just startSet, Just operator) ->-          fromValue @[NThunk m] startSet >>= \ss ->-          force operator $ \op ->-              toValue @[NThunk m] =<< snd <$> go op ss S.empty-  where-    go :: NValue m -> [NThunk m] -> Set (NValue m)-       -> m (Set (NValue m), [NThunk m])-    go _ [] ks = pure (ks, [])-    go op (t:ts) ks =-        force t $ \v -> fromValue @(AttrSet (NThunk m)) t >>= \s ->-            case M.lookup "key" s of-                Nothing ->-                    throwError $ ErrorCall $-                        "builtins.genericClosure: Attribute 'key' required"-                Just k -> force k $ \k' ->-                    if S.member k' ks-                        then go op ts ks-                        else do-                            ys <- fromValue @[NThunk m] =<< (op `callFunc` pure v)-                            case S.toList ks of-                                []  -> checkComparable k' k'-                                j:_ -> checkComparable k' j-                            fmap (t:) <$> go op (ts ++ ys) (S.insert k' ks)--replaceStrings :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m) -> m (NValue m)-replaceStrings tfrom tto ts =-    fromNix tfrom >>= \(from :: [Text]) ->-    fromNix tto   >>= \(to   :: [Text]) ->-    fromValue ts  >>= \(s    :: Text) -> do-        when (length from /= length to) $-            throwError $ ErrorCall $-                "'from' and 'to' arguments to 'replaceStrings'"-                    ++ " have different lengths"-        let lookupPrefix s = do-                (prefix, replacement) <--                    find ((`Text.isPrefixOf` s) . fst) $ zip from to-                let rest = Text.drop (Text.length prefix) s-                return (prefix, replacement, rest)-            finish = LazyText.toStrict . Builder.toLazyText-            go orig result = case lookupPrefix orig of-                Nothing -> case Text.uncons orig of-                    Nothing -> finish result-                    Just (h, t) -> go t $ result <> Builder.singleton h-                Just (prefix, replacement, rest) -> case prefix of-                    "" -> case Text.uncons rest of-                        Nothing -> finish $ result <> Builder.fromText replacement-                        Just (h, t) -> go t $ mconcat-                            [ result-                            , Builder.fromText replacement-                            , Builder.singleton h-                            ]-                    _ -> go rest $ result <> Builder.fromText replacement-        toNix $ go s mempty--removeAttrs :: forall e m. MonadNix e m-            => m (NValue m) -> m (NValue m) -> m (NValue m)-removeAttrs set = fromNix >=> \(toRemove :: [Text]) ->-    fromValue @(AttrSet (NThunk m),-                AttrSet SourcePos) set >>= \(m, p) ->-        toNix (go m toRemove, go p toRemove)-  where-    go = foldl' (flip M.delete)--intersectAttrs :: forall e m. MonadNix e m-               => m (NValue m) -> m (NValue m) -> m (NValue m)-intersectAttrs set1 set2 =-    fromValue @(AttrSet (NThunk m),-                AttrSet SourcePos) set1 >>= \(s1, p1) ->-    fromValue @(AttrSet (NThunk m),-                AttrSet SourcePos) set2 >>= \(s2, p2) ->-        return $ nvSet (s2 `M.intersection` s1) (p2 `M.intersection` p1)--functionArgs :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-functionArgs fun = fun >>= \case-    NVClosure p _ -> toValue @(AttrSet (NThunk m)) $-        valueThunk . nvConstant . NBool <$>-            case p of-                Param name -> M.singleton name False-                ParamSet s _ _ -> isJust <$> M.fromList s-    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--pathExists_ :: MonadNix e m => m (NValue m) -> m (NValue m)-pathExists_ path = path >>= \case-    NVPath p  -> toNix =<< pathExists p-    NVStr s _ -> toNix =<< pathExists (Text.unpack s)-    v -> throwError $ ErrorCall $-            "builtins.pathExists: expected path, got " ++ show v--hasKind :: forall a e m. (MonadNix e m, FromValue a m (NValue m))-        => m (NValue m) -> m (NValue m)-hasKind = fromValueMay >=> toNix . \case Just (_ :: a) -> True; _ -> False--isAttrs :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-isAttrs = hasKind @(ValueSet m)--isList :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-isList = hasKind @[NThunk m]--isString :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-isString = hasKind @Text--isInt :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-isInt = hasKind @Int--isFloat :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-isFloat = hasKind @Float--isBool :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-isBool = hasKind @Bool--isNull :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-isNull = hasKind @()--isFunction :: MonadNix e m => m (NValue m) -> m (NValue m)-isFunction func = func >>= \case-    NVClosure {} -> toValue True-    _ -> toValue False--throw_ :: MonadNix e m => m (NValue m) -> m (NValue m)-throw_ = fromValue >=> throwError . ErrorCall . Text.unpack--import_ :: MonadNix e m => m (NValue m) -> m (NValue m)-import_ = fromValue >=> importPath M.empty . getPath--scopedImport :: forall e m. MonadNix e m-             => m (NValue m) -> m (NValue m) -> m (NValue m)-scopedImport aset path =-    fromValue aset >>= \s ->-    fromValue   path >>= \p -> importPath @m s (getPath p)--getEnv_ :: MonadNix e m => m (NValue m) -> m (NValue m)-getEnv_ = fromValue >=> \s -> do-    mres <- getEnvVar (Text.unpack s)-    toNix $ case mres of-        Nothing -> ""-        Just v  -> Text.pack v--sort_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)-sort_ comparator xs = comparator >>= \comp ->-    fromValue xs >>= sortByM (cmp comp) >>= toValue-  where-    cmp f a b = do-        isLessThan <- f `callFunc` force' a >>= (`callFunc` force' b)-        fromValue isLessThan >>= \case-            True -> pure LT-            False -> do-                isGreaterThan <- f `callFunc` force' b >>= (`callFunc` force' a)-                fromValue isGreaterThan <&> \case-                    True  -> GT-                    False -> EQ--lessThan :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)-lessThan ta tb = ta >>= \va -> tb >>= \vb -> do-    let badType = throwError $ ErrorCall $-            "builtins.lessThan: expected two numbers or two strings, "-                ++ "got " ++ show va ++ " and " ++ show vb-    nvConstant . NBool <$> case (va, vb) of-        (NVConstant ca, NVConstant cb) -> case (ca, cb) of-            (NInt   a, NInt   b) -> pure $ a < b-            (NFloat a, NInt   b) -> pure $ a < fromInteger b-            (NInt   a, NFloat b) -> pure $ fromInteger a < b-            (NFloat a, NFloat b) -> pure $ a < b-            _ -> badType-        (NVStr a _, NVStr b _) -> pure $ a < b-        _ -> badType--concatLists :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-concatLists = fromValue @[NThunk m]-    >=> mapM (fromValue @[NThunk m] >=> pure)-    >=> toValue . concat--listToAttrs :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-listToAttrs = fromValue @[NThunk m] >=> \l ->-    fmap (flip nvSet M.empty . M.fromList . reverse) $-        forM l $ fromValue @(AttrSet (NThunk m)) >=> \s -> do-            name <- attrsetGet "name" s-            val  <- attrsetGet "value" s-            fromValue name <&> (, val)--hashString :: MonadNix e m => Text -> Text -> Prim m Text-hashString algo s = Prim $ do-    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--placeHolder :: MonadNix e m => m (NValue m) -> m (NValue m)-placeHolder = fromValue @Text >=> \_ -> do-    h <- runPrim (hashString "sha256" "fdasdfas")-    toNix h--absolutePathFromValue :: MonadNix e m => NValue m -> m FilePath-absolutePathFromValue = \case-    NVStr pathText _ -> do-        let path = Text.unpack pathText-        unless (isAbsolute path) $-            throwError $ ErrorCall $ "string " ++ show path ++ " doesn't represent an absolute path"-        pure path-    NVPath path -> pure path-    v -> throwError $ ErrorCall $ "expected a path, got " ++ show v--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 name _) -> do-          mres <- findPath x (Text.unpack name)-          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-   | FileTypeSymlink-   | FileTypeUnknown-   deriving (Show, Read, Eq, Ord)--instance Applicative m => ToNix FileType m (NValue m) where-    toNix = toNix . \case-        FileTypeRegular   -> "regular" :: Text-        FileTypeDirectory -> "directory"-        FileTypeSymlink   -> "symlink"-        FileTypeUnknown   -> "unknown"--readDir_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-readDir_ pathThunk = do-    path  <- absolutePathFromValue =<< pathThunk-    items <- listDirectory path-    itemsWithTypes <- forM items $ \item -> do-        s <- Nix.Effects.getSymbolicLinkStatus $ path </> item-        let t = if-                | isRegularFile s  -> FileTypeRegular-                | isDirectory s    -> FileTypeDirectory-                | isSymbolicLink s -> FileTypeSymlink-                | otherwise        -> FileTypeUnknown-        pure (Text.pack item, t)-    toNix (M.fromList itemsWithTypes)--fromJSON :: MonadNix e m => m (NValue m) -> m (NValue m)-fromJSON = fromValue >=> \encoded ->-    case A.eitherDecodeStrict' @A.Value $ encodeUtf8 encoded of-        Left jsonError ->-            throwError $ ErrorCall $ "builtins.fromJSON: " ++ jsonError-        Right v -> toValue v--toXML_ :: MonadNix e m => m (NValue m) -> m (NValue m)-toXML_ v = v >>= normalForm >>= \x ->-    pure $ nvStr (Text.pack (toXML x)) mempty--typeOf :: MonadNix e m => m (NValue m) -> m (NValue m)-typeOf v = v >>= toNix @Text . \case-    NVConstant a -> case a of-        NInt _   -> "int"-        NFloat _ -> "float"-        NBool _  -> "bool"-        NNull    -> "null"-    NVStr _ _     -> "string"-    NVList _      -> "list"-    NVSet _ _     -> "set"-    NVClosure {}  -> "lambda"-    NVPath _      -> "path"-    NVBuiltin _ _ -> "lambda"-    _ -> error "Pattern synonyms obscure complete patterns"--tryEval :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-tryEval e = catch (onSuccess <$> e) (pure . onError)-  where-    onSuccess v = flip nvSet M.empty $ M.fromList-        [ ("success", valueThunk (nvConstant (NBool True)))-        , ("value", valueThunk v)-        ]--    onError :: SomeException -> NValue m-    onError _ = flip nvSet M.empty $ M.fromList-        [ ("success", valueThunk (nvConstant (NBool False)))-        , ("value", valueThunk (nvConstant (NBool False)))-        ]--trace_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)-trace_ msg action = do-  traceEffect . Text.unpack =<< fromValue @Text msg-  action--exec_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-exec_ xs = do-  ls <- fromValue @[NThunk m] xs-  xs <- traverse (fromValue @Text . force') ls-  exec (map Text.unpack xs)--fetchTarball :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)-fetchTarball v = v >>= \case-    NVSet s _ -> case M.lookup "url" s of-        Nothing -> throwError $ ErrorCall-                      "builtins.fetchTarball: Missing url attribute"-        Just url -> force url $ go (M.lookup "sha256" s)-    v@NVStr {} -> 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 uri _ -> fetch uri msha-        v -> throwError $ ErrorCall $-                "builtins.fetchTarball: Expected URI or string, got " ++ show v--{- jww (2018-04-11): This should be written using pipes in another module-    fetch :: Text -> Maybe (NThunk m) -> m (NValue m)-    fetch uri msha = case takeExtension (Text.unpack uri) of-        ".tgz" -> undefined-        ".gz"  -> undefined-        ".bz2" -> undefined-        ".xz"  -> undefined-        ".tar" -> undefined-        ext -> throwError $ ErrorCall $ "builtins.fetchTarball: Unsupported extension '"-                  ++ ext ++ "'"--}--    fetch :: Text -> Maybe (NThunk m) -> m (NValue m)-    fetch uri Nothing =-        nixInstantiateExpr $ "builtins.fetchTarball \"" ++-            Text.unpack uri ++ "\""-    fetch url (Just m) = fromValue m >>= \sha ->-        nixInstantiateExpr $ "builtins.fetchTarball { "-          ++ "url    = \"" ++ Text.unpack url ++ "\"; "-          ++ "sha256 = \"" ++ Text.unpack sha ++ "\"; }"--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 -> 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 uri _ -> getURL uri -- msha-        v -> throwError $ ErrorCall $-                 "builtins.fetchurl: Expected URI or string, got " ++ show v--partition_ :: forall e m. MonadNix e m-           => m (NValue m) -> m (NValue m) -> m (NValue m)-partition_ fun xs = fun >>= \f ->-    fromValue @[NThunk m] xs >>= \l -> do-        let match t = f `callFunc` force' t >>= fmap (, t) . fromValue-        selection <- traverse match l-        let (right, wrong) = partition fst selection-        let makeSide = valueThunk . nvList . map snd-        toValue @(AttrSet (NThunk m)) $-            M.fromList [("right", makeSide right), ("wrong", makeSide wrong)]--currentSystem :: MonadNix e m => m (NValue m)-currentSystem = do-  os <- getCurrentSystemOS-  arch <- getCurrentSystemArch-  return $ nvStr (arch <> "-" <> os) mempty--currentTime_ :: MonadNix e m => m (NValue m)-currentTime_ = do-    opts :: Options <- asks (view hasLens)-    toNix @Integer $ round $ Time.utcTimeToPOSIXSeconds (currentTime opts)--derivationStrict_ :: MonadNix e m => m (NValue m) -> m (NValue m)-derivationStrict_ = (>>= derivationStrict)--newtype Prim m a = Prim { runPrim :: m a }---- | Types that support conversion to nix in a particular monad-class ToBuiltin m a | a -> m where-    toBuiltin :: String -> a -> m (NValue m)--instance (MonadNix e m, ToNix a m (NValue m))-      => ToBuiltin m (Prim m a) where-    toBuiltin _ p = toNix =<< runPrim p--instance (MonadNix e m, FromNix a m (NValue m), ToBuiltin m b)-      => ToBuiltin m (a -> b) where-    toBuiltin name f = return $ nvBuiltin name (fromNix >=> toBuiltin name . f)+{-# language CPP #-}+{-# language AllowAmbiguousTypes #-}+{-# language ConstraintKinds #-}+{-# language FunctionalDependencies #-}+{-# language KindSignatures #-}+{-# language MonoLocalBinds #-}+{-# language MultiWayIf #-}+{-# language PartialTypeSignatures #-}+{-# language QuasiQuotes #-}+{-# language PatternSynonyms #-}+{-# language TemplateHaskell #-}+{-# language UndecidableInstances #-}+{-# language PackageImports #-} -- 2021-07-05: Due to hashing Haskell IT system situation, in HNix we currently ended-up with 2 hash package dependencies @{hashing, cryptonite}@++{-# options_ghc -fno-warn-name-shadowing #-}+++-- | Code that implements Nix builtins. Lists the functions that are built into the Nix expression evaluator. Some built-ins (aka `derivation`), are always in the scope, so they can be accessed by the name. To keap the namespace clean, most built-ins are inside the `builtins` scope - a set that contains all what is a built-in.+module Nix.Builtins+  ( withNixContext+  , builtins+  )+where++import           Nix.Prelude+import           GHC.Exception                  ( ErrorCall(ErrorCall) )+import           Control.Monad                  ( foldM )+import           Control.Monad.Catch            ( MonadCatch(catch) )+import           Control.Monad.ListM            ( sortByM )+import           "hashing" 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+import qualified Data.Aeson                    as A+#if MIN_VERSION_aeson(2,0,0)+import qualified Data.Aeson.Key                as AKM+import qualified Data.Aeson.KeyMap             as AKM+#endif+import           Data.Align                     ( alignWith )+import           Data.Array+import           Data.Bits+import qualified Data.ByteString               as B+import           Data.ByteString.Base16        as Base16+import           Data.Char                      ( isDigit )+import           Data.Foldable                  ( foldrM )+import           Data.Fix                       ( foldFix )+import           Data.List                      ( partition )+import qualified Data.HashSet                  as HS+import qualified Data.HashMap.Lazy             as M+import           Data.Scientific+import qualified Data.Set                      as S+import qualified Data.Text                     as Text+import           Data.Text.Read                 ( decimal )+import qualified Data.Text.Lazy.Builder        as Builder+import           Data.These                     ( fromThese, These )+import qualified Data.Time.Clock.POSIX         as Time+import qualified Data.Vector                   as V+import           NeatInterpolation              ( text )+import           Nix.Atoms+import           Nix.Convert+import           Nix.Effects+import           Nix.Effects.Basic              ( fetchTarball )+import           Nix.Exec+import           Nix.Expr.Types+import qualified Nix.Eval                      as Eval+import           Nix.Frames+import           Nix.Json+import           Nix.Normal+import           Nix.Options+import           Nix.Parser+import           Nix.Render+import           Nix.Scope+import           Nix.String+import           Nix.String.Coerce+import           Nix.Value+import           Nix.Value.Equal+import           Nix.Value.Monad+import           Nix.XML+import           System.Nix.Base32             as Base32+import           System.PosixCompat.Files       ( isRegularFile+                                                , isDirectory+                                                , isSymbolicLink+                                                )+import qualified Text.Show+import           Text.Regex.TDFA                ( Regex+                                                , makeRegex+                                                , matchOnceText+                                                , matchAllText+                                                )++-- This is a big module. There is recursive reuse:+-- @builtins -> builtinsList -> scopedImport -> withNixContext -> builtins@,+-- since @builtins@ is self-recursive: aka we ship @builtins.builtins.builtins...@.++-- * Internal++-- ** Nix Builtins Haskell type level++newtype Prim m a = Prim (m a)++data BuiltinType = Normal | TopLevel+data Builtin v =+  Builtin+    { _kind   :: BuiltinType+    , mapping :: (VarName, v)+    }++-- *** @class ToBuiltin@ and its instances++-- | Types that support conversion to nix in a particular monad+class ToBuiltin t f m a | a -> m where+  toBuiltin :: Text -> a -> m (NValue t f m)++instance+  ( MonadNix e t f m+  , ToValue a m (NValue t f m)+  )+  => ToBuiltin t f m (Prim m a) where+  toBuiltin _ p = toValue @a @m =<< coerce p++instance+  ( MonadNix e t f m+  , FromValue a m (Deeper (NValue t f m))+  , ToBuiltin t f m b+  )+  => ToBuiltin t f m (a -> b) where+  toBuiltin name f =+    pure $ NVBuiltin (coerce name) $ toBuiltin name . f <=< fromValue . Deeper++-- *** @WValue@ closure wrapper to have @Ord@++-- We wrap values solely to provide an Ord instance for genericClosure+newtype WValue t f m = WValue (NValue t f m)++instance NVConstraint f => Eq (WValue t f m) where+  WValue (NVConstant (NFloat x)) == WValue (NVConstant (NInt y)) =+    x == fromInteger y+  WValue (NVConstant (NInt   x)) == WValue (NVConstant (NFloat y)) =+    fromInteger x == y+  WValue (NVConstant (NInt   x)) == WValue (NVConstant (NInt   y)) = x == y+  WValue (NVConstant (NFloat x)) == WValue (NVConstant (NFloat y)) = x == y+  WValue (NVPath     x         ) == WValue (NVPath     y         ) = x == y+  WValue (NVStr x) == WValue (NVStr y) =+    ignoreContext x == ignoreContext y+  _ == _ = False++instance NVConstraint f => Ord (WValue t f m) where+  WValue (NVConstant (NFloat x)) <= WValue (NVConstant (NInt y)) =+    x <= fromInteger y+  WValue (NVConstant (NInt   x)) <= WValue (NVConstant (NFloat y)) =+    fromInteger x <= y+  WValue (NVConstant (NInt   x)) <= WValue (NVConstant (NInt   y)) = x <= y+  WValue (NVConstant (NFloat x)) <= WValue (NVConstant (NFloat y)) = x <= y+  WValue (NVPath     x         ) <= WValue (NVPath     y         ) = x <= y+  WValue (NVStr x) <= WValue (NVStr y) =+    ignoreContext x <= ignoreContext y+  _ <= _ = False++-- ** Helpers++pattern NVBool :: MonadNix e t f m => Bool -> NValue t f m+pattern NVBool a = NVConstant (NBool a)++data NixPathEntryType+  = PathEntryPath+  | PathEntryURI+ deriving (Show, Eq)++-- | @NIX_PATH@ is colon-separated, but can also contain URLs, which have a colon+-- (i.e. @https://...@)+uriAwareSplit :: Text -> [(Text, NixPathEntryType)]+uriAwareSplit txt =+  case Text.break (== ':') txt of+    (e1, e2)+      | Text.null e2                              -> one (e1, PathEntryPath)+      | "://" `Text.isPrefixOf` e2      ->+        let ((suffix, _) : path) = uriAwareSplit (Text.drop 3 e2) in+        (e1 <> "://" <> suffix, PathEntryURI) : path+      | otherwise                                 -> (e1, PathEntryPath) : uriAwareSplit (Text.drop 1 e2)++foldNixPath+  :: forall e t f m r+   . MonadNix e t f m+  => r+  -> (Path -> Maybe Text -> NixPathEntryType -> r -> m r)+  -> m r+foldNixPath z f =+  do+    mres <- lookupVar "__includes"+    dirs <-+      maybe+        stub+        ((fromValue . Deeper) <=< demand)+        mres+    mPath    <- getEnvVar "NIX_PATH"+    mDataDir <- getEnvVar "NIX_DATA_DIR"+    dataDir  <-+      maybe+        getDataDir+        (pure . coerce . toString)+        mDataDir++    foldrM+      fun+      z+      $ (fromInclude . ignoreContext <$> dirs)+        <> uriAwareSplit `whenJust` mPath+        <> one (fromInclude $ "nix=" <> fromString (coerce dataDir) <> "/nix/corepkgs")+ where++  fromInclude :: Text -> (Text, NixPathEntryType)+  fromInclude x =+    (x, ) $+      bool+        PathEntryPath+        PathEntryURI+        ("://" `Text.isInfixOf` x)++  fun :: (Text, NixPathEntryType) -> r -> m r+  fun (x, ty) rest =+    case Text.splitOn "=" x of+      [p] -> f (coerce $ toString p) mempty ty rest+      [n, p] -> f (coerce $ toString p) (pure n) ty rest+      _ -> throwError $ ErrorCall $ "Unexpected entry in NIX_PATH: " <> show x++attrsetGet :: MonadNix e t f m => VarName -> AttrSet (NValue t f m) -> m (NValue t f m)+attrsetGet k s =+  maybe+    (throwError $ ErrorCall $ toString @Text $ "Attribute '" <> coerce k <> "' required")+    pure+    (M.lookup k s)++data VersionComponent+  = VersionComponentPre -- ^ The string "pre"+  | VersionComponentString !Text -- ^ A string other than "pre"+  | VersionComponentNumber !Integer -- ^ A number+  deriving (Read, Eq, Ord)++instance Show VersionComponent where+  show =+    \case+      VersionComponentPre      -> "pre"+      VersionComponentString s -> show s+      VersionComponentNumber n -> show n++splitVersion :: Text -> [VersionComponent]+splitVersion s =+  (\ (x, xs) -> if+    | isRight eDigitsPart ->+        either+          (\ e -> error $ "splitVersion: did hit impossible: '" <> fromString e <> "' while parsing '" <> s <> "'.")+          (\ res ->+            one (VersionComponentNumber $ fst res)+            <> splitVersion (snd res)+          )+          eDigitsPart++    | x `elem` separators -> splitVersion xs++    | otherwise -> one charsPart <> splitVersion rest2+  ) `whenJust` Text.uncons s+ where+  -- | Based on https://github.com/NixOS/nix/blob/4ee4fda521137fed6af0446948b3877e0c5db803/src/libexpr/names.cc#L44+  separators :: String+  separators = ".-"++  eDigitsPart :: Either String (Integer, Text)+  eDigitsPart = decimal @Integer $ s++  (charsSpan, rest2) =+    Text.span+      (\c -> not $ isDigit c || c `elem` separators)+      s++  charsPart :: VersionComponent+  charsPart =+    case charsSpan of+      "pre" -> VersionComponentPre+      xs'   -> VersionComponentString xs'+++compareVersions :: Text -> Text -> Ordering+compareVersions s1 s2 =+  fold $ (alignWith cmp `on` splitVersion) s1 s2+ where+  cmp :: These VersionComponent VersionComponent -> Ordering+  cmp = uncurry compare . join fromThese (VersionComponentString mempty)++splitDrvName :: Text -> (Text, Text)+splitDrvName s =+  both (Text.intercalate sep) (namePieces, versionPieces)+ where+  sep    = "-"+  pieces :: [Text]+  pieces = Text.splitOn sep s+  isFirstVersionPiece :: Text -> Bool+  isFirstVersionPiece p =+    maybe+      False+      (isDigit . fst)+      (Text.uncons p)+  -- Like 'break', but always puts the first item into the first result+  -- list+  breakAfterFirstItem :: (a -> Bool) -> [a] -> ([a], [a])+  breakAfterFirstItem f =+    handlePresence+      mempty+      (\ (h : t) -> let (a, b) = break f t in (h : a, b))+  (namePieces, versionPieces) =+    breakAfterFirstItem isFirstVersionPiece pieces++splitMatches+  :: forall e t f m+   . MonadNix e t f m+  => Int+  -> [[(ByteString, (Int, Int))]]+  -> ByteString+  -> [NValue t f m]+splitMatches _ [] haystack = one $ thunkStr haystack+splitMatches _ ([] : _) _ =+  fail "Fail in splitMatches: this should never happen!"+splitMatches numDropped (((_, (start, len)) : captures) : mts) haystack =+  thunkStr before : caps : splitMatches (numDropped + relStart + len)+                                        mts+                                        (B.drop len rest)+ where+  relStart       = max 0 start - numDropped+  (before, rest) = B.splitAt relStart haystack+  caps :: NValue t f m+  caps           = NVList (f <$> captures)+  f :: (ByteString, (Int, b)) -> NValue t f m+  f (a, (s, _))  =+    bool+      NVNull+      (thunkStr a)+      (s >= 0)++thunkStr :: NVConstraint f => ByteString -> NValue t f m+thunkStr s = mkNVStrWithoutContext $ decodeUtf8 s++hasKind+  :: forall a e t f m+   . (MonadNix e t f m, FromValue a m (NValue t f m))+  => NValue t f m+  -> m (NValue t f m)+hasKind =+  inHaskMay+    (isJust @a)+++absolutePathFromValue :: MonadNix e t f m => NValue t f m -> m Path+absolutePathFromValue =+  \case+    NVStr ns ->+      do+        let+          path = coerce . toString $ ignoreContext ns++        when (not (isAbsolute path)) $ throwError $ ErrorCall $ "string " <> show path <> " doesn't represent an absolute path"+        pure path++    NVPath path -> pure path+    v           -> throwError $ ErrorCall $ "expected a path, got " <> show v+++data FileType+  = FileTypeRegular+  | FileTypeDirectory+  | FileTypeSymlink+  | FileTypeUnknown+  deriving (Show, Read, Eq, Ord)++instance Convertible e t f m => ToValue FileType m (NValue t f m) where+  toValue =+    toValue . mkNixStringWithoutContext .+      \case+        FileTypeRegular   -> "regular" :: Text+        FileTypeDirectory -> "directory"+        FileTypeSymlink   -> "symlink"+        FileTypeUnknown   -> "unknown"++-- ** Builtin functions++derivationNix+  :: forall e t f m. (MonadNix e t f m, Scoped (NValue t f m) m)+  => m (NValue t f m)+derivationNix = foldFix Eval.eval $$(do+    -- This is compiled in so that we only parse it once at compile-time.+    let Right expr = parseNixText [text|+      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|]+    [|| expr ||]+  )++nixPathNix :: forall e t f m . MonadNix e t f m => m (NValue t f m)+nixPathNix =+  fmap+    NVList+    $ foldNixPath mempty $+        \p mn ty rest ->+          pure $+            pure+              (NVSet+                mempty+                (M.fromList+                  [case ty of+                    PathEntryPath -> ("path", NVPath  p)+                    PathEntryURI  -> ( "uri", mkNVStrWithoutContext $ fromString $ coerce p)++                  , ( "prefix", mkNVStrWithoutContext $ maybeToMonoid mn)+                  ]+                )+              )+            <> rest++toStringNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)+toStringNix = toValue <=< coerceAnyToNixString callFunc DontCopyToStore++hasAttrNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+hasAttrNix x y =+  do+    (coerce -> key) <- fromStringNoContext =<< fromValue x+    (aset, _) <- fromValue @(AttrSet (NValue t f m), PositionSet) y++    toValue $ M.member key aset++hasContextNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)+hasContextNix = inHask hasContext++getAttrNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+getAttrNix x y =+  do+    (coerce -> key) <- fromStringNoContext =<< fromValue x+    (aset, _) <- fromValue @(AttrSet (NValue t f m), PositionSet) y++    attrsetGet key aset++unsafeDiscardOutputDependencyNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> m (NValue t f m)+unsafeDiscardOutputDependencyNix nv =+  do+    (nc, ns) <- (getStringContext &&& ignoreContext) <$> fromValue nv+    toValue $ mkNixString (HS.map discard nc) ns+ where+  discard :: StringContext -> StringContext+  discard (StringContext AllOutputs a) = StringContext DirectPath a+  discard x                            = x++unsafeGetAttrPosNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+unsafeGetAttrPosNix nvX nvY =+  do+    x <- demand nvX+    y <- demand nvY++    case (x, y) of+      (NVStr ns, NVSet apos _) ->+        maybe+          (pure NVNull)+          toValue+          (M.lookup @VarName (coerce $ ignoreContext ns) apos)+      _xy -> throwError $ ErrorCall $ "Invalid types for builtins.unsafeGetAttrPosNix: " <> show _xy++-- This function is a bit special in that it doesn't care about the contents+-- of the list.+lengthNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+lengthNix = inHask (length :: [NValue t f m] -> Int)++addNix+  :: MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+addNix nvX nvY =+  do+    x' <- demand nvX+    y' <- demand nvY++    case (x', y') of+      (NVConstant (NInt   x), NVConstant (NInt   y)) -> toValue (             x + y :: Integer       )+      (NVConstant (NFloat x), NVConstant (NInt   y)) -> toValue $             x + fromInteger y+      (NVConstant (NInt   x), NVConstant (NFloat y)) -> toValue $ fromInteger x + y+      (NVConstant (NFloat x), NVConstant (NFloat y)) -> toValue $             x + y+      (_x                   , _y                   ) -> throwError $ Addition _x _y++mulNix+  :: MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+mulNix nvX nvY =+  do+    x' <- demand nvX+    y' <- demand nvY++    case (x', y') of+      (NVConstant (NInt   x), NVConstant (NInt   y)) -> toValue (x * y :: Integer       )+      (NVConstant (NFloat x), NVConstant (NInt   y)) -> toValue (x * fromInteger y)+      (NVConstant (NInt   x), NVConstant (NFloat y)) -> toValue (fromInteger x * y)+      (NVConstant (NFloat x), NVConstant (NFloat y)) -> toValue (x * y            )+      (_x                   , _y                   ) -> throwError $ Multiplication _x _y++divNix+  :: MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+divNix nvX nvY =+  do+    x' <- demand nvX+    y' <- demand nvY+    case (x', y') of+      (NVConstant (NInt   x), NVConstant (NInt   y)) | y /= 0 -> toValue (  floor (fromInteger x / fromInteger y :: Double) :: Integer)+      (NVConstant (NFloat x), NVConstant (NInt   y)) | y /= 0 -> toValue $                     x / fromInteger y+      (NVConstant (NInt   x), NVConstant (NFloat y)) | y /= 0 -> toValue $         fromInteger x / y+      (NVConstant (NFloat x), NVConstant (NFloat y)) | y /= 0 -> toValue $                     x / y+      (_x                   , _y                   )         -> throwError $ Division _x _y++anyNix+  :: MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+anyNix f = toValue <=< anyMNix fromValue <=< traverse (callFunc f) <=< fromValue+ where+  anyMNix :: Monad m => (a -> m Bool) -> [a] -> m Bool+  anyMNix _ []       = pure False+  anyMNix p (x : xs) =+    bool+      (anyMNix p xs)+      (pure True)+      =<< p x++allNix+  :: MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+allNix f = toValue <=< allMNix fromValue <=< traverse (callFunc f) <=< fromValue+ where+  allMNix :: Monad m => (a -> m Bool) -> [a] -> m Bool+  allMNix _ []       = pure True+  allMNix p (x : xs) =+    bool+      (pure False)+      (allMNix p xs)+      =<< p x++foldl'Nix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+foldl'Nix f z xs =  foldM go z =<< fromValue @[NValue t f m] xs+ where+  go b a = (`callFunc` a) =<< callFunc f b++headNix :: forall e t f m. MonadNix e t f m => NValue t f m -> m (NValue t f m)+headNix =+  maybe+    (throwError $ ErrorCall "builtins.head: empty list")+    pure+  . viaNonEmpty head <=< fromValue @[NValue t f m]++tailNix :: forall e t f m. MonadNix e t f m => NValue t f m -> m (NValue t f m)+tailNix =+  maybe+    (throwError $ ErrorCall "builtins.tail: empty list")+    (pure . NVList)+  . viaNonEmpty tail <=< fromValue @[NValue t f m]++splitVersionNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)+splitVersionNix v =+  do+    version <- fromStringNoContext =<< fromValue v+    pure $+      NVList $+        mkNVStrWithoutContext . show <$>+          splitVersion version++compareVersionsNix+  :: MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+compareVersionsNix t1 t2 =+  do+    s1 <- mkText t1+    s2 <- mkText t2++    let+      cmpVers =+        case compareVersions s1 s2 of+          LT -> -1+          EQ -> 0+          GT -> 1++    pure $ NVConstant $ NInt cmpVers++ where+  mkText = fromStringNoContext <=< fromValue++parseDrvNameNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+parseDrvNameNix drvname =+  do+    s <- fromStringNoContext =<< fromValue drvname++    let+      (name :: Text, version :: Text) = splitDrvName s++    toValue @(AttrSet (NValue t f m)) $+      M.fromList+        [ ( "name" :: VarName+          , mkNVStr name+          )+        , ( "version"+          , mkNVStr version+          )+        ]++ where+  mkNVStr = mkNVStrWithoutContext++matchNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+matchNix pat str =+  do+    p <- fromStringNoContext =<< fromValue pat+    ns <- fromValue str++    -- NOTE: 2018-11-19: Currently prim_match in nix/src/libexpr/primops.cc+    -- ignores the context of its second argument. This is probably a bug but we're+    -- going to preserve the behavior here until it is fixed upstream.+    -- Relevant issue: https://github.com/NixOS/nix/issues/2547+    let+      s  = ignoreContext ns+      re = makeRegex p :: Regex+      mkMatch t =+        bool+          (pure NVNull)+          (toValue $ mkNixStringWithoutContext t)+          (not $ Text.null t)++    case matchOnceText re s of+      Just ("", sarr, "") ->+        do+          let submatches = fst <$> elems sarr+          NVList <$>+            traverse+              mkMatch+              (case submatches of+                 [] -> mempty+                 [a] -> one a+                 _:xs -> xs -- return only the matched groups, drop the full string+              )+      _ -> pure NVNull++splitNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+splitNix pat str =+  do+    p <- fromStringNoContext =<< fromValue pat+    ns <- fromValue str+        -- NOTE: Currently prim_split in nix/src/libexpr/primops.cc ignores the+        -- context of its second argument. This is probably a bug but we're+        -- going to preserve the behavior here until it is fixed upstream.+        -- Relevant issue: https://github.com/NixOS/nix/issues/2547+    let+      s = ignoreContext ns+      regex       = makeRegex p :: Regex+      haystack = encodeUtf8 s++    pure $ NVList $ splitMatches 0 (elems <$> matchAllText regex haystack) haystack++substringNix :: forall e t f m. MonadNix e t f m => Int -> Int -> NixString -> Prim m NixString+substringNix start len str =+  Prim $+    bool+      (throwError $ ErrorCall $ "builtins.substring: negative start position: " <> show start)+      (pure $ modifyNixContents (take . Text.drop start) str)+      (start >= 0)+ where+  take =+    bool+      id  --NOTE: negative values of 'len' are OK, and mean "take everything"+      (Text.take len)+      (len >= 0)++attrNamesNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+attrNamesNix =+    coersion . inHask @(AttrSet (NValue t f m))+      (fmap (mkNixStringWithoutContext . coerce) . sort . M.keys)+ where+  coersion = fmap (coerce :: CoerceDeeperToNValue t f m)++attrValuesNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+attrValuesNix nvattrs =+  do+    attrs <- fromValue @(AttrSet (NValue t f m)) nvattrs+    toValue $+      snd <$>+        sortOn+          (fst @VarName @(NValue t f m))+          (M.toList attrs)++mapNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+mapNix f =+  inHaskM @[NValue t f m]+    (traverse+      (defer+      . withFrame Debug (ErrorCall "While applying f in map:\n")+      . callFunc f+      )+    )++mapAttrsNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+mapAttrsNix f xs =+  do+    nixAttrset <- fromValue @(AttrSet (NValue t f m)) xs+    let+      keyVals = M.toList nixAttrset+      keys = fst <$> keyVals++      applyFunToKeyVal (key, val) =+        do+          runFunForKey <- callFunc f $ mkNVStrWithoutContext (coerce key)+          callFunc runFunForKey val++    newVals <-+      traverse+        (defer @(NValue t f m) . withFrame Debug (ErrorCall "While applying f in mapAttrs:\n") . applyFunToKeyVal)+        keyVals++    toValue $ M.fromList $ zip keys newVals++filterNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+filterNix f =+  inHaskM+    (filterM fh)+ where+  fh :: NValue t f m -> m Bool+  fh = fromValue <=< callFunc f++catAttrsNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+catAttrsNix attrName xs =+  do+    n <- fromStringNoContext =<< fromValue attrName+    l <- fromValue @[NValue t f m] xs++    NVList . catMaybes <$>+      traverse+        (fmap (M.lookup @VarName $ coerce n) . fromValue <=< demand)+        l++baseNameOfNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)+baseNameOfNix x =+  do+    ns <- coerceStringlikeToNixString DontCopyToStore x+    pure $+      NVStr $+        modifyNixContents+          (fromString . coerce takeFileName . toString)+          ns++bitAndNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+bitAndNix x y =+  do+    a <- fromValue @Integer x+    b <- fromValue @Integer y++    toValue $ a .&. b++bitOrNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+bitOrNix x y =+  do+    a <- fromValue @Integer x+    b <- fromValue @Integer y++    toValue $ a .|. b++bitXorNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+bitXorNix x y =+  do+    a <- fromValue @Integer x+    b <- fromValue @Integer y++    toValue $ a `xor` b++builtinsBuiltinNix+  :: forall e t f m+   . MonadNix e t f m+  => m (NValue t f m)+builtinsBuiltinNix = throwError $ ErrorCall "HNix does not provide builtins.builtins at the moment. Using builtins directly should be preferred"++-- a safer version of `attrsetGet`+attrGetOr+  :: forall e t f m v a+   . (MonadNix e t f m, FromValue v m (NValue t f m))+  => a+  -> (v -> m a)+  -> VarName+  -> AttrSet (NValue t f m)+  -> m a+attrGetOr fallback fun name attrs =+  maybe+    (pure fallback)+    (fun <=< fromValue)+    (M.lookup name attrs)+++--  NOTE: It is a part of the implementation taken from:+--  https://github.com/haskell-nix/hnix/pull/755+--  look there for `sha256` and/or `filterSource`+pathNix :: forall e t f m. MonadNix e t f m => NValue t f m -> m (NValue t f m)+pathNix arg =+  do+    attrs <- fromValue @(AttrSet (NValue t f m)) arg+    path      <- fmap (coerce . toString) $ fromStringNoContext =<< coerceToPath =<< attrsetGet "path" attrs++    -- TODO: Fail on extra args+    -- XXX: This is a very common pattern, we could factor it out+    name      <- toText <$> attrGetOr (takeFileName path) (fmap (coerce . toString) . fromStringNoContext) "name" attrs+    recursive <- attrGetOr True pure "recursive" attrs++    Right (coerce . toText . coerce @StorePath @String -> s) <- addToStore name (NarFile path) recursive False+    -- TODO: Ensure that s matches sha256 when not empty+    pure $ NVStr $ mkNixStringWithSingletonContext (StringContext DirectPath s) s+ where+  coerceToPath = coerceToString callFunc DontCopyToStore CoerceAny++dirOfNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)+dirOfNix nvdir =+  do+    dir <- demand nvdir++    case dir of+      NVStr ns -> pure $ NVStr $ modifyNixContents (fromString . coerce takeDirectory . toString) ns+      NVPath path -> pure $ NVPath $ takeDirectory path+      v -> throwError $ ErrorCall $ "dirOf: expected string or path, got " <> show v++-- jww (2018-04-28): This should only be a string argument, and not coerced?+unsafeDiscardStringContextNix+  :: MonadNix e t f m => NValue t f m -> m (NValue t f m)+unsafeDiscardStringContextNix =+  inHask (mkNixStringWithoutContext . ignoreContext)++-- | Evaluate `a` to WHNF to collect its topmost effect.+seqNix+  :: MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+seqNix a b = b <$ demand a++-- | Evaluate 'a' to NF to collect all of its effects, therefore data cycles are ignored.+deepSeqNix+  :: MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+deepSeqNix a b = b <$ normalForm_ a++elemNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+elemNix x = inHaskM (anyMNix $ valueEqM x)+ where+  anyMNix :: Monad m => (a -> m Bool) -> [a] -> m Bool+  anyMNix p =+    handlePresence+      (pure False)+      (\ (x : xss) ->+        bool+          (anyMNix p xss)+          (pure True)+          =<< p x+      )++elemAtNix+  :: MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+elemAtNix xs n =+  do+    n' <- fromValue n+    xs' <- fromValue xs+    maybe+      (throwError $ ErrorCall $ "builtins.elem: Index " <> show n' <> " too large for list of length " <> show (length xs'))+      pure+      (xs' !!? n')++genListNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+genListNix f nixN =+  do+    n <- fromValue @Integer nixN+    bool+      (throwError $ ErrorCall $ "builtins.genList: Expected a non-negative number, got " <> show n)+      (toValue =<< traverse (defer . callFunc f <=< toValue) [0 .. n - 1])+      (n >= 0)++genericClosureNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+genericClosureNix c =+  do+  s <- fromValue @(AttrSet (NValue t f m)) c++  case (M.lookup "startSet" s, M.lookup "operator" s) of+    (Nothing    , Nothing        ) -> throwError $ ErrorCall "builtins.genericClosure: Attributes 'startSet' and 'operator' required"+    (Nothing    , Just _         ) -> throwError $ ErrorCall "builtins.genericClosure: Attribute 'startSet' required"+    (Just _     , Nothing        ) -> throwError $ ErrorCall "builtins.genericClosure: Attribute 'operator' required"+    (Just startSet, Just operator) ->+      do+        ss <- fromValue @[NValue t f m] =<< demand startSet+        op <- demand operator+        let+          go+            :: Set (WValue t f m)+            -> [NValue t f m]+            -> m (Set (WValue t f m), [NValue t f m])+          go ks []       = pure (ks, mempty)+          go ks (t : ts) =+            do+              v <- demand t+              k <- demand =<< attrsetGet "key" =<< fromValue @(AttrSet (NValue t f m)) v++              bool+                (do+                  checkComparable k $+                    handlePresence+                      k+                      (\ (WValue j:_) -> j)+                      (S.toList ks)++                  (<<$>>) (v :) . go (S.insert (WValue k) ks) . (<>) ts =<< fromValue @[NValue t f m] =<< callFunc op v+                )+                (go ks ts)+                (S.member (WValue k) ks)++        toValue @[NValue t f m] =<< snd <$> go mempty ss++-- | Takes:+-- 1. List of strings to match.+-- 2. List of strings to replace corresponding match occurance. (arg 1 & 2 lists matched by index)+-- 3. String to process+-- -> returns the string with requested replacements.+--+-- Example:+-- builtins.replaceStrings ["ll" "e"] [" " "i"] "Hello world" == "Hi o world".+replaceStringsNix+  :: MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+replaceStringsNix tfrom tto ts =+  do+    -- NixStrings have context - remember+    (fromKeys :: [NixString]) <- fromValue (Deeper tfrom)+    (toVals   :: [NixString]) <- fromValue (Deeper tto)+    (string   ::  NixString ) <- fromValue ts++    when (length fromKeys /= length toVals) $ throwError $ ErrorCall "builtins.replaceStrings: Arguments `from`&`to` construct a key-value map, so the number of their elements must always match."++    let+      --  2021-02-18: NOTE: if there is no match - the process does not changes the context, simply slides along the string.+      --  So it isbe more effective to pass the context as the first argument.+      --  And moreover, the `passOneCharNgo` passively passes the context, to context can be removed from it and inherited directly.+      --  Then the solution would've been elegant, but the Nix bug prevents elegant implementation.+      go ctx input output =+        maybe+            -- Passively pass the chars+          passOneChar+          replace+          maybePrefixMatch++       where+        -- When prefix matched something - returns (match, replacement, remainder)+        maybePrefixMatch :: Maybe (Text, NixString, Text)+        maybePrefixMatch = formMatchReplaceTailInfo <$> find ((`Text.isPrefixOf` input) . fst) fromKeysToValsMap+         where+          formMatchReplaceTailInfo (m, r) = (m, r, Text.drop (Text.length m) input)++          fromKeysToValsMap = zip (ignoreContext <$> fromKeys) toVals++        -- Not passing args => It is constant that gets embedded into `go` => It is simple `go` tail recursion+        passOneChar =+          maybe+            (finish ctx output)  -- The base case - there is no chars left to process -> finish+            (\(c, i) -> go ctx i (output <> Builder.singleton c)) -- If there are chars - pass one char & continue+            (Text.uncons input)  -- chip first char++        --  2021-02-18: NOTE: rly?: toStrict . toLazyText+        --  Maybe `text-builder`, `text-show`?+        finish ctx output = mkNixString ctx (toStrict $ Builder.toLazyText output)++        replace (key, replacementNS, unprocessedInput) = replaceWithNixBug unprocessedInput updatedOutput++         where+          replaceWithNixBug =+            bool+              (go updatedCtx)  -- tail recursion+              -- Allowing match on "" is a inherited bug of Nix,+              -- when "" is checked - it always matches. And so - when it checks - it always insers a replacement, and then process simply passesthrough the char that was under match.+              --+              -- repl> builtins.replaceStrings ["" "e"] [" " "i"] "Hello world"+              -- " H e l l o   w o r l d "+              -- repl> builtins.replaceStrings ["ll" ""] [" " "i"] "Hello world"+              -- "iHie ioi iwioirilidi"+              --  2021-02-18: NOTE: There is no tests for this+              bugPassOneChar  -- augmented recursion+              isNixBugCase++          isNixBugCase = key == mempty++          updatedOutput  = output <> replacement+          updatedCtx     = ctx <> replacementCtx++          replacement    = Builder.fromText $ ignoreContext replacementNS+          replacementCtx = getStringContext replacementNS++          -- The bug modifies the content => bug demands `pass` to be a real function =>+          -- `go` calls `pass` function && `pass` calls `go` function+          -- => mutual recusion case, so placed separately.+          bugPassOneChar input output =+            maybe+              (finish updatedCtx output)  -- The base case - there is no chars left to process -> finish+              (\(c, i) -> go updatedCtx i $ output <> Builder.singleton c) -- If there are chars - pass one char & continue+              (Text.uncons input)  -- chip first char++    toValue $ go (getStringContext string) (ignoreContext string) mempty++removeAttrsNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+removeAttrsNix set v =+  do+    (m, p) <- fromValue @(AttrSet (NValue t f m), PositionSet) set+    (nsToRemove :: [NixString]) <- fromValue $ Deeper v+    (coerce -> toRemove) <- traverse fromStringNoContext nsToRemove+    toValue (fun m toRemove, fun p toRemove)+ where+  fun :: forall k v . (Eq k, Hashable k) => HashMap k v -> [k] -> HashMap k v+  fun = foldl' (flip M.delete)++intersectAttrsNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+intersectAttrsNix set1 set2 =+  do+    (s1, p1) <- fromValue @(AttrSet (NValue t f m), PositionSet) set1+    (s2, p2) <- fromValue @(AttrSet (NValue t f m), PositionSet) set2++    pure $ NVSet (p2 `M.intersection` p1) (s2 `M.intersection` s1)++functionArgsNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+functionArgsNix nvfun =+  do+    fun <- demand nvfun+    case fun of+      NVClosure p _ ->+        toValue @(AttrSet (NValue t f m)) $ NVBool <$>+          case p of+            Param name     -> one (name, False)+            ParamSet _ _ pset -> isJust <$> M.fromList pset+      _v -> throwError $ ErrorCall $ "builtins.functionArgs: expected function, got " <> show _v++toFileNix+  :: MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+toFileNix name s =+  do+    name' <- fromStringNoContext =<< fromValue name+    s'    <- fromValue s+    mres  <-+      toFile_+        (coerce $ toString name')+        (ignoreContext s')++    let+      storepath  = coerce (fromString @Text) mres+      sc = StringContext DirectPath storepath++    toValue $ mkNixStringWithSingletonContext sc storepath++toPathNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)+toPathNix = inHask @Path id++pathExistsNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)+pathExistsNix nvpath =+  do+    path <- demand nvpath+    toValue =<<+      case path of+        NVPath p  -> doesPathExist p+        NVStr  ns -> doesPathExist $ coerce $ toString $ ignoreContext ns+        _v -> throwError $ ErrorCall $ "builtins.pathExists: expected path, got " <> show _v++isPathNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+isPathNix = hasKind @Path++isAttrsNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+isAttrsNix = hasKind @(AttrSet (NValue t f m))++isListNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+isListNix = hasKind @[NValue t f m]++isIntNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+isIntNix = hasKind @Int++isFloatNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+isFloatNix = hasKind @Float++isBoolNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+isBoolNix = hasKind @Bool++isNullNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+isNullNix = hasKind @()++-- isString cannot use `hasKind` because it coerces derivationNixs to strings.+isStringNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)+isStringNix nv =+  do+    v <- demand nv++    toValue $+      case v of+        NVStr{} -> True+        _       -> False++isFunctionNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)+isFunctionNix nv =+  do+    v <- demand nv++    toValue $+      case v of+        NVClosure{} -> True+        _           -> False++throwNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)+throwNix =+  throwError . ErrorCall . toString . ignoreContext+    <=< coerceStringlikeToNixString CopyToStore++-- | Implementation of Nix @import@ clause.+--+-- Because Nix @import@s work strictly+-- (import gets fully evaluated befor bringing it into the scope it was called from)+-- - that property raises a requirement for execution phase of the interpreter go into evaluation phase+-- & then also go into parsing phase on the imports.+-- So it is not possible (more precise - not practical) to do a full parse Nix code phase fully & then go into evaluation phase.+-- As it is not possible to "import them lazily", as import is strict & it is not possible to establish+-- what imports whould be needed up until where it would be determined & they import strictly+--+importNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+importNix = scopedImportNix $ NVSet mempty mempty++-- | @scopedImport scope path@+-- An undocumented secret powerful function.+--+-- At the same time it is strongly forbidden to be used, as prolonged use of it would bring devastating consequences.+-- As it is essentially allows rewriting(redefinition) paradigm.+--+-- Allows to import the environment into the scope of a file expression that gets imported.+-- It is as if the contents at @path@ were given to @import@ wrapped as: @with scope; path@+-- meaning:+--+-- > -- Nix pseudocode:+-- > import (with scope; path)+--+-- For example, it allows to use itself as:+-- > bar = scopedImport pkgs ./bar.nix;+-- > -- & declare @./bar.nix@ without a header, so as:+-- > stdenv.mkDerivation { ... buildInputs = [ libfoo ]; }+--+-- But that breaks the evaluation/execution sharing of the @import@s.+--+-- Function also allows to redefine or extend the builtins.+--+-- For instance, to trace all calls to function ‘map’:+--+-- >  let+-- >    overrides = {+-- >      map = f: xs: builtins.trace "call of map!" (map f xs);+--+-- >      # Propagate override by calls to import&scopedImport.+-- >      import = fn: scopedImport overrides fn;+-- >      scopedImport = attrs: fn: scopedImport (overrides // attrs) fn;+--+-- >      # Update ‘builtins’.+-- >      builtins = builtins // overrides;+-- >    };+-- >  in scopedImport overrides ./bla.nix+--+-- In the related matter the function can be added and passed around as builtin.+scopedImportNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+scopedImportNix asetArg pathArg =+  do+    (coerce -> scope) <- fromValue @(AttrSet (NValue t f m)) asetArg+    p <- fromValue pathArg++    path  <- pathToDefaultNix @t @f @m p+    path' <-+      maybe+        (do+          traceM "No known current directory"+          pure path+        )+        (\ res ->+          do+            p' <- fromValue @Path =<< demand res++            traceM $ "Current file being evaluated is: " <> show p'+            pure $ takeDirectory p' </> path+        )+        =<< lookupVar "__cur_file"++    clearScopes @(NValue t f m)+      $ withNixContext (pure path')+      $ pushScope scope+      $ importPath @t @f @m path'++getEnvNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)+getEnvNix v =+  (toValue . mkNixStringWithoutContext . maybeToMonoid) =<< getEnvVar =<< fromStringNoContext =<< fromValue v++sortNix+  :: forall e t f m+  . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+sortNix comp =+  inHaskM (sortByM cmp)+ where+  cmp :: NValue t f m -> NValue t f m -> m Ordering+  cmp a b =+    bool+      (fmap+         (bool EQ GT)+         (compare b a)+      )+      (pure LT)+      =<< compare a b+   where+    compare :: NValue t f m -> NValue t f m -> m Bool+    compare a2 a1 = fromValue =<< (`callFunc` a1) =<< callFunc comp a2++lessThanNix+  :: MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+lessThanNix ta tb =+  do+    va <- demand ta+    vb <- demand tb++    let+      badType = throwError $ ErrorCall $ "builtins.lessThan: expected two numbers or two strings, got '" <> show va <> "' and '" <> show vb <> "'."++    NVBool <$>+      case (va, vb) of+        (NVConstant ca, NVConstant cb) ->+          case (ca, cb) of+            (NInt   a, NInt   b) -> pure $             a < b+            (NInt   a, NFloat b) -> pure $ fromInteger a < b+            (NFloat a, NInt   b) -> pure $             a < fromInteger b+            (NFloat a, NFloat b) -> pure $             a < b+            _                    -> badType+        (NVStr a, NVStr b) -> pure $ ignoreContext a < ignoreContext b+        _ -> badType++-- | Helper function, generalization of @concat@ operations.+concatWith+  :: forall e t f m+   . MonadNix e t f m+  => (NValue t f m -> m (NValue t f m))+  -> NValue t f m+  -> m (NValue t f m)+concatWith f =+  toValue .+    concat <=<+      traverse+        (fromValue @[NValue t f m] <=< f)+        <=< fromValue @[NValue t f m]++-- | Nix function of Haskell:+-- > concat :: [[a]] -> [a]+--+-- Concatenate a list of lists into a single list.+concatListsNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+concatListsNix = concatWith demand++-- | Nix function of Haskell:+-- > concatMap :: Foldable t => (a -> [b]) -> t a -> [b]+concatMapNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+concatMapNix f = concatWith (callFunc f)++listToAttrsNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+listToAttrsNix lst =+  do+    l <- fromValue @[NValue t f m] lst+    fmap+      (NVSet mempty . M.fromList . reverse)+      (traverse+        (\ nvattrset ->+          do+            a <- fromValue @(AttrSet (NValue t f m)) =<< demand nvattrset+            (coerce -> name) <- fromStringNoContext =<< fromValue =<< demand =<< attrsetGet "name" a+            val  <- attrsetGet "value" a++            pure (name, val)+        )+        l+      )++-- prim_hashString from nix/src/libexpr/primops.cc+-- fail if context in the algo arg+-- propagate context from the s arg+-- | The result coming out of hashString is base16 encoded+hashStringNix+  :: forall e t f m. MonadNix e t f m => NixString -> NixString -> Prim m NixString+hashStringNix nsAlgo ns =+  Prim $+    do+      algo <- fromStringNoContext nsAlgo+      let+        f g = pure $ modifyNixContents g ns++      case algo of+        --  2021-03-04: Pattern can not be taken-out because hashes represented as different types+        "md5"    -> f (show . mkHash @MD5.MD5)+        "sha1"   -> f (show . mkHash @SHA1.SHA1)+        "sha256" -> f (show . mkHash @SHA256.SHA256)+        "sha512" -> f (show . mkHash @SHA512.SHA512)++        _ -> throwError $ ErrorCall $ "builtins.hashString: expected \"md5\", \"sha1\", \"sha256\", or \"sha512\", got " <> show algo++       where+        -- This intermidiary `a` is only needed because of the type application+        mkHash :: (Show a, HashAlgorithm a) => Text -> a+        mkHash s = hash $ encodeUtf8 s+++-- | hashFileNix+-- use hashStringNix to hash file content+hashFileNix+  :: forall e t f m . MonadNix e t f m => NixString -> Path -> Prim m NixString+hashFileNix nsAlgo nvfilepath = Prim $ hash =<< fileContent+ where+  hash = outPrim . hashStringNix nsAlgo+  outPrim (Prim x) = x+  fileContent :: m NixString+  fileContent = mkNixStringWithoutContext <$> Nix.Render.readFile nvfilepath+++-- | groupByNix+-- Groups elements of list together by the string returned from the function f called on +-- each element. It returns an attribute set where each attribute value contains the +-- elements of list that are mapped to the same corresponding attribute name returned by f.+groupByNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+groupByNix nvfun nvlist = do+  list   <- demand nvlist+  fun    <- demand nvfun+  (f, l) <- extractP (fun, list)+  NVSet mempty+    .   fmap (NVList . reverse)+    .   M.fromListWith (<>)+    <$> traverse (app f) l+ where+  app f x = do+    name <- fromValue @Text =<< f x+    pure (VarName name, one x)+  extractP (NVBuiltin _ f, NVList l) = pure (f, l)+  extractP (NVClosure _ f, NVList l) = pure (f, l)+  extractP _v =+    throwError+      $  ErrorCall+      $  "builtins.groupBy: expected function and list, got "+      <> show _v+++placeHolderNix :: forall t f m e . MonadNix e t f m => NValue t f m -> m (NValue t f m)+placeHolderNix p =+  do+    t <- fromStringNoContext =<< fromValue p+    h <-+      coerce @(Prim m NixString) @(m NixString) $+        (hashStringNix `on` mkNixStringWithoutContext)+          "sha256"+          ("nix-output:" <> t)+    toValue+      $ mkNixStringWithoutContext+      $ Text.cons '/'+      $ Base32.encode+      -- Please, stop Text -> Bytestring here after migration to Text+      $ case Base16.decode (bytes h) of -- The result coming out of hashString is base16 encoded+#if MIN_VERSION_base16_bytestring(1,0,0)+        -- Please, stop Text -> String here after migration to Text+        Left e -> error $ "Couldn't Base16 decode the text: '" <> body h <> "'.\nThe Left fail content: '" <> show e <> "'."+        Right d -> d+#else+        (d, "") -> d+        (_, e) -> error $ "Couldn't Base16 decode the text: '" <> body h <> "'.\nUndecodable remainder: '" <> show e <> "'."+#endif+    where+      bytes :: NixString -> ByteString+      bytes = encodeUtf8 . body++      body = ignoreContext++readFileNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)+readFileNix = toValue <=< Nix.Render.readFile <=< absolutePathFromValue <=< demand++findFileNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+findFileNix nvaset nvfilepath =+  do+    aset <- demand nvaset+    filePath <- demand nvfilepath++    case (aset, filePath) of+      (NVList x, NVStr ns) ->+        do+          mres <- findPath @t @f @m x $ coerce $ toString $ ignoreContext 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)++readDirNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+readDirNix nvpath =+  do+    path           <- absolutePathFromValue =<< demand nvpath+    items          <- listDirectory path++    let+      -- | Function indeed binds filepaths as keys ('VarNames') in Nix attrset.+      detectFileTypes :: Path -> m (VarName, FileType)+      detectFileTypes item =+        do+          s <- getSymbolicLinkStatus $ path </> item+          let+            t =+              if+                | isRegularFile s  -> FileTypeRegular+                | isDirectory s    -> FileTypeDirectory+                | isSymbolicLink s -> FileTypeSymlink+                | otherwise        -> FileTypeUnknown++          pure (coerce @(String -> Text) fromString item, t)++    itemsWithTypes <-+      traverse+        detectFileTypes+        items++    (coerce :: CoerceDeeperToNValue t f m) <$> toValue (M.fromList itemsWithTypes)++fromJSONNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+fromJSONNix nvjson =+  do+    j <- demand nvjson+    jText <- fromStringNoContext =<< fromValue j++    either+      (\ jsonError -> throwError $ ErrorCall $ "builtins.fromJSON: " <> jsonError)+      jsonToNValue+      -- do we really need to marshall Text -> ByteString -> Aeson.Value (that is a Text)+      (A.eitherDecodeStrict' @A.Value $ encodeUtf8 jText)++ where+  jsonToNValue :: (A.Value -> m (NValue t f m))+  jsonToNValue =+    \case+      A.Object m ->+        traverseToNValue+          (NVSet mempty)+#if MIN_VERSION_aeson(2,0,0)+          (M.mapKeys (coerce . AKM.toText)  $ AKM.toHashMap m)+#else+          (M.mapKeys coerce m)+#endif+      A.Array  l -> traverseToNValue NVList (V.toList l)+      A.String s -> pure $ mkNVStrWithoutContext s+      A.Number n ->+        pure $+          NVConstant $+            either+              NFloat+              NInt+              (floatingOrInteger n)+      A.Bool   b -> pure $ NVBool b+      A.Null     -> pure NVNull+   where+    traverseToNValue :: Traversable t0 => (t0 (NValue t f m) -> b) -> t0 A.Value -> m b+    traverseToNValue f v = f <$> traverse jsonToNValue v++toJSONNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)+toJSONNix = (fmap NVStr . toJSONNixString) <=< demand++toXMLNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)+toXMLNix = (fmap (NVStr . toXML) . normalForm) <=< demand++typeOfNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)+typeOfNix nvv =+  do+    v <- demand nvv+    let+      detectType =+        case v of+          NVConstant a ->+            case a of+              NURI   _ -> "string"+              NInt   _ -> "int"+              NFloat _ -> "float"+              NBool  _ -> "bool"+              NNull    -> "null"+          NVStr     _   -> "string"+          NVList    _   -> "list"+          NVSet     _ _ -> "set"+          NVClosure{}   -> "lambda"+          NVPath    _   -> "path"+          NVBuiltin _ _ -> "lambda"+          _             -> error "Pattern synonyms obscure complete patterns"++    toValue $ mkNixStringWithoutContext detectType++tryEvalNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+tryEvalNix e = (`catch` (pure . onError))+  (onSuccess <$> demand e)+ where+  onSuccess v =+    NVSet+      mempty+      $ M.fromList+        [ ("success", NVBool True)+        , ("value"  , v            )+        ]++  onError :: SomeException -> NValue t f m+  onError _ =+    NVSet+      mempty+      $ M.fromList+        $ (, NVBool False) <$>+          [ "success"+          , "value"+          ]++traceNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+traceNix msg action =+  do+    traceEffect @t @f @m . toString . ignoreContext =<< fromValue msg+    pure action++-- Please, can function remember fail context+addErrorContextNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m  -- action+  -> m (NValue t f m)+addErrorContextNix _ = pure++execNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+execNix xs =+  -- 2018-11-19: NOTE: Still need to do something with the context here+  -- See prim_exec in nix/src/libexpr/primops.cc+  -- Requires the implementation of EvalState::realiseContext+  (exec . fmap ignoreContext) =<< traverse (coerceStringlikeToNixString DontCopyToStore) =<< fromValue @[NValue t f m] xs++fetchurlNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+fetchurlNix =+  (\case+    NVSet _ s -> fetch (M.lookup "sha256" s) =<< demand =<< attrsetGet "url" s+    v@NVStr{} -> fetch Nothing v+    v -> throwError $ ErrorCall $ "builtins.fetchurl: Expected URI or set, got " <> show v+  ) <=< demand++ where+  --  2022-01-21: NOTE: Needs to check the hash match.+  fetch :: Maybe (NValue t f m) -> NValue t f m -> m (NValue t f m)+  fetch _msha =+    \case+      NVStr ns ->+        either -- msha+          throwError+          toValue+          =<< getURL+            =<< maybe+              (throwError $ ErrorCall "builtins.fetchurl: unsupported arguments to url")+              pure+              (getStringNoContext ns)++      v -> throwError $ ErrorCall $ "builtins.fetchurl: Expected URI or string, got " <> show v++partitionNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+partitionNix f nvlst =+  do+    let+      match t = (, t) <$> (fromValue =<< callFunc f t)+    selection <- traverse match =<< fromValue @[NValue t f m] nvlst++    let+      (right, wrong) = partition fst selection+      makeSide       = NVList . fmap snd++    toValue @(AttrSet (NValue t f m))+      $ M.fromList+          [ ("right", makeSide right)+          , ("wrong", makeSide wrong)+          ]++currentSystemNix :: MonadNix e t f m => m (NValue t f m)+currentSystemNix =+  do+    os   <- getCurrentSystemOS+    arch <- getCurrentSystemArch++    pure $ mkNVStrWithoutContext $ arch <> "-" <> os++currentTimeNix :: MonadNix e t f m => m (NValue t f m)+currentTimeNix =+  do+    opts <- askOptions+    toValue @Integer $ round $ Time.utcTimeToPOSIXSeconds $ getTime opts++derivationStrictNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)+derivationStrictNix = derivationStrict++getRecursiveSizeNix :: (MonadIntrospect m, NVConstraint f) => a -> m (NValue t f m)+getRecursiveSizeNix = fmap (NVConstant . NInt . fromIntegral) . recursiveSize++getContextNix+  :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)+getContextNix =+  \case+    (NVStr ns) ->+      NVSet mempty <$> traverseToValue (getNixLikeContext $ toNixLikeContext $ getStringContext ns)+    x -> throwError $ ErrorCall $ "Invalid type for builtins.getContext: " <> show x+  <=< demand++appendContextNix+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+appendContextNix tx ty =+  do+    x <- demand tx+    y <- demand ty++    case (x, y) of+      (NVStr ns, NVSet _ attrs) ->+        do+          let+            getPathNOuts :: NValue t f m -> m NixLikeContextValue+            getPathNOuts tx =+              do+                x <- demand tx++                case x of+                  NVSet _ atts ->+                    do+                      -- TODO: Fail for unexpected keys.++                      let+                        getK :: VarName -> m Bool+                        getK k =+                          maybe+                            (pure False)+                            (fromValue <=< demand)+                            $ M.lookup k atts++                        getOutputs :: m [Text]+                        getOutputs =+                          maybe+                            stub+                            (\ touts ->+                              do+                                outs <- demand touts++                                case outs of+                                  NVList vs -> traverse (fmap ignoreContext . fromValue) vs+                                  _x -> throwError $ ErrorCall $ "Invalid types for context value outputs in builtins.appendContext: " <> show _x+                            )+                            (M.lookup "outputs" atts)++                      path <- getK "path"+                      allOutputs <- getK "allOutputs"++                      NixLikeContextValue path allOutputs <$> getOutputs++                  _x -> throwError $ ErrorCall $ "Invalid types for context value in builtins.appendContext: " <> show _x+            addContext :: HashMap VarName NixLikeContextValue -> NixString+            addContext newContextValues =+              mkNixString+                (fromNixLikeContext $+                  NixLikeContext $+                    M.unionWith+                      (<>)+                      newContextValues+                      $ getNixLikeContext $+                          toNixLikeContext $+                            getStringContext ns+                )+                $ ignoreContext ns++          toValue . addContext =<< traverse getPathNOuts attrs++      _xy -> throwError $ ErrorCall $ "Invalid types for builtins.appendContext: " <> show _xy+++nixVersionNix :: MonadNix e t f m => m (NValue t f m)+nixVersionNix = toValue $ mkNixStringWithoutContext "2.3"++langVersionNix :: MonadNix e t f m => m (NValue t f m)+langVersionNix = toValue (5 :: Int)++-- ** @builtinsList@++builtinsList :: forall e t f m . MonadNix e t f m => m [Builtin (NValue t f m)]+builtinsList =+  sequenceA+    [ add  TopLevel "abort"            throwNix -- for now+    , add  TopLevel "baseNameOf"       baseNameOfNix+    , add0 TopLevel "derivation"       derivationNix+    , add  TopLevel "derivationStrict" derivationStrictNix+    , add  TopLevel "dirOf"            dirOfNix+    , add  TopLevel "import"           importNix+    , add  TopLevel "isNull"           isNullNix+    , add2 TopLevel "map"              mapNix+    , add2 TopLevel "mapAttrs"         mapAttrsNix+    , add  TopLevel "placeholder"      placeHolderNix+    , add2 TopLevel "removeAttrs"      removeAttrsNix+    , add2 TopLevel "scopedImport"     scopedImportNix+    , add  TopLevel "throw"            throwNix+    , add  TopLevel "toString"         toStringNix+    , add2 TopLevel "trace"            traceNix+    , add0 Normal   "nixVersion"       nixVersionNix+    , add0 Normal   "langVersion"      langVersionNix+    , add2 Normal   "add"              addNix+    , add2 Normal   "addErrorContext"  addErrorContextNix+    , add2 Normal   "all"              allNix+    , add2 Normal   "any"              anyNix+    , add2 Normal   "appendContext"    appendContextNix+    , add  Normal   "attrNames"        attrNamesNix+    , add  Normal   "attrValues"       attrValuesNix+    , add2 Normal   "bitAnd"           bitAndNix+    , add2 Normal   "bitOr"            bitOrNix+    , add2 Normal   "bitXor"           bitXorNix+    , add0 Normal   "builtins"         builtinsBuiltinNix+    , add2 Normal   "catAttrs"         catAttrsNix+    , add' Normal   "ceil"             (arity1 (ceiling @Float @Integer))+    , add2 Normal   "compareVersions"  compareVersionsNix+    , add  Normal   "concatLists"      concatListsNix+    , add2 Normal   "concatMap"        concatMapNix+    , add' Normal   "concatStringsSep" (arity2 intercalateNixString)+    , add0 Normal   "currentSystem"    currentSystemNix+    , add0 Normal   "currentTime"      currentTimeNix+    , add2 Normal   "deepSeq"          deepSeqNix+    , add2 Normal   "div"              divNix+    , add2 Normal   "elem"             elemNix+    , add2 Normal   "elemAt"           elemAtNix+    , add  Normal   "exec"             execNix+    , add0 Normal   "false"            (pure $ NVBool False)+    --, add  Normal   "fetchGit"         fetchGit+    --, add  Normal   "fetchMercurial"   fetchMercurial+    , add  Normal   "fetchTarball"     fetchTarball+    , add  Normal   "fetchurl"         fetchurlNix+    , add2 Normal   "filter"           filterNix+    --, add  Normal   "filterSource"     filterSource+    , add2 Normal   "findFile"         findFileNix+    , add' Normal   "floor"            (arity1 (floor @Float @Integer))+    , add3 Normal   "foldl'"           foldl'Nix+    , add  Normal   "fromJSON"         fromJSONNix+    --, add  Normal   "fromTOML"         fromTOML+    , add  Normal   "functionArgs"     functionArgsNix+    , add  Normal   "genericClosure"   genericClosureNix+    , add2 Normal   "genList"          genListNix+    , add2 Normal   "getAttr"          getAttrNix+    , add  Normal   "getContext"       getContextNix+    , add  Normal   "getEnv"           getEnvNix+    , add2 Normal   "groupBy"          groupByNix+    , add2 Normal   "hasAttr"          hasAttrNix+    , add  Normal   "hasContext"       hasContextNix+    , add' Normal   "hashString"       (hashStringNix @e @t @f @m)+    , add' Normal   "hashFile"         hashFileNix+    , add  Normal   "head"             headNix+    , add2 Normal   "intersectAttrs"   intersectAttrsNix+    , add  Normal   "isAttrs"          isAttrsNix+    , add  Normal   "isBool"           isBoolNix+    , add  Normal   "isFloat"          isFloatNix+    , add  Normal   "isFunction"       isFunctionNix+    , add  Normal   "isInt"            isIntNix+    , add  Normal   "isList"           isListNix+    , add  Normal   "isString"         isStringNix+    , add  Normal   "isPath"           isPathNix+    , add  Normal   "length"           lengthNix+    , add2 Normal   "lessThan"         lessThanNix+    , add  Normal   "listToAttrs"      listToAttrsNix+    , add2 Normal   "match"            matchNix+    , add2 Normal   "mul"              mulNix+    , add0 Normal   "nixPath"          nixPathNix+    , add0 Normal   "null"             (pure NVNull)+    , add  Normal   "parseDrvName"     parseDrvNameNix+    , add2 Normal   "partition"        partitionNix+    , add  Normal   "path"             pathNix+    , add  Normal   "pathExists"       pathExistsNix+    , add  Normal   "readDir"          readDirNix+    , add  Normal   "readFile"         readFileNix+    , add3 Normal   "replaceStrings"   replaceStringsNix+    , add2 Normal   "seq"              seqNix+    , add2 Normal   "sort"             sortNix+    , add2 Normal   "split"            splitNix+    , add  Normal   "splitVersion"     splitVersionNix+    , add0 Normal   "storeDir"         (pure $ mkNVStrWithoutContext "/nix/store")+    --, add  Normal   "storePath"        storePath+    , add' Normal   "stringLength"     (arity1 $ Text.length . ignoreContext)+    , add' Normal   "sub"              (arity2 ((-) @Integer))+    , add' Normal   "substring"        substringNix+    , add  Normal   "tail"             tailNix+    , add2 Normal   "toFile"           toFileNix+    , add  Normal   "toJSON"           toJSONNix+    , add  Normal   "toPath"           toPathNix -- Deprecated in Nix: https://github.com/NixOS/nix/pull/2524+    , add  Normal   "toXML"            toXMLNix+    , add0 Normal   "true"             (pure $ NVBool True)+    , add  Normal   "tryEval"          tryEvalNix+    , add  Normal   "typeOf"           typeOfNix+    , add  Normal   "unsafeDiscardOutputDependency" unsafeDiscardOutputDependencyNix+    , add  Normal   "unsafeDiscardStringContext"    unsafeDiscardStringContextNix+    , add2 Normal   "unsafeGetAttrPos"              unsafeGetAttrPosNix+    , add  Normal   "valueSize"        getRecursiveSizeNix+    ]+ where++  arity0 :: a -> Prim m a+  arity0 = Prim . pure++  arity1 :: (a -> b) -> (a -> Prim m b)+  arity1 g = arity0 . g++  arity2 :: (a -> b -> c) -> (a -> b -> Prim m c)+  arity2 f = arity1 . f++  mkBuiltin :: BuiltinType -> VarName -> m (NValue t f m) -> m (Builtin (NValue t f m))+  mkBuiltin t n v = wrap t n <$> mkThunk n v+   where+    wrap :: BuiltinType -> VarName -> v -> Builtin v+    wrap t n f = Builtin t (n, f)++    mkThunk :: VarName -> m (NValue t f m) -> m (NValue t f m)+    mkThunk n = defer . withFrame Info (ErrorCall $ "While calling builtin " <> toString n <> "\n")++  hAdd+    :: ( VarName+      -> fun+      -> m (NValue t f m)+      )+    -> BuiltinType+    -> VarName+    -> fun+    -> m (Builtin (NValue t f m))+  hAdd f t n v = mkBuiltin t n $ f n v++  add0+    :: BuiltinType+    -> VarName+    -> m (NValue t f m)+    -> m (Builtin (NValue t f m))+  add0 = hAdd (\ _ x -> x)++  add+    :: BuiltinType+    -> VarName+    -> ( NValue t f m+      -> m (NValue t f m)+      )+    -> m (Builtin (NValue t f m))+  add = hAdd builtin++  add2+    :: BuiltinType+    -> VarName+    -> ( NValue t f m+      -> NValue t f m+      -> m (NValue t f m)+      )+    -> m (Builtin (NValue t f m))+  add2 = hAdd builtin2++  add3+    :: BuiltinType+    -> VarName+    -> ( NValue t f m+      -> NValue t f m+      -> NValue t f m+      -> m (NValue t f m)+      )+    -> m (Builtin (NValue t f m))+  add3 = hAdd builtin3++  add'+    :: ToBuiltin t f m a+    => BuiltinType+    -> VarName+    -> a+    -> m (Builtin (NValue t f m))+  add' = hAdd (toBuiltin . coerce)+++-- * Exported++-- | Evaluate expression in the default context.+withNixContext+  :: forall e t f m r+   . (MonadNix e t f m, Has e Options)+  => Maybe Path+  -> m r+  -> m r+withNixContext mpath action =+  do+    base <- builtins+    opts <- askOptions++    pushScope+      (one ("__includes", NVList $ mkNVStrWithoutContext . fromString . coerce <$> getInclude opts))+      (pushScopes+        base $+        maybe+          id+          (\ path act ->+            do+              traceM $ "Setting __cur_file = " <> show path+              pushScope (one ("__cur_file", NVPath path)) act+          )+          mpath+          action+      )++builtins+  :: forall e t f m+  . ( MonadNix e t f m+     , Scoped (NValue t f m) m+     )+  => m (Scopes m (NValue t f m))+builtins =+  do+    ref <- defer $ NVSet mempty <$> buildMap+    (`pushScope` askScopes) . coerce . M.fromList . (one ("builtins", ref) <>) =<< topLevelBuiltins+ where+  buildMap :: m (HashMap VarName (NValue t f m))+  buildMap         =  M.fromList . (mapping <$>) <$> builtinsList++  topLevelBuiltins :: m [(VarName, NValue t f m)]+  topLevelBuiltins = mapping <<$>> fullBuiltinsList++  fullBuiltinsList :: m [Builtin (NValue t f m)]+  fullBuiltinsList = nameBuiltins <<$>> builtinsList+   where+    nameBuiltins :: Builtin v -> Builtin v+    nameBuiltins b@(Builtin TopLevel _) = b+    nameBuiltins (Builtin Normal nB) =+      Builtin TopLevel $ first (coerce @(Text -> Text) ("__" <>)) nB+
src/Nix/Cache.hs view
@@ -1,48 +1,43 @@-{-# LANGUAGE CPP #-}+{-# language CPP #-} +-- | Reading and writing Nix cache files module Nix.Cache where -import qualified Data.ByteString.Lazy as BS+import           Nix.Prelude+import qualified Data.ByteString.Lazy          as BSL import           Nix.Expr.Types.Annotated -#if defined (__linux__) && MIN_VERSION_base(4, 10, 0)+#if defined (__linux__)+-- This is about: https://hackage.haskell.org/package/compact #define USE_COMPACT 1 #endif  #ifdef USE_COMPACT-import qualified Data.Compact as C-import qualified Data.Compact.Serialize as C-#endif-#ifdef MIN_VERSION_serialise-import qualified Codec.Serialise as S+import qualified Data.Compact                  as C+import qualified Data.Compact.Serialize        as C #endif+import qualified Codec.Serialise               as S -readCache :: FilePath -> IO NExprLoc+readCache :: Path -> IO NExprLoc readCache path = do #if USE_COMPACT-    eres <- C.unsafeReadCompact path-    case eres of-        Left err -> error $ "Error reading cache file: " ++ err-        Right expr -> return $ C.getCompact expr-#else-#ifdef MIN_VERSION_serialise-    eres <- S.deserialiseOrFail <$> BS.readFile path-    case eres of-        Left err -> error $ "Error reading cache file: " ++ show err-        Right expr -> return expr+  eres <- C.unsafeReadCompact path+  either+    (\ err  -> fail $ "Error reading cache file: " <> err)+    (\ expr -> pure $ C.getCompact expr)+    eres #else-    error "readCache not implemented for this platform"-#endif+  eres <- S.deserialiseOrFail <$> BSL.readFile (coerce path)+  either+    (\ err  -> fail $ "Error reading cache file: " <> show err)+    pure+    eres #endif -writeCache :: FilePath -> NExprLoc -> IO ()+writeCache :: Path -> NExprLoc -> IO () writeCache path expr = #ifdef USE_COMPACT-    C.writeCompact path =<< C.compact expr-#else-#ifdef MIN_VERSION_serialise-    BS.writeFile path (S.serialise expr)+  C.writeCompact path =<< C.compact expr #else-    error "writeCache not implemented for this platform"-#endif+  BSL.writeFile (coerce path) (S.serialise expr) #endif
+ src/Nix/Cited.hs view
@@ -0,0 +1,73 @@+{-# language DeriveAnyClass #-}+{-# language TemplateHaskell #-}++{-# options_ghc -Wno-missing-signatures #-}++module Nix.Cited where++import           Nix.Prelude+import           Control.Comonad+import           Control.Comonad.Env+import           Lens.Family2.TH++import           Nix.Expr.Types.Annotated+import           Nix.Scope+import           Nix.Value                      ( NValue, NValue'(NValue') )+import           Control.Monad.Free             ( Free(Pure, Free) )++data Provenance m v =+  Provenance+    { getLexicalScope :: Scopes m v+      --  2021-11-09: NOTE: Better name?+    , getOriginExpr   :: NExprLocF (Maybe v)+      -- ^ When calling the function x: x + 2 with argument x = 3, the+      --   'originExpr' for the resulting value will be 3 + 2, while the+      --   'contextExpr' will be @(x: x + 2) 3@, preserving not only the+      --   result of the call, but what was called and with what arguments.+    }+    deriving (Generic, Typeable, Show)++data NCited m v a =+  NCited+    { getProvenance :: [Provenance m v]+    , getCited      :: a+    }+    deriving (Generic, Typeable, Functor, Foldable, Traversable, Show)++instance Applicative (NCited m v) where+  pure = NCited mempty+  (<*>) (NCited xs f) (NCited ys x) = NCited (xs <> ys) (f x)++instance Comonad (NCited m v) where+  duplicate p = NCited (getProvenance p) p+  extract = getCited++instance ComonadEnv [Provenance m v] (NCited m v) where+  ask = getProvenance++$(makeLenses ''Provenance)+$(makeLenses ''NCited)++class HasCitations1 m v f where+  citations1 :: f a -> [Provenance m v]+  addProvenance1 :: Provenance m v -> f a -> f a++class HasCitations m v a where+  citations :: a -> [Provenance m v]+  addProvenance :: Provenance m v -> a -> a++instance HasCitations m v (NCited m v a) where+  citations = getProvenance+  addProvenance x (NCited p v) = NCited (x : p) v++instance HasCitations1 m v f+  => HasCitations m v (NValue' t f m a) where+  citations (NValue' f) = citations1 f+  addProvenance x (NValue' f) = NValue' $ addProvenance1 x f++instance (HasCitations1 m v f, HasCitations m v t)+  => HasCitations m v (NValue t f m) where+  citations (Pure t) = citations t+  citations (Free v) = citations v+  addProvenance x (Pure t) = Pure $ addProvenance x t+  addProvenance x (Free v) = Free $ addProvenance x v
+ src/Nix/Cited/Basic.hs view
@@ -0,0 +1,186 @@+{-# language GeneralizedNewtypeDeriving #-}+{-# language UndecidableInstances #-}+{-# language PatternSynonyms    #-}++module Nix.Cited.Basic where++import           Nix.Prelude+import           Control.Comonad                ( Comonad )+import           Control.Comonad.Env            ( ComonadEnv )+import           Control.Monad.Catch     hiding ( catchJust )+import           Nix.Cited+import           Nix.Eval                      as Eval+                                                ( EvalFrame(EvaluatingExpr,ForcingExpr) )+import           Nix.Exec+import           Nix.Expr.Types.Annotated+import           Nix.Frames+import           Nix.Options+import           Nix.Thunk+import           Nix.Value+++-- * data type @Cited@++newtype Cited t f m a = Cited (NCited m (NValue t f m) a)+  deriving+    ( Generic+    , Typeable+    , Functor+    , Applicative+    , Foldable+    , Traversable+    , Comonad+    , ComonadEnv [Provenance m (NValue t f m)]+    )+++-- ** Helpers++-- | @Cited@ pattern.+-- > pattern CitedP m a = Cited (NCited m a)+pattern CitedP+  :: [Provenance m (NValue t f m)]+  -> a+  -> Cited t f m a+pattern CitedP m a = Cited (NCited m a)+{-# complete CitedP #-}++-- | Take:+-- 1. Provenence info.+-- 2. Value (like thunk)+-- -> Produce cited value (thunk)+cite+  :: Functor m+  => [Provenance m (NValue t f m)]+  -> m a+  -> m (Cited t f m a)+cite v = fmap (Cited . NCited v)+++-- ** instances++instance+  HasCitations1 m (NValue t f m) (Cited t f m)+ where++  citations1 (Cited c) = citations c+  addProvenance1 x (Cited c) = Cited $ addProvenance x c++instance+  ( Has e Options+  , Framed e m+  , MonadThunk t m v+  , Typeable m+  , Typeable f+  , Typeable u+  , MonadCatch m+  )+  => MonadThunk (Cited u f m t) m v where++  thunk :: m v -> m (Cited u f m t)+  thunk mv =+    do+      opts <- askOptions++      bool+        (cite mempty)+        (\ mt ->+          do+            frames <- askFrames++            -- Gather the current evaluation context at the time of thunk+            -- creation, and record it along with the thunk.+            let+              fun :: SomeException -> [Provenance m (NValue u f m)]+              fun (fromException -> Just (EvaluatingExpr scope (Ann s e))) =+                one $ Provenance scope $ AnnF s (Nothing <$ e)+              fun _ = mempty++              ps :: [Provenance m (NValue u f m)]+              ps = foldMap (fun . frame) frames++            cite ps mt+        )+        (isThunks opts)+        (thunk mv)++  thunkId :: Cited u f m t -> ThunkId m+  thunkId (CitedP _ t) = thunkId @_ @m t++  query :: m v -> Cited u f m t -> m v+  query m (CitedP _ t) = query m t++  -- | The ThunkLoop exception is thrown as an exception with MonadThrow,+  --   which does not capture the current stack frame information to provide+  --   it in a NixException, so we catch and re-throw it here using+  --   'throwError' from Frames.hs.+  force :: Cited u f m t -> m v+  force (CitedP ps t) = handleDisplayProvenance ps $ force t++  forceEff :: Cited u f m t -> m v+  forceEff (CitedP ps t) = handleDisplayProvenance ps $ forceEff t++  further :: Cited u f m t -> m (Cited u f m t)+  further (CitedP ps t) = cite ps $ further t+++-- ** Kleisli functor HOFs++-- Please, do not use MonadThunkF for MonadThunk, later uses more straight-forward specialized line of functions.+instance+  ( Has e Options+  , Framed e m+  , MonadThunkF t m v+  , Typeable m+  , Typeable f+  , Typeable u+  , MonadCatch m+  )+  => MonadThunkF (Cited u f m t) m v where++  queryF :: (v -> m r) -> m r -> Cited u f m t -> m r+  queryF k m (CitedP _ t) = queryF k m t++  forceF :: (v -> m r) -> Cited u f m t -> m r+  forceF k (CitedP ps t) = handleDisplayProvenance ps $ forceF k t++  forceEffF :: (v -> m r) -> Cited u f m t -> m r+  forceEffF k (CitedP ps t) = handleDisplayProvenance ps $ forceEffF k t++  furtherF :: (m v -> m v) -> Cited u f m t -> m (Cited u f m t)+  furtherF k (CitedP ps t) = cite ps $ furtherF k t+++-- * Representation++handleDisplayProvenance+  :: (MonadCatch m+    , Typeable m+    , Typeable v+    , Has e Frames+    , MonadReader e m+    )+  => [Provenance m v]+  -> m a+  -> m a+handleDisplayProvenance ps f =+  catch+    (displayProvenance ps f)+    (throwError @ThunkLoop)++displayProvenance+  :: (MonadThrow m+    , MonadReader e m+    , Has e Frames+    , Typeable m+    , Typeable v+    )+  => [Provenance m v]+  -> m a+  -> m a+displayProvenance =+  handlePresence+    id+    (\ (Provenance scope e@(AnnF s _) : _) ->+      withFrame Info $ ForcingExpr scope $ wrapExprLoc s e+    )
src/Nix/Context.hs view
@@ -1,33 +1,33 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}- module Nix.Context where -import Nix.Options-import Nix.Scope-import Nix.Frames-import Nix.Utils-import Nix.Expr.Types.Annotated (SrcSpan, nullSpan)+import           Nix.Prelude+import           Nix.Options                    ( Options )+import           Nix.Scope                      ( Scopes )+import           Nix.Frames                     ( Frames )+import           Nix.Expr.Types.Annotated       ( SrcSpan+                                                , nullSpan+                                                ) -data Context m v = Context-    { scopes  :: Scopes m v-    , source  :: SrcSpan-    , frames  :: Frames-    , options :: Options+--  2021-07-18: NOTE: It should be Options -> Scopes -> Frames -> Source(span)+data Context m t =+  Context+    { getOptions :: Options+    , getScopes  :: Scopes m t+    , getSource  :: SrcSpan+    , getFrames  :: Frames     } -instance Has (Context m v) (Scopes m v) where-    hasLens f (Context x y z w) = (\x' -> Context x' y z w) <$> f x+instance Has (Context m t) (Scopes m t) where+  hasLens f a = (\x -> a { getScopes = x }) <$> f (getScopes a) -instance Has (Context m v) SrcSpan where-    hasLens f (Context x y z w) = (\y' -> Context x y' z w) <$> f y+instance Has (Context m t) SrcSpan where+  hasLens f a = (\x -> a { getSource = x }) <$> f (getSource a) -instance Has (Context m v) Frames where-    hasLens f (Context x y z w) = (\z' -> Context x y z' w) <$> f z+instance Has (Context m t) Frames where+  hasLens f a = (\x -> a { getFrames = x }) <$> f (getFrames a) -instance Has (Context m v) Options where-    hasLens f (Context x y z w) = (\w' -> Context x y z w') <$> f w+instance Has (Context m t) Options where+  hasLens f a = (\x -> a { getOptions = x }) <$> f (getOptions a) -newContext :: Options -> Context m v-newContext = Context emptyScopes nullSpan []+newContext :: Options -> Context m t+newContext o = Context o mempty nullSpan mempty
src/Nix/Convert.hs view
@@ -1,20 +1,10 @@-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MonoLocalBinds #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE MultiWayIf #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE UndecidableInstances #-}+{-# language AllowAmbiguousTypes #-}+{-# language ConstraintKinds #-}+{-# language IncoherentInstances #-}+{-# language TypeFamilies #-}+{-# language UndecidableInstances #-} -{-# OPTIONS_GHC -Wno-missing-signatures #-}-{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# options_ghc -fno-warn-name-shadowing #-}  -- | Although there are a lot of instances in this file, really it's just a --   combinatorial explosion of the following combinations:@@ -25,559 +15,471 @@  module Nix.Convert where -import           Control.Monad-import           Data.Aeson (toJSON)-import qualified Data.Aeson as A-import           Data.ByteString-import           Data.Fix-import           Data.HashMap.Lazy (HashMap)-import qualified Data.HashMap.Lazy as M-import           Data.Scientific-import           Data.Text (Text)-import qualified Data.Text as Text-import           Data.Text.Encoding (encodeUtf8, decodeUtf8)-import qualified Data.Vector as V+import           Nix.Prelude+import           Control.Monad.Free+import qualified Data.HashMap.Lazy             as M import           Nix.Atoms import           Nix.Effects import           Nix.Expr.Types-import           Nix.Expr.Types.Annotated import           Nix.Frames-import           Nix.Normal-import           Nix.Thunk-import           Nix.Utils+import           Nix.String import           Nix.Value+import           Nix.Value.Monad+import           Nix.Thunk                      ( MonadThunk(force) ) +newtype Deeper a = Deeper a+  deriving (Typeable, Functor, Foldable, Traversable)++type CoerceDeeperToNValue t f m = Deeper (NValue t f m) -> NValue t f m+type CoerceDeeperToNValue' t f m = Deeper (NValue' t f m (NValue t f m)) -> NValue' t f m (NValue t f m)++{-++IMPORTANT NOTE++We used to have Text instances of FromValue, ToValue, FromNix, and ToNix.+However, we're removing these instances because they are dangerous due to the+fact that they hide the way string contexts are handled. It's better to have to+explicitly handle string context in a way that is appropriate for the situation.++Do not add these instances back!++-}+++type Convertible e t f m+  = (Framed e m, MonadDataErrorContext t f m, MonadThunk t m (NValue t f m))++-- | Transform Nix -> Hask. Run function. Convert Hask -> Nix.+inHask :: forall a1 a2 v b m . (Monad m, FromValue a1 m v, ToValue a2 m b) => (a1 -> a2) -> v -> m b+inHask f = toValue . f <=< fromValue++inHaskM :: forall a1 a2 v b m . (Monad m, FromValue a1 m v, ToValue a2 m b) => (a1 -> m a2) -> v -> m b+inHaskM f = toValue <=< f <=< fromValue++-- | Maybe transform Nix -> Hask. Run function. Convert Hask -> Nix.+inHaskMay :: forall a1 a2 v b m . (Monad m, FromValue a1 m v, ToValue a2 m b) => (Maybe a1 -> a2) -> v -> m b+inHaskMay f = toValue . f <=< fromValueMay+++-- * FromValue+ class FromValue a m v where-    fromValue    :: v -> m a-    fromValueMay :: v -> m (Maybe a)+  fromValue    :: v -> m a+  fromValueMay :: v -> m (Maybe a) -type Convertible e m = (Framed e m, MonadVar m, Typeable m)+traverseFromValue+  :: ( Applicative m+     , Traversable t+     , FromValue b m a+     )+  => t a+  -> m (Maybe (t b))+traverseFromValue = traverse2 fromValueMay -instance Convertible e m => FromValue () m (NValueNF m) where-    fromValueMay = \case-        Fix (NVConstantF NNull) -> pure $ Just ()-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ ExpectationNF TNull v+traverseToValue+  :: ( Traversable t+     , Applicative f+     , ToValue a f b+     )+  => t a+  -> f (t b)+traverseToValue = traverse toValue -instance Convertible e m-      => FromValue () m (NValue m) where-    fromValueMay = \case-        NVConstant NNull -> pure $ Just ()-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ Expectation TNull v+-- Please, hide these helper function from export, to be sure they get optimized away.+fromMayToValue+  :: forall t f m a e+  . ( Convertible e t f m+    , FromValue a m (NValue' t f m (NValue t f m))+    )+  => ValueType+  -> NValue' t f m (NValue t f m)+  -> m a+fromMayToValue t v =+  maybe+    (throwError $ Expectation @t @f @m t (Free v))+    pure+    =<< fromValueMay v -instance Convertible e m-      => FromValue Bool m (NValueNF m) where-    fromValueMay = \case-        Fix (NVConstantF (NBool b)) -> pure $ Just b-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ ExpectationNF TBool v+fromMayToDeeperValue+  :: forall t f m a e m1+  . ( Convertible e t f m+    , FromValue (m1 a) m (Deeper (NValue' t f m (NValue t f m)))+    )+  => ValueType+  -> Deeper (NValue' t f m (NValue t f m))+  -> m (m1 a)+fromMayToDeeperValue t v =+  maybe+    (throwError $ Expectation @t @f @m t $ Free $ (coerce :: CoerceDeeperToNValue' t f m) v)+    pure+    =<< fromValueMay v -instance Convertible e m-      => FromValue Bool m (NValue m) where-    fromValueMay = \case-        NVConstant (NBool b) -> pure $ Just b-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ Expectation TBool v+instance ( Convertible e t f m+         , MonadValue (NValue t f m) m+         , FromValue a m (NValue' t f m (NValue t f m))+         )+  => FromValue a m (NValue t f m) where -instance Convertible e m-      => FromValue Int m (NValueNF m) where-    fromValueMay = \case-        Fix (NVConstantF (NInt b)) -> pure $ Just (fromInteger b)-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ ExpectationNF TInt v+  fromValueMay =+    free+      (fromValueMay <=< force)+      fromValueMay+      <=< demand -instance Convertible e m-      => FromValue Int m (NValue m) where-    fromValueMay = \case-        NVConstant (NInt b) -> pure $ Just (fromInteger b)-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ Expectation TInt v+  fromValue =+    free+      (fromValue <=< force)+      fromValue+      <=< demand -instance Convertible e m-      => FromValue Integer m (NValueNF m) where-    fromValueMay = \case-        Fix (NVConstantF (NInt b)) -> pure $ Just b-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ ExpectationNF TInt v+instance ( Convertible e t f m+         , MonadValue (NValue t f m) m+         , FromValue a m (Deeper (NValue' t f m (NValue t f m)))+         )+  => FromValue a m (Deeper (NValue t f m)) where -instance Convertible e m-      => FromValue Integer m (NValue m) where-    fromValueMay = \case-        NVConstant (NInt b) -> pure $ Just b-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ Expectation TInt v+  fromValueMay :: Deeper (NValue t f m) -> m (Maybe a)+  fromValueMay (Deeper v) =+    free+      ((fromValueMay . Deeper) <=< force)  -- these places are complex in types+      (fromValueMay . Deeper)+      =<< demand v -instance Convertible e m-      => FromValue Float m (NValueNF m) where-    fromValueMay = \case-        Fix (NVConstantF (NFloat b)) -> pure $ Just b-        Fix (NVConstantF (NInt i)) -> pure $ Just (fromInteger i)-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ ExpectationNF TFloat v+  fromValue (Deeper v) =+    free+      ((fromValue . Deeper) <=< force)+      (fromValue . Deeper)+      =<< demand v -instance Convertible e m-      => FromValue Float m (NValue m) where-    fromValueMay = \case-        NVConstant (NFloat b) -> pure $ Just b-        NVConstant (NInt i) -> pure $ Just (fromInteger i)-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ Expectation TFloat v+instance Convertible e t f m+  => FromValue () m (NValue' t f m (NValue t f m)) where -instance (Convertible e m, MonadEffects m)-      => FromValue Text m (NValueNF m) where-    fromValueMay = \case-        Fix (NVStrF t _) -> pure $ Just t-        Fix (NVPathF p) -> Just . Text.pack . unStorePath <$> addPath p-        Fix (NVSetF s _) -> case M.lookup "outPath" s of-            Nothing -> pure Nothing-            Just p -> fromValueMay @Text p-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ ExpectationNF TString v+  fromValueMay =+    pure .+      \case+        NVConstant' NNull -> stub+        _                 -> mempty -instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m, MonadEffects m)-      => FromValue Text m (NValue m) where-    fromValueMay = \case-        NVStr t _ -> pure $ Just t-        NVPath p -> Just . Text.pack . unStorePath <$> addPath p-        NVSet s _ -> case M.lookup "outPath" s of-            Nothing -> pure Nothing-            Just p -> fromValueMay @Text p-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ Expectation TString v+  fromValue = fromMayToValue TNull -instance (Convertible e m, MonadEffects m)-      => FromValue (Text, DList Text) m (NValueNF m) where-    fromValueMay = \case-        Fix (NVStrF t d) -> pure $ Just (t, d)-        Fix (NVPathF p) -> Just . (,mempty) . Text.pack . unStorePath <$> addPath p-        Fix (NVSetF s _) -> case M.lookup "outPath" s of-            Nothing -> pure Nothing-            Just p -> fmap (,mempty) <$> fromValueMay @Text p-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ ExpectationNF TString v+instance Convertible e t f m+  => FromValue Bool m (NValue' t f m (NValue t f m)) where -instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m, MonadEffects m)-      => FromValue (Text, DList Text) m (NValue m) where-    fromValueMay = \case-        NVStr t d -> pure $ Just (t, d)-        NVPath p -> Just . (,mempty) . Text.pack . unStorePath <$> addPath p-        NVSet s _ -> case M.lookup "outPath" s of-            Nothing -> pure Nothing-            Just p -> fmap (,mempty) <$> fromValueMay @Text p-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ Expectation TString v+  fromValueMay =+    pure .+      \case+        NVConstant' (NBool b) -> pure b+        _                     -> Nothing -instance Convertible e m-      => FromValue ByteString m (NValueNF m) where-    fromValueMay = \case-        Fix (NVStrF t _) -> pure $ Just (encodeUtf8 t)-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ ExpectationNF TString v+  fromValue = fromMayToValue TBool -instance Convertible e m-      => FromValue ByteString m (NValue m) where-    fromValueMay = \case-        NVStr t _ -> pure $ Just (encodeUtf8 t)-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ Expectation TString v+instance Convertible e t f m+  => FromValue Int m (NValue' t f m (NValue t f m)) where -newtype Path = Path { getPath :: FilePath }-    deriving Show+  fromValueMay =+    pure .+      \case+        NVConstant' (NInt b) -> pure $ fromInteger b+        _                    -> Nothing -instance Convertible e m => FromValue Path m (NValueNF m) where-    fromValueMay = \case-        Fix (NVPathF p) -> pure $ Just (Path p)-        Fix (NVStrF s _) -> pure $ Just (Path (Text.unpack s))-        Fix (NVSetF s _) -> case M.lookup "outPath" s of-            Nothing -> pure Nothing-            Just p -> fromValueMay @Path p-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ ExpectationNF TPath v+  fromValue = fromMayToValue TInt -instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m)-      => FromValue Path m (NValue m) where-    fromValueMay = \case-        NVPath p -> pure $ Just (Path p)-        NVStr s _ -> pure $ Just (Path (Text.unpack s))-        NVSet s _ -> case M.lookup "outPath" s of-            Nothing -> pure Nothing-            Just p -> fromValueMay @Path p-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ Expectation TPath v+instance Convertible e t f m+  => FromValue Integer m (NValue' t f m (NValue t f m)) where -instance (Convertible e m, FromValue a m (NValueNF m), Show a)-      => FromValue [a] m (NValueNF m) where-    fromValueMay = \case-        Fix (NVListF l) -> sequence <$> traverse fromValueMay l-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ ExpectationNF TList v+  fromValueMay =+    pure .+      \case+        NVConstant' (NInt b) -> pure b+        _                    -> Nothing -instance Convertible e m => FromValue [NThunk m] m (NValue m) where-    fromValueMay = \case-        NVList l -> pure $ Just l-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ Expectation TList v+  fromValue = fromMayToValue TInt -instance Convertible e m-      => FromValue (HashMap Text (NValueNF m)) m (NValueNF m) where-    fromValueMay = \case-        Fix (NVSetF s _) -> pure $ Just s-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ ExpectationNF TSet v+instance Convertible e t f m+  => FromValue Float m (NValue' t f m (NValue t f m)) where -instance Convertible e m-      => FromValue (HashMap Text (NThunk m)) m (NValue m) where-    fromValueMay = \case-        NVSet s _ -> pure $ Just s-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ Expectation TSet v+  fromValueMay =+    pure .+      \case+        NVConstant' (NFloat b) -> pure b+        NVConstant' (NInt   i) -> pure $ fromInteger i+        _                      -> Nothing -instance Convertible e m-      => FromValue (HashMap Text (NValueNF m),-                 HashMap Text SourcePos) m (NValueNF m) where-    fromValueMay = \case-        Fix (NVSetF s p) -> pure $ Just (s, p)-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ ExpectationNF TSet v+  fromValue = fromMayToValue TFloat -instance Convertible e m-      => FromValue (HashMap Text (NThunk m),-                   HashMap Text SourcePos) m (NValue m) where-    fromValueMay = \case-        NVSet s p -> pure $ Just (s, p)-        _ -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ Expectation TSet v+instance ( Convertible e t f m+         , MonadValue (NValue t f m) m+         , MonadEffects t f m+         )+  => FromValue NixString m (NValue' t f m (NValue t f m)) where -instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m)-      => FromValue (NThunk m) m (NValue m) where-    fromValueMay = pure . Just . value @_ @_ @m-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> error "Impossible, see fromValueMay"+  fromValueMay =+    \case+      NVStr' ns -> pure $ pure ns+      NVPath' p ->+        (\path -> pure $ mkNixStringWithSingletonContext (StringContext DirectPath path) path) . fromString . coerce <$>+          addPath p+      NVSet' _ s ->+        maybe+          stub+          fromValueMay+          (M.lookup "outPath" s)+      _ -> stub -instance (Monad m, FromValue a m v) => FromValue a m (m v) where-    fromValueMay = (>>= fromValueMay)-    fromValue    = (>>= fromValue)+  --  2021-07-18: NOTE: There may be cases where conversion wrongly marks the content to have a context.+  --  See: https://github.com/haskell-nix/hnix/pull/958#issuecomment-881949183 thread.+  fromValue = fromMayToValue $ TString HasContext -instance (MonadThunk (NValue m) (NThunk m) m, FromValue a m (NValue m))-      => FromValue a m (NThunk m) where-    fromValueMay = force ?? fromValueMay-    fromValue    = force ?? fromValue+instance Convertible e t f m+  => FromValue ByteString m (NValue' t f m (NValue t f m)) where -instance (Convertible e m, MonadEffects m)-      => FromValue A.Value m (NValueNF m) where-    fromValueMay = \case-        Fix (NVConstantF a) -> pure $ Just $ case a of-            NInt n   -> toJSON n-            NFloat n -> toJSON n-            NBool b  -> toJSON b-            NNull    -> A.Null-        Fix (NVStrF s _)     -> pure $ Just $ toJSON s-        Fix (NVListF l)      -> fmap (A.Array . V.fromList) . sequence-                                  <$> traverse fromValueMay l-        Fix (NVSetF m _)     -> fmap A.Object . sequence <$> traverse fromValueMay m-        Fix NVClosureF {}    -> pure Nothing-        Fix (NVPathF p)      -> Just . toJSON . unStorePath <$> addPath p-        Fix (NVBuiltinF _ _) -> pure Nothing-    fromValue v = fromValueMay v >>= \case-        Just b -> pure b-        _ -> throwError $ CoercionToJsonNF v+  fromValueMay =+    pure .+      \case+        NVStr' ns -> encodeUtf8 <$> getStringNoContext ns+        _         -> mempty -class ToValue a m v where-    toValue :: a -> m v+  fromValue = fromMayToValue $ TString mempty -instance Applicative m => ToValue () m (NValueNF m) where-    toValue _ = pure . Fix . NVConstantF $ NNull+instance Convertible e t f m+  => FromValue Text m (NValue' t f m (NValue t f m)) where -instance Applicative m => ToValue () m (NValue m) where-    toValue _ = pure . nvConstant $ NNull+  fromValueMay =+    pure .+      \case+        NVStr' ns -> getStringNoContext ns+        _         -> mempty -instance Applicative m => ToValue Bool m (NValueNF m) where-    toValue = pure . Fix . NVConstantF . NBool+  fromValue = fromMayToValue $ TString mempty -instance Applicative m => ToValue Bool m (NValue m) where-    toValue = pure . nvConstant . NBool+instance ( Convertible e t f m+         , MonadValue (NValue t f m) m+         )+  => FromValue Path m (NValue' t f m (NValue t f m)) where -instance Applicative m => ToValue Int m (NValueNF m) where-    toValue = pure . Fix . NVConstantF . NInt . toInteger+  fromValueMay =+    \case+      NVPath' p  -> pure $ pure $ coerce p+      NVStr'  ns -> pure $ coerce . toString <$> getStringNoContext  ns+      NVSet' _ s ->+        maybe+          stub+          (fromValueMay @Path)+          (M.lookup "outPath" s)+      _ -> stub -instance Applicative m => ToValue Int m (NValue m) where-    toValue = pure . nvConstant . NInt . toInteger+  fromValue = fromMayToValue TPath -instance Applicative m => ToValue Integer m (NValueNF m) where-    toValue = pure . Fix . NVConstantF . NInt+instance Convertible e t f m+  => FromValue [NValue t f m] m (NValue' t f m (NValue t f m)) where -instance Applicative m => ToValue Integer m (NValue m) where-    toValue = pure . nvConstant . NInt+  fromValueMay =+    pure .+      \case+        NVList' l -> pure l+        _         -> mempty -instance Applicative m => ToValue Float m (NValueNF m) where-    toValue = pure . Fix . NVConstantF . NFloat+  fromValue = fromMayToValue TList -instance Applicative m => ToValue Float m (NValue m) where-    toValue = pure . nvConstant . NFloat+instance ( Convertible e t f m+         , FromValue a m (NValue t f m)+         )+  => FromValue [a] m (Deeper (NValue' t f m (NValue t f m))) where+  fromValueMay =+    \case+      Deeper (NVList' l) -> traverseFromValue l+      _                  -> stub -instance Applicative m => ToValue Text m (NValueNF m) where-    toValue = pure . Fix . flip NVStrF mempty -instance Applicative m => ToValue Text m (NValue m) where-    toValue = pure . flip nvStr mempty+  fromValue = fromMayToDeeperValue TList -instance Applicative m => ToValue (Text, DList Text) m (NValueNF m) where-    toValue = pure . Fix . uncurry NVStrF+instance Convertible e t f m+  => FromValue (AttrSet (NValue t f m)) m (NValue' t f m (NValue t f m)) where -instance Applicative m => ToValue (Text, DList Text) m (NValue m) where-    toValue = pure . uncurry nvStr+  fromValueMay =+    pure .+      \case+        NVSet' _ s -> pure s+        _          -> mempty -instance Applicative m => ToValue ByteString m (NValueNF m) where-    toValue = pure . Fix . flip NVStrF mempty . decodeUtf8+  fromValue = fromMayToValue TSet -instance Applicative m => ToValue ByteString m (NValue m) where-    toValue = pure . flip nvStr mempty . decodeUtf8+instance ( Convertible e t f m+         , FromValue a m (NValue t f m)+         )+  => FromValue (AttrSet a) m (Deeper (NValue' t f m (NValue t f m))) where -instance Applicative m => ToValue Path m (NValueNF m) where-    toValue = pure . Fix . NVPathF . getPath+  fromValueMay =+    \case+      Deeper (NVSet' _ s) -> traverseFromValue s+      _                   -> stub -instance Applicative m => ToValue Path m (NValue m) where-    toValue = pure . nvPath . getPath+  fromValue = fromMayToDeeperValue TSet -instance MonadThunk (NValue m) (NThunk m) m-      => ToValue SourcePos m (NValue m) where-    toValue (SourcePos f l c) = do-        f' <- toValue (Text.pack f)-        l' <- toValue (unPos l)-        c' <- toValue (unPos c)-        let pos = M.fromList-                [ ("file" :: Text, value @_ @_ @m f')-                , ("line",        value @_ @_ @m l')-                , ("column",      value @_ @_ @m c') ]-        pure $ nvSet pos mempty+instance Convertible e t f m+  => FromValue (AttrSet (NValue t f m), PositionSet) m+              (NValue' t f m (NValue t f m)) where -instance (ToValue a m (NValueNF m), Applicative m)-      => ToValue [a] m (NValueNF m) where-    toValue = fmap (Fix . NVListF) . traverse toValue+  fromValueMay =+    pure .+      \case+        NVSet' p s -> pure (s, p)+        _          -> mempty -instance Applicative m => ToValue [NThunk m] m (NValue m) where-    toValue = pure . nvList+  fromValue = fromMayToValue TSet -instance Applicative m-      => ToValue (HashMap Text (NValueNF m)) m (NValueNF m) where-    toValue = pure . Fix . flip NVSetF M.empty+instance ( Convertible e t f m+         , FromValue a m (NValue t f m)+         )+  => FromValue (AttrSet a, PositionSet) m+              (Deeper (NValue' t f m (NValue t f m))) where -instance Applicative m => ToValue (HashMap Text (NThunk m)) m (NValue m) where-    toValue = pure . flip nvSet M.empty+  fromValueMay =+    \case+      Deeper (NVSet' p s) -> (, p) <<$>> traverseFromValue s+      _                   -> stub -instance Applicative m => ToValue (HashMap Text (NValueNF m),-                HashMap Text SourcePos) m (NValueNF m) where-    toValue (s, p) = pure $ Fix $ NVSetF s p+  fromValue = fromMayToDeeperValue TSet -instance Applicative m => ToValue (HashMap Text (NThunk m),-                HashMap Text SourcePos) m (NValue m) where-    toValue (s, p) = pure $ nvSet s p+-- This instance needs IncoherentInstances, and only because of ToBuiltin+instance ( Convertible e t f m+         , FromValue a m (NValue' t f m (NValue t f m))+         )+  => FromValue a m (Deeper (NValue' t f m (NValue t f m))) where+  fromValueMay = fromValueMay . (coerce :: CoerceDeeperToNValue' t f m)+  fromValue    = fromValue . (coerce :: CoerceDeeperToNValue' t f m) -instance (MonadThunk (NValue m) (NThunk m) m, ToValue a m (NValue m))-      => ToValue a m (NThunk m) where-    toValue = fmap (value @(NValue m) @_ @m) . toValue -instance Applicative m => ToValue Bool m (NExprF r) where-    toValue = pure . NConstant . NBool+-- * ToValue -instance Applicative m => ToValue () m (NExprF r) where-    toValue _ = pure . NConstant $ NNull+class ToValue a m v where+  toValue :: a -> m v -whileForcingThunk :: forall s e m r. (Framed e m, Exception s, Typeable m)-                  => s -> m r -> m r-whileForcingThunk frame =-    withFrame Debug (ForcingThunk @m) . withFrame Debug frame+instance (Convertible e t f m+  , ToValue a m (NValue' t f m (NValue t f m))+  )+  => ToValue a m (NValue t f m) where+  toValue v = Free <$> toValue v -instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m)-      => ToValue A.Value m (NValue m) where-    toValue = \case-        A.Object m -> flip nvSet M.empty-            <$> traverse (thunk . toValue @_ @_ @(NValue m)) m-        A.Array l -> nvList <$>-            traverse (\x -> thunk . whileForcingThunk (CoercionFromJson @m x)-                                 . toValue $ x) (V.toList l)-        A.String s -> pure $ nvStr s mempty-        A.Number n -> pure $ nvConstant $ case floatingOrInteger n of-            Left r -> NFloat r-            Right i -> NInt i-        A.Bool b -> pure $ nvConstant $ NBool b-        A.Null -> pure $ nvConstant NNull+instance ( Convertible e t f m+  , ToValue a m (Deeper (NValue' t f m (NValue t f m)))+  )+  => ToValue a m (Deeper (NValue t f m)) where+  toValue v = Free <<$>> toValue v -class FromNix a m v where-    fromNix :: v -> m a-    default fromNix :: FromValue a m v => v -> m a-    fromNix = fromValue+instance Convertible e t f m+  => ToValue () m (NValue' t f m (NValue t f m)) where+  toValue = const $ pure NVNull' -    fromNixMay :: v -> m (Maybe a)-    default fromNixMay :: FromValue a m v => v -> m (Maybe a)-    fromNixMay = fromValueMay+instance Convertible e t f m+  => ToValue Bool m (NValue' t f m (NValue t f m)) where+  toValue = pure . NVConstant' . NBool -instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m,-          FromNix a m (NValue m))-      => FromNix [a] m (NValue m) where-    fromNixMay = \case-        NVList l -> sequence <$> traverse (`force` fromNixMay) l-        _ -> pure Nothing-    fromNix v = fromNixMay v >>= \case-        Just b -> pure b-        _ -> throwError $ Expectation TList v+instance Convertible e t f m+  => ToValue Int m (NValue' t f m (NValue t f m)) where+  toValue = pure . NVConstant' . NInt . toInteger -instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m,-          FromNix a m (NValue m))-      => FromNix (HashMap Text a) m (NValue m) where-    fromNixMay = \case-        NVSet s _ -> sequence <$> traverse (`force` fromNixMay) s-        _ -> pure Nothing-    fromNix v = fromNixMay v >>= \case-        Just b -> pure b-        _ -> throwError $ Expectation TSet v+instance Convertible e t f m+  => ToValue Integer m (NValue' t f m (NValue t f m)) where+  toValue = pure . NVConstant' . NInt -instance Convertible e m => FromNix () m (NValueNF m) where-instance Convertible e m => FromNix () m (NValue m) where-instance Convertible e m => FromNix Bool m (NValueNF m) where-instance Convertible e m => FromNix Bool m (NValue m) where-instance Convertible e m => FromNix Int m (NValueNF m) where-instance Convertible e m => FromNix Int m (NValue m) where-instance Convertible e m => FromNix Integer m (NValueNF m) where-instance Convertible e m => FromNix Integer m (NValue m) where-instance Convertible e m => FromNix Float m (NValueNF m) where-instance Convertible e m => FromNix Float m (NValue m) where-instance (Convertible e m, MonadEffects m) => FromNix Text m (NValueNF m) where-instance (Convertible e m, MonadEffects m, MonadThunk (NValue m) (NThunk m) m) => FromNix Text m (NValue m) where-instance (Convertible e m, MonadEffects m) => FromNix (Text, DList Text) m (NValueNF m) where-instance (Convertible e m, MonadEffects m, MonadThunk (NValue m) (NThunk m) m) => FromNix (Text, DList Text) m (NValue m) where-instance Convertible e m => FromNix ByteString m (NValueNF m) where-instance Convertible e m => FromNix ByteString m (NValue m) where-instance Convertible e m => FromNix Path m (NValueNF m) where-instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m) => FromNix Path m (NValue m) where-instance (Convertible e m, FromValue a m (NValueNF m), Show a) => FromNix [a] m (NValueNF m) where-instance Convertible e m => FromNix (HashMap Text (NValueNF m)) m (NValueNF m) where-instance Convertible e m => FromNix (HashMap Text (NValueNF m), HashMap Text SourcePos) m (NValueNF m) where-instance Convertible e m => FromNix (HashMap Text (NThunk m), HashMap Text SourcePos) m (NValue m) where-instance (Convertible e m, MonadEffects m, MonadThunk (NValue m) (NThunk m) m) => FromNix A.Value m (NValueNF m) where+instance Convertible e t f m+  => ToValue Float m (NValue' t f m (NValue t f m)) where+  toValue = pure . NVConstant' . NFloat -instance (Convertible e m, MonadEffects m,-          MonadThunk (NValue m) (NThunk m) m) => FromNix A.Value m (NValue m) where-    fromNixMay = fromNixMay <=< normalForm-    fromNix    = fromNix <=< normalForm+instance Convertible e t f m+  => ToValue NixString m (NValue' t f m (NValue t f m)) where+  toValue = pure . NVStr' -instance (Monad m, FromNix a m v) => FromNix a m (m v) where-    fromNixMay = (>>= fromNixMay)-    fromNix    = (>>= fromNix)+instance Convertible e t f m+  => ToValue ByteString m (NValue' t f m (NValue t f m)) where+  toValue = pure . NVStr' . mkNixStringWithoutContext . decodeUtf8 -instance (MonadThunk (NValue m) (NThunk m) m, FromNix a m (NValue m))-      => FromNix a m (NThunk m) where-    fromNixMay = force ?? fromNixMay-    fromNix    = force ?? fromNix+instance Convertible e t f m+  => ToValue Text m (NValue' t f m (NValue t f m)) where+  toValue = pure . NVStr' . mkNixStringWithoutContext -instance MonadThunk (NValue m) (NThunk m) m-      => FromNix (NThunk m) m (NValue m) where-    fromNixMay = pure . Just . value-    fromNix    = pure . value+instance Convertible e t f m+  => ToValue Path m (NValue' t f m (NValue t f m)) where+  toValue = pure . NVPath' -class ToNix a m v where-    toNix :: a -> m v-    default toNix :: ToValue a m v => a -> m v-    toNix = toValue+instance Convertible e t f m+  => ToValue StorePath m (NValue' t f m (NValue t f m)) where+  toValue = toValue @Path . coerce -instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m,-          ToNix a m (NValue m))-      => ToNix [a] m (NValue m) where-    toNix = fmap nvList-        . traverse (thunk . ((\v -> whileForcingThunk (ConcerningValue v) (pure v))-                                <=< toNix))+instance Convertible e t f m+  => ToValue NSourcePos m (NValue' t f m (NValue t f m)) where+  toValue (NSourcePos f l c) = do+    f' <- toValue $ mkNixStringWithoutContext $ fromString $ coerce f+    l' <- toValue $ unPos $ coerce l+    c' <- toValue $ unPos $ coerce c+    let pos = M.fromList [("file" :: VarName, f'), ("line", l'), ("column", c')]+    pure $ NVSet' mempty pos -instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m,-          ToNix a m (NValue m))-      => ToNix (HashMap Text a) m (NValue m) where-    toNix = fmap (flip nvSet M.empty)-        . traverse (thunk . ((\v -> whileForcingThunk (ConcerningValue v) (pure v))-                                <=< toNix))+-- | With 'ToValue', we can always act recursively+instance Convertible e t f m+  => ToValue [NValue t f m] m (NValue' t f m (NValue t f m)) where+  toValue = pure . NVList' -instance Applicative m => ToNix () m (NValueNF m) where-instance Applicative m => ToNix () m (NValue m) where-instance Applicative m => ToNix Bool m (NValueNF m) where-instance Applicative m => ToNix Bool m (NValue m) where-instance Applicative m => ToNix Int m (NValueNF m) where-instance Applicative m => ToNix Int m (NValue m) where-instance Applicative m => ToNix Integer m (NValueNF m) where-instance Applicative m => ToNix Integer m (NValue m) where-instance Applicative m => ToNix Float m (NValueNF m) where-instance Applicative m => ToNix Float m (NValue m) where-instance Applicative m => ToNix Text m (NValueNF m) where-instance Applicative m => ToNix Text m (NValue m) where-instance Applicative m => ToNix (Text, DList Text) m (NValueNF m) where-instance Applicative m => ToNix (Text, DList Text) m (NValue m) where-instance Applicative m => ToNix ByteString m (NValueNF m) where-instance Applicative m => ToNix ByteString m (NValue m) where-instance Applicative m => ToNix Path m (NValueNF m) where-instance Applicative m => ToNix Path m (NValue m) where-instance Applicative m => ToNix (HashMap Text (NValueNF m)) m (NValueNF m) where-instance Applicative m => ToNix (HashMap Text (NValueNF m), HashMap Text SourcePos) m (NValueNF m) where-instance Applicative m => ToNix (HashMap Text (NThunk m), HashMap Text SourcePos) m (NValue m) where-instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m) => ToNix A.Value m (NValue m) where-instance Applicative m => ToNix Bool m (NExprF r) where-instance Applicative m => ToNix () m (NExprF r) where+instance (Convertible e t f m+  , ToValue a m (NValue t f m)+  )+  => ToValue [a] m (Deeper (NValue' t f m (NValue t f m))) where+  toValue l = Deeper . NVList' <$> traverseToValue l -instance (MonadThunk (NValue m) (NThunk m) m, ToNix a m (NValue m))-      => ToNix a m (NThunk m) where-    toNix = thunk . toNix+instance Convertible e t f m+  => ToValue (AttrSet (NValue t f m)) m (NValue' t f m (NValue t f m)) where+  toValue s = pure $ NVSet' mempty s -instance (Applicative m, ToNix a m (NValueNF m)) => ToNix [a] m (NValueNF m) where-    toNix = fmap (Fix . NVListF) . traverse toNix+instance (Convertible e t f m, ToValue a m (NValue t f m))+  => ToValue (AttrSet a) m (Deeper (NValue' t f m (NValue t f m))) where+  toValue s =+    liftA2 (\ v s -> Deeper $ NVSet' s v)+      (traverseToValue s)+      stub -instance MonadThunk (NValue m) (NThunk m) m => ToNix (NThunk m) m (NValue m) where-    toNix = force ?? pure+instance Convertible e t f m+  => ToValue (AttrSet (NValue t f m), PositionSet) m+            (NValue' t f m (NValue t f m)) where+  toValue (s, p) = pure $ NVSet' p s -convertNix :: forall a t m v. (FromNix a m t, ToNix a m v, Monad m) => t -> m v-convertNix = fromNix @a >=> toNix+instance (Convertible e t f m, ToValue a m (NValue t f m))+  => ToValue (AttrSet a, PositionSet) m+            (Deeper (NValue' t f m (NValue t f m))) where+  toValue (s, p) =+    liftA2 (\ v s -> Deeper $ NVSet' s v)+      (traverseToValue s)+      (pure p)++instance Convertible e t f m+  => ToValue NixLikeContextValue m (NValue' t f m (NValue t f m)) where+  toValue nlcv = do+    let+      g f =+        bool+          (pure Nothing)+          (pure <$> toValue True)+          (f nlcv)+    path <- g nlcvPath+    allOutputs <- g nlcvAllOutputs+    outputs <- do+      let+        outputs = mkNixStringWithoutContext <$> nlcvOutputs nlcv++      ts :: [NValue t f m] <- traverseToValue outputs+      handlePresence+        (pure Nothing)+        (fmap pure . toValue)+        ts+    pure $ NVSet' mempty $ M.fromList $ catMaybes+      [ ("path"      ,) <$> path+      , ("allOutputs",) <$> allOutputs+      , ("outputs"   ,) <$> outputs+      ]++instance Convertible e t f m => ToValue () m (NExprF (NValue t f m)) where+  toValue = const . pure . NConstant $ NNull++instance Convertible e t f m => ToValue Bool m (NExprF (NValue t f m)) where+  toValue = pure . NConstant . NBool
src/Nix/Effects.hs view
@@ -1,47 +1,463 @@+{-# language AllowAmbiguousTypes #-}+{-# language CPP #-}+{-# language DefaultSignatures #-}+{-# language TypeFamilies #-}+{-# language DataKinds #-}+{-# language GeneralizedNewtypeDeriving #-}+{-# language UndecidableInstances #-}+{-# language PackageImports #-} -- 2021-07-05: Due to hashing Haskell IT system situation, in HNix we currently ended-up with 2 hash package dependencies @{hashing, cryptonite}@+{-# language TypeOperators #-}++{-# options_ghc -Wno-orphans #-}++ module Nix.Effects where -import Data.Text (Text)-import Nix.Render-import Nix.Utils-import Nix.Value-import System.Posix.Files+import           Nix.Prelude             hiding ( putStrLn+                                                , print+                                                )+import qualified Nix.Prelude                   as Prelude+import           GHC.Exception                  ( ErrorCall(ErrorCall) )+import qualified Data.HashSet                  as HS+import qualified Data.Text                     as Text+import           Network.HTTP.Client     hiding ( path, Proxy )+import           Network.HTTP.Client.TLS+import           Network.HTTP.Types+import qualified "cryptonite" Crypto.Hash      as Hash+import           Nix.Utils.Fix1+import           Nix.Expr.Types.Annotated+import           Nix.Frames              hiding ( Proxy )+import           Nix.Parser+import           Nix.Render+import           Nix.Value+import qualified Paths_hnix+import           System.Exit+import qualified System.Info+import           System.Process +import qualified System.Nix.Store.Remote       as Store.Remote+import qualified System.Nix.StorePath          as Store+import qualified System.Nix.Nar                as Store.Nar+ -- | A path into the nix store-newtype StorePath = StorePath { unStorePath :: FilePath }+newtype StorePath = StorePath Path -class MonadFile m => MonadEffects m where-    -- | Import a path into the nix store, and return the resulting path-    addPath :: FilePath -> m StorePath -    toFile_ :: FilePath -> String -> m StorePath+-- All of the following type classes defer to the underlying 'm'. -    -- | Determine the absolute path of relative path in the current context-    makeAbsolutePath :: FilePath -> m FilePath-    findEnvPath :: String -> m FilePath+-- * @class MonadEffects t f m@ -    -- | Having an explicit list of sets corresponding to the NIX_PATH-    -- and a file path try to find an existing path-    findPath :: [NThunk m] -> FilePath -> m FilePath+class+  ( MonadFile m+  , MonadStore m+  , MonadPutStr m+  , MonadHttp m+  , MonadEnv m+  , MonadPaths m+  , MonadInstantiate m+  , MonadExec m+  , MonadIntrospect m+  )+  => MonadEffects t f m where -    pathExists :: FilePath -> m Bool-    importPath :: AttrSet (NThunk m) -> FilePath -> m (NValue m)+  -- | Determine the absolute path in the current context.+  toAbsolutePath :: Path -> m Path+  findEnvPath :: String -> m Path -    getEnvVar :: String -> m (Maybe String)-    getCurrentSystemOS :: m Text-    getCurrentSystemArch :: m Text+  -- | Having an explicit list of sets corresponding to the @NIX_PATH@ and a file path try to find an existing path.+  findPath :: [NValue t f m] -> Path -> m Path -    listDirectory :: FilePath -> m [FilePath]-    getSymbolicLinkStatus :: FilePath -> m FileStatus+  importPath :: Path -> m (NValue t f m)+  pathToDefaultNix :: Path -> m Path -    derivationStrict :: NValue m -> m (NValue m)+  derivationStrict :: NValue t f m -> m (NValue t f m) -    nixInstantiateExpr :: String -> m (NValue m)+  --  2021-04-01: for trace, so leaving String here+  traceEffect :: String -> m () -    getURL :: Text -> m (NValue m) -    getRecursiveSize :: a -> m (NValue m)+-- ** Instances -    traceEffect :: String -> m ()+instance+  ( MonadFix1T t m+  , MonadStore m+  )+  => MonadStore (Fix1T t m)+ where+  addToStore a b c d = lift $ addToStore a b c d+  addTextToStore' a b c d = lift $ addTextToStore' a b c d -    exec :: [String] -> m (NValue m)+-- * @class MonadIntrospect m@ +class+  Monad m+  => MonadIntrospect m+ where+  recursiveSize :: a -> m Word+  default recursiveSize :: (MonadTrans t, MonadIntrospect m', m ~ t m') => a -> m Word+  recursiveSize = lift . recursiveSize+++-- ** Instances++instance MonadIntrospect IO where+  recursiveSize =+#ifdef MIN_VERSION_ghc_datasize+    recursiveSize+#else+    const $ pure 0+#endif++deriving+  instance+    MonadIntrospect (t (Fix1 t))+    => MonadIntrospect (Fix1 t)++deriving+  instance+    MonadIntrospect (t (Fix1T t m) m)+    => MonadIntrospect (Fix1T t m)+++-- * @class MonadExec m@++class+  Monad m+  => MonadExec m where++    exec' :: [Text] -> m (Either ErrorCall NExprLoc)+    default exec' :: (MonadTrans t, MonadExec m', m ~ t m')+                  => [Text] -> m (Either ErrorCall NExprLoc)+    exec' = lift . exec'+++-- ** Instances++instance MonadExec IO where+  exec' = \case+    []            -> pure $ Left $ ErrorCall "exec: missing program"+    (prog : args) -> do+      (exitCode, out, _) <- liftIO $ readProcessWithExitCode (toString prog) (toString <$> args) mempty+      let+        t    = Text.strip $ fromString out+        emsg = "program[" <> prog <> "] args=" <> show args+      case exitCode of+        ExitSuccess ->+          pure $+          if Text.null t+            then Left $ ErrorCall $ toString $ "exec has no output :" <> emsg+            else+              either+                (\ err -> Left $ ErrorCall $ toString $ "Error parsing output of exec: " <> show err <> " " <> emsg)+                pure+                (parseNixTextLoc t)+        err -> pure $ Left $ ErrorCall $ toString $ "exec  failed: " <> show err <> " " <> emsg++deriving+  instance+    MonadExec (t (Fix1 t))+    => MonadExec (Fix1 t)++deriving+  instance+    MonadExec (t (Fix1T t m) m)+    => MonadExec (Fix1T t m)+++-- * @class MonadInstantiate m@++class+  Monad m+  => MonadInstantiate m where++    instantiateExpr :: Text -> m (Either ErrorCall NExprLoc)+    default instantiateExpr :: (MonadTrans t, MonadInstantiate m', m ~ t m') => Text -> m (Either ErrorCall NExprLoc)+    instantiateExpr = lift . instantiateExpr+++-- ** Instances++instance MonadInstantiate IO where++  instantiateExpr expr =+    do+      traceM $+        "Executing: " <> show ["nix-instantiate", "--eval", "--expr ", expr]++      (exitCode, out, err) <-+        readProcessWithExitCode+          "nix-instantiate"+          ["--eval", "--expr", toString expr]+          mempty++      pure $+        case exitCode of+          ExitSuccess ->+            either+              (\ e -> Left $ ErrorCall $ "Error parsing output of nix-instantiate: " <> show e)+              pure+              (parseNixTextLoc $ fromString out)+          status -> Left $ ErrorCall $ "nix-instantiate failed: " <> show status <> ": " <> err++deriving+  instance+    MonadInstantiate (t (Fix1 t))+    => MonadInstantiate (Fix1 t)++deriving+  instance+    MonadInstantiate (t (Fix1T t m) m)+    => MonadInstantiate (Fix1T t m)+++-- * @class MonadEnv m@++class+  Monad m+  => MonadEnv m where++  getEnvVar :: Text -> m (Maybe Text)+  default getEnvVar :: (MonadTrans t, MonadEnv m', m ~ t m') => Text -> m (Maybe Text)+  getEnvVar = lift . getEnvVar++  getCurrentSystemOS :: m Text+  default getCurrentSystemOS :: (MonadTrans t, MonadEnv m', m ~ t m') => m Text+  getCurrentSystemOS = lift getCurrentSystemOS++  getCurrentSystemArch :: m Text+  default getCurrentSystemArch :: (MonadTrans t, MonadEnv m', m ~ t m') => m Text+  getCurrentSystemArch = lift getCurrentSystemArch+++-- ** Instances++instance MonadEnv IO where+  getEnvVar            = (<<$>>) fromString . lookupEnv . toString++  getCurrentSystemOS   = pure $ fromString System.Info.os++  -- Invert the conversion done by GHC_CONVERT_CPU in GHC's aclocal.m4+  getCurrentSystemArch = pure $ fromString $ case System.Info.arch of+    "i386" -> "i686"+    arch   -> arch++deriving+  instance+    MonadEnv (t (Fix1 t))+    => MonadEnv (Fix1 t)++deriving+  instance+    MonadEnv (t (Fix1T t m) m)+    => MonadEnv (Fix1T t m)+++-- * @class MonadPaths m@++class+  Monad m+  => MonadPaths m where+  getDataDir :: m Path+  default getDataDir :: (MonadTrans t, MonadPaths m', m ~ t m') => m Path+  getDataDir = lift getDataDir+++-- ** Instances++instance MonadPaths IO where+  getDataDir = coerce Paths_hnix.getDataDir++deriving+  instance+    MonadPaths (t (Fix1 t))+    => MonadPaths (Fix1 t)++deriving+  instance+    MonadPaths (t (Fix1T t m) m)+    => MonadPaths (Fix1T t m)+++-- * @class MonadHttp m@++class+  Monad m+  => MonadHttp m where++  getURL :: Text -> m (Either ErrorCall StorePath)+  default getURL :: (MonadTrans t, MonadHttp m', m ~ t m') => Text -> m (Either ErrorCall StorePath)+  getURL = lift . getURL++baseNameOf :: Text -> Text+baseNameOf a = Text.takeWhileEnd (/='/') $ Text.dropWhileEnd (=='/') a++-- conversion from Store.StorePath to Effects.StorePath, different type with the same name.+toStorePath :: Store.StorePath -> StorePath+toStorePath = StorePath . coerce . decodeUtf8 @FilePath @ByteString . Store.storePathToRawFilePath++-- ** Instances++instance MonadHttp IO where+  getURL url =+    do+      let urlstr = toString url+      traceM $ "fetching HTTP URL: " <> urlstr+      req     <- parseRequest urlstr+      manager <-+        bool+          (newManager defaultManagerSettings)+          newTlsManager+          (secure req)+      response <- httpLbs (req { method = "GET" }) manager+      let status = statusCode $ responseStatus response+      let body = responseBody response+      -- let digest::Hash.Digest Hash.SHA256 = Hash.hash $ (B.concat . BL.toChunks) body+      let name = baseNameOf url+      bool+        (pure $ Left $ ErrorCall $ "fail, got " <> show status <> " when fetching url = " <> urlstr)+        -- using addTextToStore' result in different hash from the addToStore.+        -- see https://github.com/haskell-nix/hnix/pull/1051#issuecomment-1031380804+        (addToStore name (NarText $ toStrict body) False False)+        (status == 200)+++deriving+  instance+    MonadHttp (t (Fix1 t))+    => MonadHttp (Fix1 t)++deriving+  instance+    MonadHttp (t (Fix1T t m) m)+    => MonadHttp (Fix1T t m)+++-- * @class MonadPutStr m@++class+  (Monad m, MonadIO m)+  => MonadPutStr m where++  --TODO: Should this be used *only* when the Nix to be evaluated invokes a+  --`trace` operation?+  --  2021-04-01: Due to trace operation here, leaving it as String.+  putStr :: String -> m ()+  default putStr :: (MonadTrans t, MonadPutStr m', m ~ t m') => String -> m ()+  putStr = lift . Prelude.putStr+++-- ** Instances++instance MonadPutStr IO where+  putStr = Prelude.putStr++deriving+  instance+    MonadPutStr (t (Fix1 t))+    => MonadPutStr (Fix1 t)++deriving+  instance+    MonadPutStr (t (Fix1T t m) m)+    => MonadPutStr (Fix1T t m)+++-- ** Functions++putStrLn :: MonadPutStr m => String -> m ()+putStrLn = Nix.Effects.putStr . (<> "\n")++print :: (MonadPutStr m, Show a) => a -> m ()+print = putStrLn . show++-- * Store effects++-- ** Data type synonyms++type RecursiveFlag = Bool+type RepairFlag = Bool+type StorePathName = Text+type PathFilter m = Path -> m Bool+type StorePathSet = HS.HashSet StorePath+++-- ** @class MonadStore m@++data NarContent = NarFile Path | NarText ByteString+-- | convert NarContent to NarSource needed in the store API+toNarSource :: MonadIO m => NarContent -> Store.Nar.NarSource m+toNarSource (NarFile path) = Store.Nar.dumpPath $ coerce path+toNarSource (NarText text) = Store.Nar.dumpString text++class+  Monad m+  => MonadStore m where++  -- | Copy the contents of a local path(Or pure text) to the store.  The resulting store+  -- path is returned.  Note: This does not support yet support the expected+  -- `filter` function that allows excluding some files.+  addToStore :: StorePathName -> NarContent -> RecursiveFlag -> RepairFlag -> m (Either ErrorCall StorePath)+  default addToStore :: (MonadTrans t, MonadStore m', m ~ t m') => StorePathName -> NarContent -> RecursiveFlag -> RepairFlag -> m (Either ErrorCall StorePath)+  addToStore a b c d = lift $ addToStore a b c d++  -- | Like addToStore, but the contents written to the output path is a+  -- regular file containing the given string.+  addTextToStore' :: StorePathName -> Text -> Store.StorePathSet -> RepairFlag -> m (Either ErrorCall StorePath)+  default addTextToStore' :: (MonadTrans t, MonadStore m', m ~ t m') => StorePathName -> Text -> Store.StorePathSet -> RepairFlag -> m (Either ErrorCall StorePath)+  addTextToStore' a b c d = lift $ addTextToStore' a b c d+++-- *** Instances++instance MonadStore IO where++  addToStore name content recursive repair =+    either+      (\ err -> pure $ Left $ ErrorCall $ "String '" <> show name <> "' is not a valid path name: " <> err)+      (\ pathName ->+        do+          res <- Store.Remote.runStore $ Store.Remote.addToStore @Hash.SHA256 pathName (toNarSource content) recursive repair+          either+            Left -- err+            (pure . toStorePath) -- store path+            <$> parseStoreResult "addToStore" res+      )+      (Store.makeStorePathName name)++  addTextToStore' name text references repair =+    do+      res <- Store.Remote.runStore $ Store.Remote.addTextToStore name text references repair+      either+        Left -- err+        (pure . toStorePath) -- path+        <$> parseStoreResult "addTextToStore" res+++-- ** Functions++parseStoreResult :: Monad m => Text -> (Either String a, [Store.Remote.Logger]) -> m (Either ErrorCall a)+parseStoreResult name (res, logs) =+  pure $+    either+      (\ msg -> Left $ ErrorCall $ "Failed to execute '" <> toString name <> "': " <> msg <> "\n" <> show logs)+      pure+      res++addTextToStore :: (Framed e m, MonadStore m) => StorePathName -> Text -> Store.StorePathSet -> RepairFlag -> m StorePath+addTextToStore a b c d =+  either+    throwError+    pure+    =<< addTextToStore' a b c d++--  2021-10-30: NOTE: Misleading name, please rename.+-- | Add @Path@ into the Nix Store+addPath :: (Framed e m, MonadStore m) => Path -> m StorePath+addPath p =+  either+    throwError+    pure+    =<< addToStore (fromString $ coerce takeFileName p) (NarFile p) True False++toFile_ :: (Framed e m, MonadStore m) => Path -> Text -> m StorePath+toFile_ p contents = addTextToStore (fromString $ coerce p) contents mempty False
+ src/Nix/Effects/Basic.hs view
@@ -0,0 +1,279 @@+{-# language CPP #-}++module Nix.Effects.Basic where++import           Nix.Prelude             hiding ( head+                                                )+import           Relude.Unsafe                  ( head )+import           GHC.Exception                  ( ErrorCall(ErrorCall) )+import           Control.Monad                  ( foldM )+import qualified Data.HashMap.Lazy             as M+import           Data.List.Split                ( splitOn )+import qualified Data.Text                     as Text+import           Prettyprinter                  ( fillSep )+import           Nix.Convert+import           Nix.Effects+import           Nix.Exec                       ( MonadNix+                                                , evalExprLoc+                                                , nixInstantiateExpr+                                                )+import           Nix.Expr.Types+import           Nix.Expr.Types.Annotated+import           Nix.Frames+import           Nix.Parser+import           Nix.Render+import           Nix.Scope+import           Nix.String+import           Nix.Value+import           Nix.Value.Monad++#ifdef MIN_VERSION_ghc_datasize+import           GHC.DataSize+#endif+++++defaultToAbsolutePath :: forall e t f m . MonadNix e t f m => Path -> m Path+defaultToAbsolutePath origPath =+  do+    origPathExpanded <- expandHomePath origPath+    fmap+      removeDotDotIndirections+      . canonicalizePath+        =<< bool+            (fmap+              (<///> origPathExpanded)+              $ maybe+                  getCurrentDirectory+                  ( (\case+                      NVPath s -> pure $ takeDirectory s+                      val -> throwError $ ErrorCall $ "when resolving relative path, __cur_file is in scope, but is not a path; it is: " <> show val+                    ) <=< demand+                  )+                  =<< lookupVar "__cur_file"+            )+            (pure origPathExpanded)+            (isAbsolute origPathExpanded)++expandHomePath :: MonadFile m => Path -> m Path+expandHomePath (coerce -> ('~' : xs)) = (<> coerce xs) <$> getHomeDirectory+expandHomePath p          = pure p++-- | Incorrectly normalize paths by rewriting patterns like @a/b/..@ to @a@.+--   This is incorrect on POSIX systems, because if @b@ is a symlink, its+--   parent may be a different directory from @a@. See the discussion at+--   https://hackage.haskell.org/package/directory-1.3.1.5/docs/System-Directory.html#v:canonicalizePath+removeDotDotIndirections :: Path -> Path+removeDotDotIndirections = coerce . intercalate "/" . go mempty . splitOn "/" . coerce+ where+  go s       []            = reverse s+  go (_ : s) (".." : rest) = go s rest+  go s       (this : rest) = go (this : s) rest++infixr 9 <///>+(<///>) :: Path -> Path -> Path+x <///> y+  | isAbsolute y || "." `isPrefixOf` coerce y = x </> y+  | otherwise                          = joinByLargestOverlap x y+ where+  joinByLargestOverlap :: Path -> Path -> Path+  joinByLargestOverlap (splitDirectories -> xs) (splitDirectories -> ys) =+    joinPath $ head+      [ xs <> drop (length tx) ys | tx <- tails xs, tx `elem` inits ys ]++defaultFindEnvPath :: MonadNix e t f m => String -> m Path+defaultFindEnvPath = findEnvPathM . coerce++findEnvPathM :: forall e t f m . MonadNix e t f m => Path -> m Path+findEnvPathM name =+  maybe+    (fail "impossible")+    (\ v ->+      do+        l <- fromValue @[NValue t f m] =<< demand v+        findPathBy nixFilePath l name+    )+    =<< lookupVar "__nixPath"++ where+  nixFilePath :: MonadEffects t f m => Path -> m (Maybe Path)+  nixFilePath path =+    do+      absPath <- toAbsolutePath @t @f path+      isDir   <- doesDirectoryExist absPath+      absFile <-+        bool+          (pure absPath)+          (toAbsolutePath @t @f $ absPath </> "default.nix")+          isDir++      (pure absFile `whenTrue`) <$> doesFileExist absFile++findPathBy+  :: forall e t f m+   . MonadNix e t f m+  => (Path -> m (Maybe Path))+  -> [NValue t f m]+  -> Path+  -> m Path+findPathBy finder ls name =+  maybe+    (throwError $ ErrorCall $ "file ''" <> coerce name <> "'' was not found in the Nix search path (add it's using $NIX_PATH or -I)")+    pure+    =<< foldM fun mempty ls+ where+  fun+    :: MonadNix e t f m+    => Maybe Path+    -> NValue t f m+    -> m (Maybe Path)+  fun =+    maybe+      (\ nv ->+        do+          (s :: HashMap VarName (NValue t f m)) <- fromValue =<< demand nv+          p <- resolvePath s+          path <- fromValue =<< demand p++          maybe+            (tryPath path mempty)+            (\ nv' ->+              do+                mns <- fromValueMay @NixString =<< demand nv'+                tryPath path $+                  whenJust+                    (\ nsPfx ->+                      let pfx = ignoreContext nsPfx in+                      pure $ coerce $ toString pfx `whenFalse` Text.null pfx+                    )+                    mns+            )+            (M.lookup "prefix" s)+      )+      (const . pure . pure)++  tryPath :: Path -> Maybe Path -> m (Maybe Path)+  tryPath p (Just n) | n' : ns <- splitDirectories name, n == n' =+    finder $ p <///> joinPath ns+  tryPath p _ = finder $ p <///> name++  resolvePath :: HashMap VarName (NValue t f m) -> m (NValue t f m)+  resolvePath s =+    maybe+      (maybe+        (throwError $ ErrorCall $ "__nixPath must be a list of attr sets with 'path' elements, but received: " <> show s)+        (defer . fetchTarball)+        (M.lookup "uri" s)+      )+      pure+      (M.lookup "path" s)++fetchTarball+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> m (NValue t f m)+fetchTarball =+  \case+    NVSet _ s ->+      maybe+        (throwError $ ErrorCall "builtins.fetchTarball: Missing url attribute")+        (fetchFromString (M.lookup "sha256" s) <=< demand)+        (M.lookup "url" s)+    v@NVStr{} -> fetchFromString Nothing v+    v -> throwError $ ErrorCall $ "builtins.fetchTarball: Expected URI or set, got " <> show v+  <=< demand+ where+  fetchFromString+    :: Maybe (NValue t f m)+    -> NValue t f m+    -> m (NValue t f m)+  fetchFromString msha =+    \case+      NVStr ns -> fetch (ignoreContext ns) msha+      v -> throwError $ ErrorCall $ "builtins.fetchTarball: Expected URI or string, got " <> show v++{- jww (2018-04-11): This should be written using pipes in another module+    fetch :: Text -> Maybe (NThunk m) -> m (NValue t f m)+    fetch uri msha = case takeExtension uri of+        ".tgz" -> undefined+        ".gz"  -> undefined+        ".bz2" -> undefined+        ".xz"  -> undefined+        ".tar" -> undefined+        ext -> throwError $ ErrorCall $ "builtins.fetchTarball: Unsupported extension '"+                  <> ext <> "'"+-}++  fetch :: Text -> Maybe (NValue t f m) -> m (NValue t f m)+  fetch uri =+    maybe+      (nixInstantiateExpr $+        "builtins.fetchTarball \"" <> uri <> "\""+      )+      (\ v ->+        do+          nsSha <- fromValue =<< demand v++          let sha = ignoreContext nsSha++          nixInstantiateExpr $+            "builtins.fetchTarball { " <> "url    = \"" <> uri <> "\"; " <> "sha256 = \"" <> sha <> "\"; }"+      )++defaultFindPath :: MonadNix e t f m => [NValue t f m] -> Path -> m Path+defaultFindPath = findPathM++findPathM+  :: forall e t f m+   . MonadNix e t f m+  => [NValue t f m]+  -> Path+  -> m Path+findPathM = findPathBy existingPath+ where+  existingPath :: MonadEffects t f m => Path -> m (Maybe Path)+  existingPath path =+    do+      apath  <- toAbsolutePath @t @f path+      doesExist <- doesPathExist apath+      pure $ pure apath `whenTrue` doesExist++defaultImportPath+  :: (MonadNix e t f m, MonadState (HashMap Path NExprLoc, b) m)+  => Path+  -> m (NValue t f m)+defaultImportPath path =+  do+    traceM $ "Importing file " <> coerce path+    withFrame+      Info+      (ErrorCall $ "While importing file " <> show path)+      $ evalExprLoc =<<+          (maybe+            (either+              (\ err -> throwError $ ErrorCall . show $ fillSep ["Parse during import failed:", err])+              (\ expr ->+                do+                  modify $ first $ M.insert path expr+                  pure expr+              )+              =<< parseNixFileLoc path+            )+            pure  -- return expr+            . M.lookup path+          ) =<< gets fst++defaultPathToDefaultNix :: MonadNix e t f m => Path -> m Path+defaultPathToDefaultNix = pathToDefaultNixFile++-- Given a path, determine the nix file to load+pathToDefaultNixFile :: MonadFile m => Path -> m Path+pathToDefaultNixFile p =+  do+    isDir <- doesDirectoryExist p+    pure $ p </> "default.nix" `whenTrue` isDir++defaultTraceEffect :: MonadPutStr m => String -> m ()+defaultTraceEffect = Nix.Effects.putStrLn
+ src/Nix/Effects/Derivation.hs view
@@ -0,0 +1,442 @@+{-# language DataKinds #-}+{-# language NamedFieldPuns #-}+{-# language RecordWildCards #-}+{-# language PackageImports #-} -- 2021-07-05: Due to hashing Haskell IT system situation, in HNix we currently ended-up with 2 hash package dependencies @{hashing, cryptonite}@++module Nix.Effects.Derivation ( defaultDerivationStrict ) where++import           Nix.Prelude             hiding ( readFile )+import           GHC.Exception                  ( ErrorCall(ErrorCall) )+import           Data.Char                      ( isAscii+                                                , isAlphaNum+                                                )+import qualified Data.HashMap.Lazy             as M+import qualified Data.HashMap.Strict           as MS ( insert )+import qualified Data.HashSet                  as S+import           Data.Foldable                  ( foldl )+import qualified Data.Map.Strict               as Map+import qualified Data.Set                      as Set+import qualified Data.Text                     as Text++import           Text.Megaparsec+import           Text.Megaparsec.Char++import qualified "cryptonite" Crypto.Hash      as Hash -- 2021-07-05: Attrocity of Haskell hashing situation, in HNix we ended-up with 2 hash package dependencies @{hashing, cryptonite}@++import           Nix.Atoms+import           Nix.Expr.Types          hiding ( Recursive )+import           Nix.Convert+import           Nix.Effects+import           Nix.Exec                       ( MonadNix+                                                , callFunc+                                                )+import           Nix.Frames+import           Nix.Json                       ( toJSONNixString )+import           Nix.Render+import           Nix.String+import           Nix.String.Coerce+import           Nix.Value+import           Nix.Value.Monad++import qualified System.Nix.ReadonlyStore      as Store+import qualified System.Nix.Hash               as Store+import qualified System.Nix.StorePath          as Store+++--  2021-07-17: NOTE: Derivation consists of @"keys"@ @"vals"@ (of text), so underlining type boundary currently stops here.+data Derivation = Derivation+  { name :: Text+  , outputs :: Map Text Text+  , inputs :: (Set Text, Map Text [Text])+  , platform :: Text+  , builder :: Text -- should be typed as a store path+  , args :: [ Text ]+  , env :: Map Text Text+  , mFixed :: Maybe Store.SomeNamedDigest+  , hashMode :: HashMode+  , useJson :: Bool+  }+  deriving Show++data HashMode = Flat | Recursive+  deriving (Show, Eq)++makeStorePathName :: (Framed e m) => Text -> m Store.StorePathName+makeStorePathName name = case Store.makeStorePathName name of+  Left err -> throwError $ ErrorCall $ "Invalid name '" <> show name <> "' for use in a store path: " <> err+  Right spname -> pure spname++parsePath :: (Framed e m) => Text -> m Store.StorePath+parsePath p = case Store.parsePath "/nix/store" (encodeUtf8 p) of+  Left err -> throwError $ ErrorCall $ "Cannot parse store path " <> show p <> ":\n" <> show err+  Right path -> pure path++writeDerivation :: (Framed e m, MonadStore m) => Derivation -> m Store.StorePath+writeDerivation drv@Derivation{inputs, name} = do+  let (inputSrcs, inputDrvs) = inputs+  references <- Set.fromList <$> traverse parsePath (Set.toList $ inputSrcs <> Set.fromList (Map.keys inputDrvs))+  path <- addTextToStore (Text.append name ".drv") (unparseDrv drv) (S.fromList $ Set.toList references) False+  parsePath $ fromString $ coerce path++-- | Traverse the graph of inputDrvs to replace fixed output derivations with their fixed output hash.+-- this avoids propagating changes to their .drv when the output hash stays the same.+hashDerivationModulo :: (MonadNix e t f m, MonadState (b, KeyMap Text) m) => Derivation -> m (Hash.Digest Hash.SHA256)+hashDerivationModulo+  Derivation+    { mFixed = Just (Store.SomeDigest (digest :: Hash.Digest hashType))+    , outputs+    , hashMode+    } =+  case Map.toList outputs of+    [("out", path)] -> pure $+      Hash.hash @ByteString @Hash.SHA256 $+        encodeUtf8 $+          "fixed:out"+          <> (if hashMode == Recursive then ":r" else mempty)+          <> ":" <> (Store.algoName @hashType)+          <> ":" <> Store.encodeDigestWith Store.Base16 digest+          <> ":" <> path+    _outputsList -> throwError $ ErrorCall $ "This is weird. A fixed output drv should only have one output named 'out'. Got " <> show _outputsList+hashDerivationModulo+  drv@Derivation+    { inputs = ( inputSrcs+               , inputDrvs+               )+    } =+  do+    cache <- gets snd+    inputsModulo <-+      Map.fromList <$>+        traverse+          (\(path, outs) ->+            maybe+              (do+                drv' <- readDerivation $ coerce $ toString path+                hash <- Store.encodeDigestWith Store.Base16 <$> hashDerivationModulo drv'+                pure (hash, outs)+              )+              (\ hash -> pure (hash, outs))+              (M.lookup path cache)+          )+          (Map.toList inputDrvs)+    pure $ Hash.hash @ByteString @Hash.SHA256 $ encodeUtf8 $ unparseDrv $ drv {inputs = (inputSrcs, inputsModulo)}++unparseDrv :: Derivation -> Text+unparseDrv Derivation{..} =+  Text.append+    "Derive"+    $ parens+      [ -- outputs: [("out", "/nix/store/.....-out", "", ""), ...]+        serializeList $+          produceOutputInfo <$> Map.toList outputs+      , -- inputDrvs+        serializeList $+          (\(path, outs) ->+            parens [s path, serializeList $ s <$> sort outs]+          ) <$> Map.toList (snd inputs)+      , -- inputSrcs+        serializeList $ s <$> Set.toList (fst inputs)+      , s platform+      , s builder+      , -- run script args+        serializeList $ s <$> args+      , -- env (key value pairs)+        serializeList $ (\(k, v) -> parens [s k, s v]) <$> Map.toList env+      ]+  where+    produceOutputInfo (outputName, outputPath) =+      let prefix = if hashMode == Recursive then "r:" else mempty in+      parens $ (s <$>) $ ([outputName, outputPath] <>) $+        maybe+          [mempty, mempty]+          (\ (Store.SomeDigest (digest :: Hash.Digest hashType)) ->+            [prefix <> Store.algoName @hashType, Store.encodeDigestWith Store.Base16 digest]+          )+          mFixed+    parens :: [Text] -> Text+    parens ts = Text.concat ["(", Text.intercalate "," ts, ")"]++    serializeList   :: [Text] -> Text+    serializeList   ls = Text.concat ["[", Text.intercalate "," ls, "]"]++    s = Text.cons '\"' . (`Text.snoc` '\"') . Text.concatMap escape++    escape :: Char -> Text+    escape '\\' = "\\\\"+    escape '\"' = "\\\""+    escape '\n' = "\\n"+    escape '\r' = "\\r"+    escape '\t' = "\\t"+    escape c = one c++readDerivation :: (Framed e m, MonadFile m) => Path -> m Derivation+readDerivation path = do+  content <- readFile path+  either+    (\ err -> throwError $ ErrorCall $ "Failed to parse " <> show path <> ":\n" <> show err)+    pure+    (parse derivationParser (coerce path) content)++derivationParser :: Parsec () Text Derivation+derivationParser = do+  _ <- "Derive("+  fullOutputs <- serializeList $+    (\[n, p, ht, h] -> (n, p, ht, h)) <$> parens s+  _ <- ","+  inputDrvs   <- Map.fromList <$> serializeList+    (liftA2 (,) ("(" *> s <* ",") (serializeList s <* ")"))+  _ <- ","+  inputSrcs   <- Set.fromList <$> serializeList s+  _ <- ","+  platform    <- s+  _ <- ","+  builder     <- s+  _ <- ","+  args        <- serializeList s+  _ <- ","+  env         <- fmap Map.fromList $ serializeList $ (\[a, b] -> (a, b)) <$> parens s+  _ <- ")"+  eof++  let outputs = Map.fromList $ (\(a, b, _, _) -> (a, b)) <$> fullOutputs+  let (mFixed, hashMode) = parseFixed fullOutputs+  let name = mempty -- FIXME (extract from file path ?)+  let useJson = one "__json" == Map.keys env++  pure $ Derivation {inputs = (inputSrcs, inputDrvs), ..}+ where+  s :: Parsec () Text Text+  s = fmap fromString $ string "\"" *> manyTill (escaped <|> regular) (string "\"")+  escaped = char '\\' *>+    (   '\n' <$ string "n"+    <|> '\r' <$ string "r"+    <|> '\t' <$ string "t"+    <|> anySingle+    )+  regular = noneOf ['\\', '"']++  wrap o c p =+    string o *> sepBy p (string ",") <* string c++  parens :: Parsec () Text a -> Parsec () Text [a]+  parens = wrap "(" ")"+  serializeList :: Parsec () Text a -> Parsec () Text [a]+  serializeList = wrap "[" "]"++  parseFixed :: [(Text, Text, Text, Text)] -> (Maybe Store.SomeNamedDigest, HashMode)+  parseFixed fullOutputs = case fullOutputs of+    [("out", _path, rht, hash)] | rht /= mempty && hash /= mempty ->+      let+        (hashType, hashMode) = case Text.splitOn ":" rht of+          ["r", ht] -> (ht, Recursive)+          [ht] ->      (ht, Flat)+          _ -> error $ "Unsupported hash type for output of fixed-output derivation in .drv file: " <> show fullOutputs+      in+        either+          -- Please, no longer `error show` after migrating to Text+          (\ err -> error $ show $ "Unsupported hash " <> show (hashType <> ":" <> hash) <> "in .drv file: " <> err)+          (\ digest -> (pure digest, hashMode))+          (Store.mkNamedDigest hashType hash)+    _ -> (Nothing, Flat)+++defaultDerivationStrict :: forall e t f m b. (MonadNix e t f m, MonadState (b, KeyMap Text) m) => NValue t f m -> m (NValue t f m)+defaultDerivationStrict val = do+    s <- M.mapKeys coerce <$> fromValue @(AttrSet (NValue t f m)) val+    (drv, ctx) <- runWithStringContextT' $ buildDerivationWithContext s+    drvName <- makeStorePathName $ name drv+    let+      inputs = toStorePaths ctx+      ifNotJsonModEnv f =+        bool f id (useJson drv)+          (env drv)++    -- Compute the output paths, and add them to the environment if needed.+    -- Also add the inputs, just computed from the strings contexts.+    drv' <- case mFixed drv of+      Just (Store.SomeDigest digest) -> do+        let+          out = pathToText $ Store.makeFixedOutputPath "/nix/store" (hashMode drv == Recursive) digest drvName+          env' = ifNotJsonModEnv $ Map.insert "out" out+        pure $ drv { inputs, env = env', outputs = one ("out", out) }++      Nothing -> do+        hash <- hashDerivationModulo $ drv+          { inputs+        --, outputs = Map.map (const "") (outputs drv)  -- not needed, this is already the case+          , env =+              ifNotJsonModEnv+                (\ baseEnv ->+                  foldl'+                    (\m k -> Map.insert k mempty m)+                    baseEnv+                    (Map.keys $ outputs drv)+                )+          }+        outputs' <- sequenceA $ Map.mapWithKey (\o _ -> makeOutputPath o hash drvName) $ outputs drv+        pure $ drv+          { inputs+          , outputs = outputs'+          , env = ifNotJsonModEnv (outputs' <>)+          }++    (coerce @Text @VarName -> drvPath) <- pathToText <$> writeDerivation drv'++    -- Memoize here, as it may be our last chance in case of readonly stores.+    drvHash <- Store.encodeDigestWith Store.Base16 <$> hashDerivationModulo drv'+    modify $ second $ MS.insert (coerce drvPath) drvHash++    let+      outputsWithContext =+        Map.mapWithKey+          (\out (coerce -> path) -> mkNixStringWithSingletonContext (StringContext (DerivationOutput out) drvPath) path)+          (outputs drv')+      drvPathWithContext = mkNixStringWithSingletonContext (StringContext AllOutputs drvPath) drvPath+      attrSet = NVStr <$> M.fromList (("drvPath", drvPathWithContext) : Map.toList outputsWithContext)+    -- TODO: Add location information for all the entries.+    --              here --v+    pure $ NVSet mempty $ M.mapKeys coerce attrSet++  where++    pathToText = decodeUtf8 . Store.storePathToRawFilePath++    makeOutputPath o h n = do+      name <- makeStorePathName $ Store.unStorePathName n <> if o == "out" then mempty else "-" <> o+      pure $ pathToText $ Store.makeStorePath "/nix/store" ("output:" <> encodeUtf8 o) h name++    toStorePaths :: HashSet StringContext -> (Set Text, Map Text [Text])+    toStorePaths = foldl (flip addToInputs) mempty++    addToInputs :: Bifunctor p => StringContext -> p (Set Text) (Map Text [Text])  -> p (Set Text) (Map Text [Text])+    addToInputs (StringContext kind (coerce -> path)) =+      case kind of+        DirectPath -> first $ Set.insert path+        DerivationOutput o -> second $ Map.insertWith (<>) path $ one o+        AllOutputs ->+          -- TODO: recursive lookup. See prim_derivationStrict+          -- XXX: When is this really used ?+          error "Not implemented: derivations depending on a .drv file are not yet supported."+++-- | Build a derivation in a context collecting string contexts.+-- This is complex from a typing standpoint, but it allows to perform the+-- full computation without worrying too much about all the string's contexts.+buildDerivationWithContext :: forall e t f m. (MonadNix e t f m) => KeyMap (NValue t f m) -> WithStringContextT m Derivation+buildDerivationWithContext drvAttrs = do+    -- Parse name first, so we can add an informative frame+    drvName     <- getAttr   "name"                      $ assertDrvStoreName <=< extractNixString+    withFrame' Info (ErrorCall $ "While evaluating derivation " <> show drvName) $ do++      useJson     <- getAttrOr "__structuredAttrs" False     pure+      ignoreNulls <- getAttrOr "__ignoreNulls"     False     pure++      args        <- getAttrOr "args"              mempty  $ traverse (extractNixString <=< fromValue')+      builder     <- getAttr   "builder"                     extractNixString+      platform    <- getAttr   "system"                    $ assertNonNull <=< extractNoCtx+      mHash       <- getAttrOr "outputHash"        mempty  $ (pure . pure) <=< extractNoCtx+      hashMode    <- getAttrOr "outputHashMode"    Flat    $ parseHashMode <=< extractNoCtx+      outputs     <- getAttrOr "outputs"       (one "out") $ traverse (extractNoCtx <=< fromValue')++      mFixedOutput <-+        maybe+          (pure Nothing)+          (\ hash -> do+            when (outputs /= one "out") $ lift $ throwError $ ErrorCall "Multiple outputs are not supported for fixed-output derivations"+            hashType <- getAttr "outputHashAlgo" extractNoCtx+            digest <- lift $ either (throwError . ErrorCall) pure $ Store.mkNamedDigest hashType hash+            pure $ pure digest)+          mHash++      -- filter out null values if needed.+      attrs <-+        lift $+          bool+            (pure drvAttrs)+            (M.mapMaybe id <$>+              traverse+                (fmap+                  (\case+                    NVConstant NNull -> Nothing+                    _value           -> Just _value+                  )+                  . demand+                )+                drvAttrs+            )+            ignoreNulls++      env <- if useJson+        then do+          jsonString :: NixString <- lift $ toJSONNixString $ NVSet mempty $ M.mapKeys coerce $+            deleteKeys [ "args", "__ignoreNulls", "__structuredAttrs" ] attrs+          rawString :: Text <- extractNixString jsonString+          pure $ one ("__json", rawString)+        else+          traverse (extractNixString <=< lift . coerceAnyToNixString callFunc CopyToStore) $+            Map.fromList $ M.toList $ deleteKeys [ "args", "__ignoreNulls" ] attrs++      pure $ Derivation { platform, builder, args, env,  hashMode, useJson+        , name = drvName+        , outputs = Map.fromList $ (, mempty) <$> outputs+        , mFixed = mFixedOutput+        , inputs = mempty -- stub for now+        }+  where++    -- common functions, lifted to WithStringContextT++    fromValue' :: (FromValue a m (NValue' t f m (NValue t f m)), MonadNix e t f m) => NValue t f m -> WithStringContextT m a+    fromValue' = lift . fromValue++    withFrame' :: (Framed e m, Exception s) => NixLevel -> s -> WithStringContextT m a -> WithStringContextT m a+    withFrame' level f = join . lift . withFrame level f . pure++    -- shortcuts to get the (forced) value of an KeyMap field++    getAttrOr' :: forall v a. (MonadNix e t f m, FromValue v m (NValue' t f m (NValue t f m)))+      => Text -> m a -> (v -> WithStringContextT m a) -> WithStringContextT m a+    getAttrOr' n d f = case M.lookup n drvAttrs of+      Nothing -> lift d+      Just v  -> withFrame' Info (ErrorCall $ "While evaluating attribute '" <> show n <> "'") $+                   f =<< fromValue' v++    getAttrOr n = getAttrOr' n . pure++    getAttr n = getAttrOr' n (throwError $ ErrorCall $ "Required attribute '" <> show n <> "' not found.")++    -- Test validity for fields++    assertDrvStoreName :: MonadNix e t f m => Text -> WithStringContextT m Text+    assertDrvStoreName name = lift $ do+      let invalid c = not $ isAscii c && (isAlphaNum c || c `elem` ("+-._?=" :: String)) -- isAlphaNum allows non-ascii chars.+      let failWith reason = throwError $ ErrorCall $ "Store name " <> show name <> " " <> reason+      when ("." `Text.isPrefixOf` name)    $ failWith "cannot start with a period"+      when (Text.length name > 211)        $ failWith "must be no longer than 211 characters"+      when (Text.any invalid name)         $ failWith "contains some invalid character"+      when (".drv" `Text.isSuffixOf` name) $ failWith "is not allowed to end in '.drv'"+      pure name++    extractNoCtx :: MonadNix e t f m => NixString -> WithStringContextT m Text+    extractNoCtx ns =+      maybe+        (lift $ throwError $ ErrorCall $ "The string " <> show ns <> " is not allowed to have a context.")+        pure+        (getStringNoContext ns)++    assertNonNull :: MonadNix e t f m => Text -> WithStringContextT m Text+    assertNonNull t = do+      when (Text.null t) $ lift $ throwError $ ErrorCall "Value must not be empty"+      pure t++    parseHashMode :: MonadNix e t f m => Text -> WithStringContextT m HashMode+    parseHashMode = \case+      "flat" ->      pure Flat+      "recursive" -> pure Recursive+      other -> lift $ throwError $ ErrorCall $ "Hash mode " <> show other <> " is not valid. It must be either 'flat' or 'recursive'"++    -- Other helpers++    deleteKeys :: [Text] -> KeyMap a -> KeyMap a+    deleteKeys keys attrSet = foldl' (flip M.delete) attrSet keys+
src/Nix/Eval.hs view
@@ -1,376 +1,581 @@-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE TypeApplications #-}+{-# language AllowAmbiguousTypes #-}+{-# language ConstraintKinds #-}+{-# language RankNTypes #-} -{-# OPTIONS_GHC -fno-warn-name-shadowing #-}  module Nix.Eval where -import           Control.Monad-import           Control.Monad.Fix-import           Control.Monad.Reader-import           Control.Monad.State.Strict-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)-import           Data.List.NonEmpty (NonEmpty(..))-import           Data.Maybe (fromMaybe, catMaybes)-import           Data.Text (Text)-import           Data.These (These(..))-import           Data.Traversable (for)+import           Nix.Prelude+import           Relude.Extra                   ( set )+import           Control.Monad                  ( foldM )+import           Control.Monad.Fix              ( MonadFix )+import           GHC.Exception                  ( ErrorCall(ErrorCall) )+import           Data.Semialign.Indexed         ( ialignWith )+import qualified Data.HashMap.Lazy             as M+import           Data.List                      ( partition )+import           Data.These                     ( These(..) ) import           Nix.Atoms import           Nix.Convert-import           Nix.Expr+import           Nix.Expr.Types+import           Nix.Expr.Types.Annotated+import           Nix.Expr.Strings               ( runAntiquoted ) import           Nix.Frames+import           Nix.String import           Nix.Scope-import           Nix.Strings (runAntiquoted)-import           Nix.Thunk-import           Nix.Utils+import           Nix.Value.Monad -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-    evalCurPos      :: m v-    evalConstant    :: NAtom -> m v-    evalString      :: NString (m v) -> m v-    evalLiteralPath :: FilePath -> m v-    evalEnvPath     :: FilePath -> m v-    evalUnary       :: NUnaryOp -> v -> m v-    evalBinary      :: NBinaryOp -> v -> m v -> m v-    -- ^ The second argument is an action because operators such as boolean &&-    -- and || may not evaluate the second argument.-    evalWith        :: m v -> m v -> m v-    evalIf          :: v -> m v -> m v -> m v-    evalAssert      :: v -> m v -> m v-    evalApp         :: v -> m v -> m v-    evalAbs         :: Params (m v)-                    -> (forall a. m v -> (AttrSet (m v) -> m v -> m (a, v)) -> m (a, v))-                    -> m v+class (Show v, Monad m) => MonadEval v m where+  freeVariable    :: VarName -> m v+  synHole         :: VarName -> m v+  attrMissing     :: NonEmpty VarName -> Maybe v -> m v+  evaledSym       :: VarName -> v -> m v+  evalCurPos      :: m v+  evalConstant    :: NAtom -> m v+  evalString      :: NString (m v) -> m v+  evalLiteralPath :: Path -> m v+  evalEnvPath     :: Path -> m v+  evalUnary       :: NUnaryOp -> v -> m v+  evalBinary      :: NBinaryOp -> v -> m v -> m v+  -- ^ The second argument is an action because operators such as boolean &&+  -- and || may not evaluate the second argument.+  evalWith        :: m v -> m v -> m v+  evalIf          :: v -> m v -> m v -> m v+  evalAssert      :: v -> m v -> m v+  evalApp         :: v -> m v -> m v+  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+  evalSelect     :: v -> NonEmpty Text -> Maybe (m v) -> m v+  evalHasAttr    :: v -> NonEmpty Text -> m v -    -- | This and the following methods are intended to allow things like-    --   adding provenance information.-    evalListElem   :: [m v] -> Int -> m v -> m v-    evalList       :: [t] -> m v-    evalSetElem    :: AttrSet (m v) -> Text -> m v -> m v-    evalSet        :: AttrSet t -> AttrSet SourcePos -> m v-    evalRecSetElem :: AttrSet (m v) -> Text -> m v -> m v-    evalRecSet     :: AttrSet t -> AttrSet SourcePos -> m v-    evalLetElem    :: Text -> m v -> m v-    evalLet        :: m v -> m v+  -- | This and the following methods are intended to allow things like+  --   adding provenance information.+  evalListElem   :: [m v] -> Int -> m v -> m v+  evalList       :: [v] -> m v+  evalSetElem    :: AttrSet (m v) -> Text -> m v -> m v+  evalSet        :: AttrSet v -> PositionSet -> m v+  evalRecSetElem :: AttrSet (m v) -> Text -> m v -> m v+  evalRecSet     :: AttrSet v -> PositionSet -> m v+  evalLetElem    :: Text -> m v -> m v+  evalLet        :: m v -> m v -}-    evalError :: Exception s => s -> m a+  evalError :: Exception s => s -> m a -type MonadNixEval e v t m =-    (MonadEval v m,-     Scoped e t m,-     MonadThunk v t m,-     MonadFix m,-     ToValue Bool m v,-     ToValue [t] m v,-     FromValue (Text, DList Text) m v,-     ToValue (AttrSet t, AttrSet SourcePos) m v,-     FromValue (AttrSet t, AttrSet SourcePos) m v)+type MonadNixEval v m+  = ( MonadEval v m+  , Scoped v m+  , MonadValue v m+  , MonadFix m+  , ToValue Bool m v+  , ToValue [v] m v+  , FromValue NixString m v+  , ToValue (AttrSet v, PositionSet) m v+  , FromValue (AttrSet v, PositionSet) m v+  )  data EvalFrame m v-    = EvaluatingExpr (Scopes m v) NExprLoc-    | ForcingExpr (Scopes m v) NExprLoc-    | Calling String SrcSpan-    deriving (Show, Typeable)+  = EvaluatingExpr (Scopes m v) NExprLoc+  | ForcingExpr (Scopes m v) NExprLoc+  | Calling VarName SrcSpan+  | SynHole (SynHoleInfo m v)+  deriving (Show, Typeable)  instance (Typeable m, Typeable v) => Exception (EvalFrame m v) -eval :: forall e v t m. MonadNixEval e v t m => NExprF (m v) -> m v+data SynHoleInfo m v = SynHoleInfo+  { _synHoleInfo_expr :: NExprLoc+  , _synHoleInfo_scope :: Scopes m v+  }+  deriving (Show, Typeable) +instance (Typeable m, Typeable v) => Exception (SynHoleInfo m v)++-- jww (2019-03-18): By deferring only those things which must wait until+-- context of us, this can be written as:+-- eval :: forall v m . MonadNixEval v m => NExprF v -> m v+eval :: forall v m . MonadNixEval v m => NExprF (m v) -> m v+ eval (NSym "__curPos") = evalCurPos -eval (NSym var) =-    lookupVar var >>= maybe (freeVariable var) (force ?? evaledSym var)+eval (NSym var       ) =+  do+    mVal <- lookupVar var+    maybe+      (freeVariable var)+      (evaledSym var <=< demand)+      mVal -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 (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-    fun >>= (`evalApp` withScopes scope arg)+eval (NApp fun arg        ) =+  do+    f <- fun+    scope <- askScopes+    evalApp f $ withScopes scope arg -eval (NBinary op larg rarg) = larg >>= evalBinary op ?? rarg+eval (NBinary op   larg rarg) =+  do+    lav <- larg+    evalBinary op lav rarg -eval (NSelect aset attr alt) = evalSelect aset attr >>= either go id-  where-    go (s, ks) = fromMaybe (attrMissing ks (Just s)) alt+eval (NSelect alt aset attr) =+  do+    let useAltOrReportMissing (s, ks) = fromMaybe (attrMissing ks $ pure s) alt -eval (NHasAttr aset attr) = evalSelect aset attr >>= toValue . isRight+    eAttr <- evalSelect aset attr+    either useAltOrReportMissing id (coerce eAttr) -eval (NList l) = do-    scope <- currentScopes-    for l (thunk . withScopes @t scope) >>= toValue+eval (NHasAttr aset attr) =+  do+    eAttr <- evalSelect aset attr+    toValue $ isRight eAttr -eval (NSet binds) =-    evalBinds False (desugarBinds (eval . NSet) binds) >>= toValue+eval (NList l           ) =+  do+    scope <- askScopes+    toValue =<< traverse (defer @v @m . withScopes @v scope) l -eval (NRecSet binds) =-    evalBinds True (desugarBinds (eval . NRecSet) binds) >>= toValue+eval (NSet r binds) =+  do+    attrSet <- evalBinds (r == Recursive) $ desugarBinds (eval . NSet mempty) binds+    toValue attrSet -eval (NLet binds body) = evalBinds True binds >>= (pushScope ?? body) . fst+eval (NLet binds body    ) =+  do+    (attrSet, _) <- evalBinds True binds+    pushScope (coerce attrSet) body -eval (NIf cond t f) = cond >>= \v -> evalIf v t f+eval (NIf cond t f       ) =+  do+    v <- cond+    evalIf v t f -eval (NWith scope body) = evalWith scope body+eval (NWith   scope  body) = evalWith scope body -eval (NAssert cond body) = cond >>= evalAssert ?? body+eval (NAssert cond   body) =+  do+    x <- cond+    evalAssert x body -eval (NAbs params body) = do-    -- It is the environment at the definition site, not the call site, that-    -- needs to be used when evaluating the body and default arguments, hence-    -- 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)+eval (NAbs    params body) = do+  -- It is the environment at the definition site, not the call site, that+  -- needs to be used when evaluating the body and default arguments, hence we+  -- defer here so the present scope is restored when the parameters and body+  -- are forced during application.+  curScope <- askScopes+  let+    withCurScope = withScopes curScope --- | If you know that the 'scope' action will result in an 'AttrSet t', then+    fun :: m v -> (AttrSet (m v) -> m v -> m r) -> m r+    fun arg k =+      withCurScope $+        do+          (coerce -> newScopeToAdd) <- buildArgument params arg+          pushScope+            newScopeToAdd $+            k+              (coerce $ withCurScope . inform <$> newScopeToAdd)+              body++  evalAbs+    params+    fun++eval (NSynHole name) = synHole name++-- | If you know that the 'scope' action will result in an 'AttrSet v', 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 :: forall v m . MonadNixEval v m => m v -> m v -> m v 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.-    scope <- currentScopes @_ @t-    s <- thunk $ withScopes scope aset-    pushWeakScope ?? body $ force s $-        fmap fst . fromValue @(AttrSet t, AttrSet SourcePos)+  scopes <- askScopes+  -- The scope is deliberately wrapped in a thunk here, since it is demanded+  -- 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.+  deferredAset <- defer $ withScopes scopes aset+  let weakscope = coerce . fst <$> (fromValue @(AttrSet v, PositionSet) =<< demand deferredAset) -attrSetAlter :: forall e v t m. MonadNixEval e v t m-             => [Text]-             -> SourcePos-             -> AttrSet (m v)-             -> AttrSet SourcePos-             -> m v-             -> m (AttrSet (m v), AttrSet SourcePos)-attrSetAlter [] _ _ _ _ =-    evalError @v $ ErrorCall "invalid selector with no components"+  pushWeakScope weakscope body -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)+attrSetAlter+  :: forall v m+   . MonadNixEval v m+  => [VarName]+  -> NSourcePos+  -> AttrSet (m v)+  -> PositionSet+  -> m v+  -> m (AttrSet (m v), PositionSet)+attrSetAlter ks' pos m' p' val =+  swap <$> go p' m' ks'+ where+  -- This `go` does traverse in disquise. Notice how it traverses `ks`.+  go+    :: PositionSet+    -> AttrSet (m v)+    -> [VarName]+    -> m (PositionSet, AttrSet (m v))+  go _ _ [] = evalError @v $ ErrorCall "invalid selector with no components"+  go p m (k : ks) =+    bool+      (pure $ insertVal val)+      (maybe+        (recurse mempty mempty)+        (\x ->+          do+            --  2021-10-12: NOTE: swapping sourcewide into (PositionSet, AttrSet) would optimize code and remove this `swap`+            (swap -> (sp, st)) <- fromValue @(AttrSet v, PositionSet) =<< x+            recurse sp $ demand <$> st+        )+        ((`M.lookup` m) k)+      )+      (isPresent ks)+   where+    insertVal :: m v -> (PositionSet, AttrSet (m v))+    insertVal v =+      ( insertPos+      , insertV v+      )+     where+      insertV v' = M.insert k v' m+      insertPos = 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 )+    recurse+      :: PositionSet+      -> AttrSet (m v)+      -> m ( PositionSet+          , AttrSet (m v)+          )+    recurse p'' m'' =+      insertVal . ((toValue @(AttrSet v, PositionSet)) <=< ((,mempty) <$>) . sequenceA . snd) <$> go p'' m'' ks -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 (SourcePos, [Binding r]))-                     (Either VarName (Binding r))-    collect (NamedVar (StaticKey x :| y:ys) val p) = do-        m <- get-        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+desugarBinds :: forall r . ([Binding r] -> r) -> [Binding r] -> [Binding r]+desugarBinds embed = (`evalState` mempty) . traverse (findBinding <=< collect)+ where+  collect+    :: Binding r+    -> State+         (AttrSet (NSourcePos, [Binding r]))+         (Either VarName (Binding r))+  collect (NamedVar (StaticKey x :| y : ys) val oldPosition) =+    do+      modify updateBindingInformation+      pure $ Left x+   where+    updateBindingInformation+      :: AttrSet (NSourcePos, [Binding r])+      -> AttrSet (NSourcePos, [Binding r])+    updateBindingInformation =+      M.insert x+        =<< maybe+            (mkBindingSingleton oldPosition)+            (\ (foundPosition, newBindings) -> second (<> newBindings) $ mkBindingSingleton foundPosition)+            . M.lookup x+    mkBindingSingleton :: NSourcePos -> (NSourcePos, [Binding r])+    mkBindingSingleton np = (np , one $ bindValAt np)+     where+      bindValAt :: NSourcePos -> Binding r+      bindValAt = NamedVar (y :| ys) val+  collect x = pure $ pure x -    go :: Either VarName (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 :| []) (embed v) p+  findBinding+    :: Either VarName (Binding r)+    -> State (AttrSet (NSourcePos, [Binding r])) (Binding r)+  findBinding =+    either+      (\ x ->+        maybe+          (error $ "No binding " <> show x)+          (\ (p, v) -> pure $ NamedVar (one $ StaticKey x) (embed v) p)+          =<< gets (M.lookup x)+      )+      pure -evalBinds :: forall e v t m. MonadNixEval e v t m-          => Bool-          -> [Binding (m v)]-          -> m (AttrSet t, AttrSet SourcePos)-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" :| []) _ _pos -> True-                         _ -> False)+evalBinds+  :: forall v m+   . MonadNixEval v m+--  2021-07-19: NOTE: Recutsivity data type+  => Bool+  -> [Binding (m v)]+--  2021-07-19: NOTE: AttrSet is a Scope+  -> m (AttrSet v, PositionSet)+evalBinds isRecursive binds =+  do+    scope <- askScopes -    go :: Scopes m t -> Binding (m v) -> m [([Text], SourcePos, m v)]-    go _ (NamedVar (StaticKey "__overrides" :| []) finalValue pos) =-        finalValue >>= fromValue >>= \(o', p') ->-            -- 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')+    buildResult scope . fold =<< (`traverse` moveOverridesLast binds) (applyBindToAdt scope) -    go _ (NamedVar pathExpr finalValue pos) = do-        let go :: NAttrPath (m v) -> m ([Text], SourcePos, m v)-            go = \case-                h :| t -> evalSetterKeyName h >>= \case-                    Nothing ->-                        pure ([], nullPos,-                              toValue @(AttrSet t, AttrSet SourcePos)-                                  (mempty, mempty))-                    Just k -> case t of-                        [] -> pure ([k], pos, finalValue)-                        x:xs -> do-                            (restOfPath, _, v) <- go (x:|xs)-                            pure (k : restOfPath, pos, v)-        go pathExpr <&> \case-            -- When there are no path segments, e.g. `${null} = 5;`, we don't-            -- bind anything-            ([], _, _) -> []-            result -> [result]+ where+  buildResult+    :: Scopes m v+    -> [([VarName], NSourcePos, m v)]+    -> m (AttrSet v, PositionSet)+  buildResult scopes bindings =+    do+      (coerce -> scope, p) <- foldM insert mempty bindings+      res <-+        bool+          (traverse mkThunk)+          (loebM . fmap encapsulate)+          isRecursive+          scope -    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-                        >>= fromValue @(AttrSet t, AttrSet SourcePos)-                        >>= \(s, _) ->-                            clearScopes @t $ pushScope s $ lookupVar key-                case mv of-                    Nothing -> attrMissing (key :| []) Nothing-                    Just v -> force v pure)+      pure (coerce res, p) -    buildResult :: Scopes m t-                -> [([Text], SourcePos, m v)]-                -> m (AttrSet t, AttrSet SourcePos)-    buildResult scope bindings = do-        (s, p) <- foldM insert (M.empty, M.empty) bindings-        res <- if recursive-               then loebM (encapsulate <$> s)-               else traverse mkThunk s-        return (res, p)-      where-        mkThunk = thunk . withScopes scope+   where+    insert :: (AttrSet (m v), PositionSet) -> ([VarName], NSourcePos, m v) -> m (AttrSet (m v), PositionSet)+    insert (m, p) (path, pos, value) = attrSetAlter path pos m p value -        encapsulate f attrs = mkThunk . pushScope attrs $ f+    mkThunk = defer . withScopes scopes -        insert (m, p) (path, pos, value) = attrSetAlter path pos m p value+    encapsulate f attrs = mkThunk $ pushScope attrs f -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-    s <- aset+  applyBindToAdt :: Scopes m v -> Binding (m v) -> m [([VarName], NSourcePos, m v)]+  applyBindToAdt _ (NamedVar (StaticKey "__overrides" :| []) finalValue pos) =+    do+      (o', p') <- fromValue =<< finalValue+      -- jww (2018-05-09): What to do with the key position here?+      pure $+        (\ (k, v) ->+          ( one k+          , fromMaybe pos $ M.lookup k p'+          , demand v+          )+        ) <$> M.toList o'++  applyBindToAdt _ (NamedVar pathExpr finalValue pos) =+    (\case+      -- When there are no path segments, e.g. `${null} = 5;`, we don't+      -- bind anything+      ([], _, _) -> mempty+      result     -> one result+    ) <$> processAttrSetKeys pathExpr++   where+    processAttrSetKeys :: NAttrPath (m v) -> m ([VarName], NSourcePos, m v)+    processAttrSetKeys (h :| t) =+      maybe+        -- Empty attrset - return a stub.+        (pure (mempty, nullPos, toValue @(AttrSet v, PositionSet) mempty) )+        (\ k ->+          handlePresence+            -- No more keys in the attrset - return the result+            (pure ( one k, pos, finalValue ) )+            -- There are unprocessed keys in attrset - recurse appending the results+            (\ (x : xs) ->+              do+                (restOfPath, _, v) <- processAttrSetKeys (x :| xs)+                pure ( k : restOfPath, pos, v )+            )+            t+        )+        =<< evalSetterKeyName h++  applyBindToAdt scopes (Inherit ms names pos) =+    pure $ processScope <$> names+   where+    processScope+      :: VarName+      -> ([VarName], NSourcePos, m v)+    processScope var =+      ( one var+      , pos+      , maybe+          (attrMissing (one var) Nothing)+          demand+          =<< maybe+              (withScopes scopes $ lookupVar var)+              (\ s ->+                do+                  (coerce -> scope, _) <- fromValue @(AttrSet v, PositionSet) =<< s++                  clearScopes $ pushScope @v scope $ lookupVar var+              )+              ms+      )++  moveOverridesLast = uncurry (<>) . partition+    (\case+      NamedVar (StaticKey "__overrides" :| []) _ _ -> False+      _ -> True+    )++evalSelect+  :: forall v m+   . MonadNixEval v m+  => m v+  -> NAttrPath (m v)+  -> m (Either (v, NonEmpty VarName) (m v))+evalSelect aset attr =+  do+    s    <- aset     path <- traverse evalGetterKeyName attr-    extract s path-  where-    extract x path@(k:|ks) = fromValueMay x >>= \case-        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) +    extract path s++ where+  extract :: NonEmpty VarName -> v -> m (Either (v, NonEmpty VarName) (m v))+  extract path@(k :| ks) x =+    maybe+      left+      (maybe+        left+        (handlePresence+          (pure . pure)+          (\ (y : ys) -> (extract (y :| ys) =<<))+          ks+          . demand+        )+        . M.lookup k . fst+      )+      =<< fromValueMay @(AttrSet v, PositionSet) x+   where+    left :: m (Either (v, NonEmpty VarName) b)+    left = pure $ Left (x, path)+ -- | Evaluate a component of an attribute path in a context where we are -- *retrieving* a value-evalGetterKeyName :: forall v m. (MonadEval v m, FromValue (Text, DList Text) 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"+evalGetterKeyName+  :: forall v m+   . (MonadEval v m, FromValue NixString m v)+  => NKeyName (m v)+  -> m VarName+evalGetterKeyName =+  maybe+    (evalError @v $ ErrorCall "value is null while a string was expected")+    pure+    <=< evalSetterKeyName  -- | Evaluate a component of an attribute path in a context where we are -- *binding* a value-evalSetterKeyName :: (MonadEval v m, FromValue (Text, DList Text) m v)-                  => 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+evalSetterKeyName+  :: (MonadEval v m, FromValue NixString m v)+  => NKeyName (m v)+  -> m (Maybe VarName)+evalSetterKeyName =+  \case+    StaticKey k -> pure $ pure k+    DynamicKey k ->+      coerce . ignoreContext <<$>> runAntiquoted "\n" assembleString (fromValueMay =<<) k -assembleString :: forall v m. (MonadEval v m, FromValue (Text, DList Text) m v)-               => NString (m v) -> m (Maybe (Text, DList Text))-assembleString = \case-    Indented _   parts -> fromParts parts-    DoubleQuoted parts -> fromParts parts-  where-    fromParts = fmap (fmap mconcat . sequence) . traverse go+assembleString+  :: forall v m+   . (MonadEval v m, FromValue NixString m v)+  => NString (m v)+  -> m (Maybe NixString)+assembleString = fromParts . stringParts+ where+  fromParts :: [Antiquoted Text (m v)] -> m (Maybe NixString)+  fromParts xs = fold <<$>> traverse2 fun xs -    go = runAntiquoted "\n" (pure . Just . (, mempty)) (>>= fromValueMay)+  fun :: Antiquoted Text (m v) -> m (Maybe NixString)+  fun =+    runAntiquoted+      "\n"+      (pure . pure . mkNixStringWithoutContext)+      (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+buildArgument+  :: forall v m . MonadNixEval v m => Params (m v) -> m v -> m (AttrSet v)+buildArgument params arg =+  do+    scope <- askScopes+    let+      argThunk = defer $ withScopes scope arg     case params of-        Param name -> M.singleton name <$> thunk (withScopes scope arg)-        ParamSet s isVariadic m ->-            arg >>= fromValue @(AttrSet t, AttrSet SourcePos)-                >>= \(args, _) -> do-                let inject = case m of-                        Nothing -> id-                        Just n -> M.insert n $ const $-                            thunk (withScopes scope arg)-                loebM (inject $ alignWithKey (assemble scope isVariadic)-                                             args (M.fromList s))-  where-    assemble :: Scopes m t-             -> Bool-             -> Text-             -> These t (Maybe (m v))-             -> AttrSet t-             -> m t-    assemble scope isVariadic k = \case-        That Nothing  ->-            const $ evalError @v $ ErrorCall $-                "Missing value for parameter: " ++ show k-        That (Just f) -> \args ->-            thunk $ withScopes scope $ pushScope args f-        This x | isVariadic -> const (pure x)-               | otherwise  ->-                 const $ evalError @v $ ErrorCall $-                     "Unexpected parameter: " ++ show k-        These x _ -> const (pure x)+      Param name -> one . (name,) <$> argThunk+      ParamSet mname variadic pset ->+        do+          (args, _) <- fromValue @(AttrSet v, PositionSet) =<< arg+          let+            inject =+              maybe+                id+                (`M.insert` const argThunk) -- why insert into const? Thunk value getting magic point?+                mname+          loebM $+            inject $+              M.mapMaybe+                id+                $ ialignWith+                    (assemble scope variadic)+                    args+                    $ M.fromList pset+ where+  assemble+    :: Scopes m v+    -> Variadic+    -> VarName+    -> These v (Maybe (m v))+    -> Maybe (AttrSet v -> m v)+  assemble _ Variadic _ (This _) = Nothing+  assemble scope _ k t =+    pure $+      case t of+        That Nothing -> const $ evalError @v $ ErrorCall $ "Missing value for parameter: ''" <> show k+        That (Just f) -> coerce $ defer . withScopes scope . (`pushScope` f)+        This _ -> const $ evalError @v $ ErrorCall $ "Unexpected parameter: " <> show k+        These x _ -> const $ pure x -addSourcePositions :: (MonadReader e m, Has e SrcSpan)-                   => Transform NExprLocF (m a)-addSourcePositions f v@(Fix (Compose (Ann ann _))) =-    local (set hasLens ann) (f v)+-- | Add source positions to @NExprLoc@.+--+-- Takes @NExprLoc@, by itself takes source position informatoin, does transformation,+-- returns @NExprLoc@ with source positions.+--+-- Actually:+--+-- > => (NExprLoc -> m a)+-- > -> NExprLoc -> m a+addSourcePositions+  :: (MonadReader e m, Has e SrcSpan) => Transform NExprLocF (m a)+addSourcePositions f (v@(Ann ann _) :: NExprLoc) =+  local (set hasLens ann) $ f v  addStackFrames-    :: forall t e m a. (Scoped e t m, Framed e m, Typeable t, Typeable m)-    => Transform NExprLocF (m a)-addStackFrames f v = do-    scopes <- currentScopes @e @t-    withFrame Info (EvaluatingExpr scopes v) (f v)+  :: forall v e m a+   . (Scoped v m, Framed e m, Typeable v, Typeable m)+  => TransformF NExprLoc (m a)+addStackFrames f v =+  do+    scopes <- askScopes -framedEvalExprLoc-    :: forall t e v m.-      (MonadNixEval e v t m, Framed e m, Has e SrcSpan,-       Typeable t, Typeable m)-    => NExprLoc -> m v-framedEvalExprLoc = adi (eval . annotated . getCompose)-                        (addStackFrames @t . addSourcePositions)+    -- sectioning gives GHC optimization+    -- If opimization question would arrive again, check the @(`withFrameInfo` f v) $ EvaluatingExpr scopes v@+    -- for possible @scopes@ implementation @v@ type arguments sharing between runs.+    (`withFrameInfo` f v) $ (`EvaluatingExpr` v) scopes+ where+  withFrameInfo = withFrame Info++evalWithMetaInfo+  :: forall e v m+  . (MonadNixEval v m, Framed e m, Has e SrcSpan, Typeable m, Typeable v)+  => NExprLoc+  -> m v+evalWithMetaInfo =+  adi addMetaInfo evalContent++-- | Add source positions & frame context system.+addMetaInfo+  :: forall v m e a+  . (Framed e m, Scoped v m, Has e SrcSpan, Typeable m, Typeable v)+  => TransformF NExprLoc (m a)+addMetaInfo = addStackFrames @v . addSourcePositions++-- | Takes annotated expression. Strip from annotation. Evaluate.+evalContent+  :: MonadNixEval v m+  => AnnF ann NExprF (m v)+  -> m v+evalContent = eval . stripAnnF
src/Nix/Exec.hs view
@@ -1,808 +1,587 @@-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE ApplicativeDo #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE MultiWayIf #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE PartialTypeSignatures #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE ViewPatterns #-}--{-# OPTIONS_GHC -Wno-missing-signatures #-}-{-# OPTIONS_GHC -Wno-orphans #-}-{-# OPTIONS_GHC -fno-warn-name-shadowing #-}--module Nix.Exec where--import           Control.Applicative-import           Control.Monad-import           Control.Monad.Catch-import           Control.Monad.Fix-import           Control.Monad.IO.Class-import           Control.Monad.Reader-import           Control.Monad.State.Strict-import           Control.Monad.Trans.Reader (ReaderT(..))-import           Control.Monad.Trans.State.Strict (StateT(..))-import qualified Data.ByteString as BS-import           Data.Coerce-import           Data.Fix-import           Data.HashMap.Lazy (HashMap)-import qualified Data.HashMap.Lazy as M-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-import           Network.HTTP.Client-import           Network.HTTP.Client.TLS-import           Network.HTTP.Types-import           Nix.Atoms-import           Nix.Context-import           Nix.Convert-import           Nix.Effects-import           Nix.Eval as Eval-import           Nix.Expr-import           Nix.Frames-import           Nix.Normal-import           Nix.Options-import           Nix.Parser-import           Nix.Pretty-import           Nix.Render-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))-import           System.FilePath-import qualified System.Info-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-import           GHC.DataSize-#endif-#endif--type MonadNix e m =-    (Scoped e (NThunk m) m, Framed e m, Has e SrcSpan, Has e Options,-     Typeable m, MonadVar m, MonadEffects m, MonadFix m, MonadCatch m,-     Alternative m)--data ExecFrame m = Assertion SrcSpan (NValue m)-    deriving (Show, Typeable)--instance Typeable m => Exception (ExecFrame m)--nverr :: forall s e m a. (MonadNix e m, Exception s) => s -> m a-nverr = evalError @(NValue m)--currentPos :: forall e m. (MonadReader e m, Has e SrcSpan) => m SrcSpan-currentPos = asks (view hasLens)--wrapExprLoc :: SrcSpan -> NExprLocF r -> NExprLoc-wrapExprLoc span x = Fix (Fix (NSym_ span "<?>") <$ x)--instance MonadNix e m => MonadThunk (NValue m) (NThunk m) m where-    thunk mv = do-        opts :: Options <- asks (view hasLens)--        if thunks opts-            then do-                frames :: Frames <- asks (view hasLens)--                -- Gather the current evaluation context at the time of thunk-                -- creation, and record it along with the thunk.-                let go (fromException ->-                            Just (EvaluatingExpr scope-                                     (Fix (Compose (Ann span e))))) =-                        let e' = Compose (Ann span (Nothing <$ e))-                        in [Provenance scope e']-                    go _ = []-                    ps = concatMap (go . frame) frames--                fmap (NThunk ps . coerce) . buildThunk $ mv-            else-                fmap (NThunk [] . coerce) . buildThunk $ mv--    -- The ThunkLoop exception is thrown as an exception with MonadThrow,-    -- which does not capture the current stack frame information to provide-    -- it in a NixException, so we catch and re-throw it here using-    -- 'throwError' from Frames.hs.-    force (NThunk ps t) f = catch go (throwError @ThunkLoop)-      where-        go = case ps of-            [] -> forceThunk t f-            Provenance scope e@(Compose (Ann span _)):_ ->-                withFrame Info (ForcingExpr scope (wrapExprLoc span e))-                    (forceThunk t f)--    value = NThunk [] . coerce . valueRef--{--prov :: MonadNix e m-     => (NValue m -> Provenance m) -> NValue m -> m (NValue m)-prov p v = do-    opts :: Options <- asks (view hasLens)-    pure $ if values opts-           then addProvenance p v-           else v--}--instance MonadNix e m => MonadEval (NValue m) m where-    freeVariable var =-        nverr $ ErrorCall $ "Undefined variable '" ++ Text.unpack var ++ "'"--    attrMissing ks Nothing =-        evalError @(NValue m) $ ErrorCall $-            "Inheriting unknown attribute: "-                ++ intercalate "." (map Text.unpack (NE.toList ks))--    attrMissing ks (Just s) =-        evalError @(NValue m) $ ErrorCall $ "Could not look up attribute "-            ++ intercalate "." (map Text.unpack (NE.toList ks))-            ++ " in " ++ show s--    evalCurPos = do-        scope <- currentScopes-        span@(SrcSpan delta _) <- currentPos-        addProvenance (\_ -> Provenance scope (NSym_ span "__curPos"))-            <$> toValue delta--    evaledSym name val = do-        scope <- currentScopes-        span <- currentPos-        pure $ addProvenance (const $ Provenance scope (NSym_ span name)) val--    evalConstant c = do-        scope <- currentScopes-        span  <- currentPos-        pure $ nvConstantP (Provenance scope (NConstant_ span c)) c--    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-        span  <- currentPos-        nvPathP (Provenance scope (NLiteralPath_ span p)) <$> makeAbsolutePath p--    evalEnvPath p = do-        scope <- currentScopes-        span  <- currentPos-        nvPathP (Provenance scope (NEnvPath_ span p)) <$> findEnvPath p--    evalUnary op arg = do-        scope <- currentScopes-        span  <- currentPos-        execUnaryOp scope span op arg--    evalBinary op larg rarg = do-        scope <- currentScopes-        span  <- currentPos-        execBinaryOp scope span op larg rarg--    evalWith c b = do-        scope <- currentScopes-        span <- currentPos-        addProvenance (\b -> Provenance scope (NWith_ span Nothing (Just b)))-            <$> evalWithAttrSet c b--    evalIf c t f = do-        scope <- currentScopes-        span  <- currentPos-        fromValue c >>= \b ->-            if b-            then addProvenance (\t -> Provenance scope (NIf_ span (Just c) (Just t) Nothing)) <$> t-            else addProvenance (\f -> Provenance scope (NIf_ span (Just c) Nothing (Just f))) <$> f--    evalAssert c body = fromValue c >>= \b -> do-        span  <- currentPos-        if b-            then do-                scope <- currentScopes-                addProvenance (\b -> Provenance scope (NAssert_ span (Just c) (Just b))) <$> body-            else nverr $ Assertion span c--    evalApp f x = do-        scope <- currentScopes-        span <- currentPos-        addProvenance (const $ Provenance scope (NBinary_ span NApp (Just f) Nothing))-            <$> callFunc f x--    evalAbs p k = do-        scope <- currentScopes-        span  <- currentPos-        pure $ nvClosureP (Provenance scope (NAbs_ span (Nothing <$ p) Nothing))-            (void p) (\arg -> snd <$> k arg (\_ b -> ((),) <$> b))--    evalError = throwError--infixl 1 `callFunc`-callFunc :: forall e m. (MonadNix e m, Typeable m)-         => NValue m -> m (NValue m) -> m (NValue m)-callFunc fun arg = case fun of-    NVClosure params f -> do-        traceM $ "callFunc:NVFunction taking " ++ show params-        f arg-    NVBuiltin name f -> do-        span <- currentPos-        withFrame Info (Calling @m @(NThunk m) name span) $ f arg-    s@(NVSet m _) | Just f <- M.lookup "__functor" m -> do-        traceM "callFunc:__functor"-        force f $ (`callFunc` pure s) >=> (`callFunc` arg)-    x -> throwError $ ErrorCall $ "Attempt to call non-function: " ++ show x--execUnaryOp :: (Framed e m, MonadVar m)-            => Scopes m (NThunk m) -> SrcSpan -> NUnaryOp -> NValue m-            -> m (NValue m)-execUnaryOp scope span op arg = do-    traceM "NUnary"-    case arg of-        NVConstant c -> case (op, c) of-            (NNeg, NInt   i) -> unaryOp $ NInt   (-i)-            (NNeg, NFloat f) -> unaryOp $ NFloat (-f)-            (NNot, NBool  b) -> unaryOp $ NBool  (not b)-            _ -> throwError $ ErrorCall $-                "unsupported argument type for unary operator " ++ show op-        x -> throwError $ ErrorCall $ "argument to unary operator"-                ++ " must evaluate to an atomic type: " ++ show x-  where-    unaryOp = pure . nvConstantP (Provenance scope (NUnary_ span op (Just arg)))--execBinaryOp-    :: forall e m. (MonadNix e m, MonadEval (NValue m) m)-    => Scopes m (NThunk m)-    -> SrcSpan-    -> NBinaryOp-    -> NValue m-    -> m (NValue m)-    -> m (NValue m)--execBinaryOp scope span NOr larg rarg = fromNix larg >>= \l ->-    if l-    then orOp Nothing True-    else rarg >>= \rval -> fromNix @Bool rval >>= orOp (Just rval)-  where-    orOp r b = pure $-        nvConstantP (Provenance scope (NBinary_ span NOr (Just larg) r)) (NBool b)--execBinaryOp scope span NAnd larg rarg = fromNix larg >>= \l ->-    if l-    then rarg >>= \rval -> fromNix @Bool rval >>= andOp (Just rval)-    else andOp Nothing False-  where-    andOp r b = pure $-        nvConstantP (Provenance scope (NBinary_ span NAnd (Just larg) r)) (NBool b)--execBinaryOp scope span op lval rarg = do-    rval <- rarg-    let bin :: (Provenance m -> a) -> a-        bin f  = f (Provenance scope (NBinary_ span op (Just lval) (Just rval)))-        toBool = pure . bin nvConstantP . NBool-    case (lval, rval) of-        (NVConstant lc, NVConstant rc) -> case (op, lc, rc) of-            (NEq,  _, _)       -> toBool =<< valueEq lval rval-            (NNEq, _, _)       -> toBool . not =<< valueEq lval rval-            (NLt,  l, r)       -> toBool $ l <  r-            (NLte, l, r)       -> toBool $ l <= r-            (NGt,  l, r)       -> toBool $ l >  r-            (NGte, l, r)       -> toBool $ l >= r-            (NAnd,  _, _)      ->-                nverr $ ErrorCall "should be impossible: && is handled above"-            (NOr,   _, _)      ->-                nverr $ ErrorCall "should be impossible: || is handled above"-            (NPlus,  l, r)     -> numBinOp bin (+) l r-            (NMinus, l, r)     -> numBinOp bin (-) l r-            (NMult,  l, r)     -> numBinOp bin (*) l r-            (NDiv,   l, r)     -> numBinOp' bin div (/) l r-            (NImpl,-             NBool l, NBool r) -> toBool $ not l || r-            _                  -> nverr $ ErrorCall $ unsupportedTypes lval rval--        (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-            NLte  -> toBool $ ls <= rs-            NGt   -> toBool $ ls >  rs-            NGte  -> toBool $ ls >= rs-            _     -> nverr $ ErrorCall $ unsupportedTypes lval rval--        (NVStr _ _, NVConstant NNull) -> case op of-            NEq  -> toBool =<< valueEq lval (nvStr "" mempty)-            NNEq -> toBool . not =<< valueEq lval (nvStr "" mempty)-            _    -> nverr $ ErrorCall $ unsupportedTypes lval rval--        (NVConstant NNull, NVStr _ _) -> case op of-            NEq  -> toBool =<< valueEq (nvStr "" mempty) rval-            NNEq -> toBool . not =<< valueEq (nvStr "" mempty) rval-            _    -> nverr $ ErrorCall $ unsupportedTypes lval rval--        (NVSet ls lp, NVSet rs rp) -> case op of-            NUpdate -> pure $ bin nvSetP (rs `M.union` ls) (rp `M.union` lp)-            NEq     -> toBool =<< valueEq lval rval-            NNEq    -> toBool . not =<< valueEq lval rval-            _       -> nverr $ ErrorCall $ unsupportedTypes lval rval--        (NVSet ls lp, NVConstant NNull) -> case op of-            NUpdate -> pure $ bin nvSetP ls lp-            NEq     -> toBool =<< valueEq lval (nvSet M.empty M.empty)-            NNEq    -> toBool . not =<< valueEq lval (nvSet M.empty M.empty)-            _       -> nverr $ ErrorCall $ unsupportedTypes lval rval--        (NVConstant NNull, NVSet rs rp) -> case op of-            NUpdate -> pure $ bin nvSetP rs rp-            NEq     -> toBool =<< valueEq (nvSet M.empty M.empty) rval-            NNEq    -> toBool . not =<< valueEq (nvSet M.empty M.empty) rval-            _       -> nverr $ ErrorCall $ unsupportedTypes lval rval--        (ls@NVSet {}, NVStr rs rc) -> case op of-            NPlus   -> (\ls -> bin nvStrP (Text.pack ls `mappend` rs) rc)-                <$> coerceToString False ls-            NEq     -> toBool =<< valueEq lval rval-            NNEq    -> toBool . not =<< valueEq lval rval-            _       -> nverr $ ErrorCall $ unsupportedTypes lval rval--        (NVStr ls lc, rs@NVSet {}) -> case op of-            NPlus   -> (\rs -> bin nvStrP (ls `mappend` Text.pack rs) lc)-                <$> 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-            NNEq    -> toBool . not =<< valueEq lval rval-            _       -> nverr $ ErrorCall $ unsupportedTypes lval rval--        (NVList ls, NVConstant NNull) -> case op of-            NConcat -> pure $ bin nvListP ls-            NEq     -> toBool =<< valueEq lval (nvList [])-            NNEq    -> toBool . not =<< valueEq lval (nvList [])-            _       -> nverr $ ErrorCall $ unsupportedTypes lval rval--        (NVConstant NNull, NVList rs) -> case op of-            NConcat -> pure $ bin nvListP rs-            NEq     -> toBool =<< valueEq (nvList []) rval-            NNEq    -> toBool . not =<< valueEq (nvList []) rval-            _       -> nverr $ ErrorCall $ unsupportedTypes lval rval--        (NVPath p, NVStr s _) -> case op of-            NEq   -> toBool $ p == Text.unpack s-            NNEq  -> toBool $ p /= Text.unpack s-            NPlus -> bin nvPathP <$> makeAbsolutePath (p `mappend` Text.unpack s)-            _     -> nverr $ ErrorCall $ unsupportedTypes lval rval--        (NVPath ls, NVPath rs) -> case op of-            NPlus -> bin nvPathP <$> makeAbsolutePath (ls ++ rs)-            _     -> nverr $ ErrorCall $ unsupportedTypes lval rval--        _ -> case op of-            NEq   -> toBool False-            NNEq  -> toBool True-            _ -> nverr $ ErrorCall $ unsupportedTypes lval rval-  where-    unsupportedTypes :: Show a => a -> a -> String-    unsupportedTypes lval rval =-        "Unsupported argument types for binary operator "-            ++ show op ++ ": " ++ show lval ++ ", " ++ show rval--    numBinOp :: (forall r. (Provenance m -> r) -> r)-             -> (forall a. Num a => a -> a -> a) -> NAtom -> NAtom -> m (NValue m)-    numBinOp bin f = numBinOp' bin f f--    numBinOp' :: (forall r. (Provenance m -> r) -> r)-              -> (Integer -> Integer -> Integer)-              -> (Float -> Float -> Float)-              -> NAtom -> NAtom -> m (NValue m)-    numBinOp' bin intF floatF l r = case (l, r) of-        (NInt   li, NInt   ri) -> toInt   $             li `intF`               ri-        (NInt   li, NFloat rf) -> toFloat $ fromInteger li `floatF`             rf-        (NFloat lf, NInt   ri) -> toFloat $             lf `floatF` fromInteger ri-        (NFloat lf, NFloat rf) -> toFloat $             lf `floatF`             rf-        _ -> nverr $ ErrorCall $ unsupportedTypes l r-      where-        toInt   = pure . bin nvConstantP . NInt-        toFloat = pure . bin nvConstantP . NFloat--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 t _ -> pure $ Text.unpack t-        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) >=> go--        NVSet s _ | Just p <- M.lookup "outPath" s ->-            force p go--        v -> throwError $ ErrorCall $ "Expected a string, but saw: " ++ show v--newtype Lazy m a = Lazy-    { runLazy :: ReaderT (Context (Lazy m) (NThunk (Lazy m)))-                        (StateT (HashMap FilePath NExprLoc) m) a }-    deriving (Functor, Applicative, Alternative, Monad, MonadPlus,-              MonadFix, MonadIO,-              MonadReader (Context (Lazy m) (NThunk (Lazy m))))--instance MonadIO m => MonadVar (Lazy m) where-    type Var (Lazy m) = IORef--    newVar = liftIO . newIORef-    readVar = liftIO . readIORef-    writeVar = (liftIO .) . writeIORef-    atomicModifyVar = (liftIO .) . atomicModifyIORef--instance (MonadIO m, Monad m) => MonadFile m where-    readFile = liftIO . BS.readFile--instance MonadCatch m => MonadCatch (Lazy m) where-    catch (Lazy (ReaderT m)) f = Lazy $ ReaderT $ \e ->-        catch (m e) ((`runReaderT` e) . runLazy . f)--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)-      => MonadEffects (Lazy m) where-    addPath path = do-        (exitCode, out, _) <--            liftIO $ readProcessWithExitCode "nix-store" ["--add", path] ""-        case exitCode of-          ExitSuccess -> do-            let dropTrailingLinefeed p = take (length p - 1) p-            return $ StorePath $ dropTrailingLinefeed out-          _ -> 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-            cwd <- do-                mres <- lookupVar @_ @(NThunk (Lazy m)) "__cur_file"-                case mres of-                    Nothing -> liftIO getCurrentDirectory-                    Just v -> force v $ \case-                        NVPath s -> return $ takeDirectory s-                        v -> throwError $ ErrorCall $ "when resolving relative path,"-                                ++ " __cur_file is in scope,"-                                ++ " but is not a path; it is: "-                                ++ show v-            pure $ cwd <///> origPathExpanded-        liftIO $ removeDotDotIndirections <$> canonicalizePath absPath--    findEnvPath = findEnvPathM--    findPath = findPathM--    pathExists = liftIO . fileExist--    importPath scope origPath = do-        path <- liftIO $ pathToDefaultNixFile origPath-        mres <- lookupVar @(Context (Lazy m) (NThunk (Lazy m)))-                         "__cur_file"-        path' <- case mres of-            Nothing  -> do-                traceM "No known current directory"-                return path-            Just p -> fromValue @_ @_ @(NThunk (Lazy m)) p >>= \(Path p') -> do-                traceM $ "Current file being evaluated is: " ++ show p'-                return $ takeDirectory p' </> path--        traceM $ "Importing file " ++ path'-        withFrame Info (ErrorCall $ "While importing file " ++ show path') $ do-            imports <- Lazy $ ReaderT $ const get-            expr <- case M.lookup path' imports of-                Just expr -> pure expr-                Nothing -> do-                    eres <- Lazy $ parseNixFileLoc path'-                    case eres of-                        Failure err  ->-                            throwError $ ErrorCall . show $-                                text "Parse during import failed:" P.</> err-                        Success expr -> do-                            Lazy $ ReaderT $ const $-                                modify (M.insert origPath expr)-                            pure expr--            let ref = value @_ @_ @(Lazy m) (nvPath path')-            -- Use this cookie so that when we evaluate the next-            -- import, we'll remember which directory its containing-            -- file was in.-            pushScope (M.singleton "__cur_file" ref) $-                pushScope scope $ evalExprLoc expr--    getEnvVar = liftIO . lookupEnv--    getCurrentSystemOS = return $ Text.pack System.Info.os--    -- Invert the conversion done by GHC_CONVERT_CPU in GHC's aclocal.m4-    getCurrentSystemArch = return $ Text.pack $ case System.Info.arch of-      "i386" -> "i686"-      arch -> arch--    listDirectory         = liftIO . System.Directory.listDirectory-    getSymbolicLinkStatus = liftIO . System.Posix.Files.getSymbolicLinkStatus--    derivationStrict = fromValue @(ValueSet (Lazy m)) >=> \s -> do-        nn <- maybe (pure False) fromNix (M.lookup "__ignoreNulls" s)-        s' <- M.fromList <$> mapMaybeM (handleEntry nn) (M.toList s)-        v' <- normalForm =<< toValue @(ValueSet (Lazy m)) s'-        nixInstantiateExpr $ "derivationStrict " ++ show (prettyNValueNF v')-      where-        mapMaybeM :: (a -> Lazy m (Maybe b)) -> [a] -> Lazy m [b]-        mapMaybeM op = foldr f (return [])-          where f x xs = op x >>= \case-                    Nothing -> xs-                    Just x  -> (x:) <$> xs--        handleEntry ignoreNulls (k, v) = fmap (k,) <$> case k of-            -- The `args' attribute is special: it supplies the command-line-            -- arguments to the builder.-            "args"          -> Just <$> convertNix @[Text] v-            "__ignoreNulls" -> pure Nothing-            _               -> force v $ \case-                NVConstant NNull | ignoreNulls -> pure Nothing-                v' -> Just <$> (toNix =<< Text.pack <$> coerceToString True v')--    nixInstantiateExpr expr = do-        traceM $ "Executing: "-            ++ show ["nix-instantiate", "--eval", "--expr ", expr]-        (exitCode, out, err) <--            liftIO $ readProcessWithExitCode "nix-instantiate"-                [ "--eval", "--expr", expr] ""-        case exitCode of-            ExitSuccess -> case parseNixTextLoc (Text.pack out) of-                Failure err ->-                    throwError $ ErrorCall $-                        "Error parsing output of nix-instantiate: " ++ show err-                Success v -> evalExprLoc v-            status ->-                throwError $ ErrorCall $ "nix-instantiate failed: " ++ show status-                    ++ ": " ++ err--    getRecursiveSize =-#ifdef MIN_VERSION_ghc_datasize-#if MIN_VERSION_ghc_datasize(0,2,0) && __GLASGOW_HASKELL__ >= 804-        toNix @Integer <=< fmap fromIntegral . liftIO . recursiveSize-#else-        const $ toNix (0 :: Integer)-#endif-#else-        const $ toNix (0 :: Integer)-#endif--    getURL url = do-        let urlstr = Text.unpack url-        traceM $ "fetching HTTP URL: " ++ urlstr-        response <- liftIO $ do-          req <- parseRequest urlstr-          manager <--            if secure req-            then newTlsManager-            else newManager defaultManagerSettings-          -- print req-          httpLbs (req { method = "GET" }) manager-          -- return response-        let status = statusCode (responseStatus response)-        if  status /= 200-          then throwError $ ErrorCall $-                 "fail, got " ++ show status ++ " when fetching url:" ++ urlstr-          else -- do-            -- let bstr = responseBody response-            -- liftIO $ print bstr-            throwError $ ErrorCall $-              "success in downloading but hnix-store is not yet ready; url = " ++ urlstr--    traceEffect = liftIO . putStrLn--    exec = \case-      [] -> throwError $ ErrorCall "exec: missing program"-      (prog:args) -> do-        (exitCode, out, _) <--            liftIO $ readProcessWithExitCode prog args ""-        let t = Text.strip (Text.pack out)-        let emsg = "program[" ++ prog ++ "] args=" ++ show args-        case exitCode of-          ExitSuccess ->-            if Text.null t-            then throwError $ ErrorCall $ "exec has no output :" ++ emsg-            else case parseNixTextLoc t of-              Failure err ->-                throwError $ ErrorCall $-                    "Error parsing output of exec: " ++ show err ++ " " ++ emsg-              Success v -> evalExprLoc v-          err -> throwError $ ErrorCall $-                    "exec  failed: " ++ show err ++ " " ++ emsg--runLazyM :: Options -> MonadIO m => Lazy m a -> m a-runLazyM opts = (`evalStateT` M.empty)-              . (`runReaderT` newContext opts)-              . runLazy---- | Incorrectly normalize paths by rewriting patterns like @a/b/..@ to @a@.---   This is incorrect on POSIX systems, because if @b@ is a symlink, its---   parent may be a different directory from @a@. See the discussion at---   https://hackage.haskell.org/package/directory-1.3.1.5/docs/System-Directory.html#v:canonicalizePath-removeDotDotIndirections :: FilePath -> FilePath-removeDotDotIndirections = intercalate "/" . go [] . splitOn "/"-    where go s [] = reverse s-          go (_:s) ("..":rest) = go s rest-          go s (this:rest) = go (this:s) rest--expandHomePath :: FilePath -> IO FilePath-expandHomePath ('~' : xs) = flip (++) xs <$> getHomeDirectory-expandHomePath p = return p---- Given a path, determine the nix file to load-pathToDefaultNixFile :: FilePath -> IO FilePath-pathToDefaultNixFile p = do-    isDir <- doesDirectoryExist p-    pure $ if isDir then p </> "default.nix" else p--infixr 9 <///>-(<///>) :: FilePath -> FilePath -> FilePath-x <///> y | isAbsolute y || "." `isPrefixOf` y = x </> y-          | otherwise = joinByLargestOverlap x y-  where-    joinByLargestOverlap (splitDirectories -> xs) (splitDirectories -> ys) =-        joinPath $ head [ xs ++ drop (length tx) ys-                        | tx <- tails xs, tx `elem` inits ys ]--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--      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)-           => Alg NExprLocF (m a) -> Alg NExprLocF (n (m a))-addTracing k v = do-    depth <- ask-    guard (depth < 2000)-    local succ $ do-        v'@(Compose (Ann span x)) <- sequence v-        return $ do-            opts :: Options <- asks (view hasLens)-            let rendered =-                    if verbose opts >= Chatty-#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 $ print $ msg rendered <> text " ...done"-            return res--evalExprLoc :: forall e m. (MonadNix e m, Has e Options, MonadIO m)-            => NExprLoc -> m (NValue m)-evalExprLoc expr = do-    opts :: Options <- asks (view hasLens)-    if tracing opts-        then join . (`runReaderT` (0 :: Int)) $-             adi (addTracing phi)-                 (raise (addStackFrames @(NThunk m) . addSourcePositions))-                 expr-        else adi phi (addStackFrames @(NThunk m) . addSourcePositions) expr-  where-    phi = Eval.eval @_ @(NValue m) @(NThunk m) @m . annotated . getCompose-    raise k f x = ReaderT $ \e -> k (\t -> runReaderT (f t) e) x+{-# language AllowAmbiguousTypes #-}+{-# language CPP #-}+{-# language ConstraintKinds #-}+{-# language PartialTypeSignatures #-}+{-# language RankNTypes #-}+{-# language TypeFamilies #-}+{-# language UndecidableInstances #-}++{-# options_ghc -Wno-orphans #-}+{-# options_ghc -fno-warn-name-shadowing #-}+++module Nix.Exec where++import           Nix.Prelude             hiding ( putStr+                                                , putStrLn+                                                , print+                                                )+import           GHC.Exception                  ( ErrorCall(ErrorCall) )+import           Control.Monad.Catch     hiding ( catchJust )+import           Control.Monad.Fix+import           Data.Fix+import qualified Data.HashMap.Lazy             as M+import qualified Data.List.NonEmpty            as NE+import qualified Data.Text                     as Text+import           Nix.Atoms+import           Nix.Cited+import           Nix.Convert+import           Nix.Effects+import           Nix.Eval                      as Eval+import           Nix.Expr.Types+import           Nix.Expr.Types.Annotated+import           Nix.Frames+import           Nix.Options+import           Nix.Pretty+import           Nix.Render+import           Nix.Scope+import           Nix.String+import           Nix.String.Coerce+import           Nix.Thunk+import           Nix.Value+import           Nix.Value.Equal+import           Nix.Value.Monad+import           Prettyprinter+import qualified Text.Show.Pretty              as PS++#ifdef MIN_VERSION_ghc_datasize +import           GHC.DataSize+#endif++type MonadCited t f m =+  ( HasCitations m (NValue t f m) t+  , HasCitations1 m (NValue t f m) f+  , MonadDataContext f m+  )++mkNVConstantWithProvenance+  :: MonadCited t f m+  => Scopes m (NValue t f m)+  -> SrcSpan+  -> NAtom+  -> NValue t f m+mkNVConstantWithProvenance scopes span x =+  addProvenance (Provenance scopes . NConstantAnnF span $ x) $ NVConstant x++mkNVStrWithProvenance+  :: MonadCited t f m+  => Scopes m (NValue t f m)+  -> SrcSpan+  -> NixString+  -> NValue t f m+mkNVStrWithProvenance scopes span x =+  addProvenance (Provenance scopes . NStrAnnF span . DoubleQuoted . one . Plain . ignoreContext $ x) $ NVStr x++mkNVPathWithProvenance+  :: MonadCited t f m+  => Scopes m (NValue t f m)+  -> SrcSpan+  -> Path+  -> Path+  -> NValue t f m+mkNVPathWithProvenance scope span lit real =+  addProvenance (Provenance scope . NLiteralPathAnnF span $ lit) $ NVPath real++mkNVClosureWithProvenance+  :: MonadCited t f m+  => Scopes m (NValue t f m)+  -> SrcSpan+  -> Params ()+  -> (NValue t f m -> m (NValue t f m))+  -> NValue t f m+mkNVClosureWithProvenance scopes span x f =+  addProvenance (Provenance scopes $ NAbsAnnF span (Nothing <$ x) Nothing) $ NVClosure x f++mkNVUnaryOpWithProvenance+  :: MonadCited t f m+  => Scopes m (NValue t f m)+  -> SrcSpan+  -> NUnaryOp+  -> Maybe (NValue t f m)+  -> NValue t f m+  -> NValue t f m+mkNVUnaryOpWithProvenance scope span op val =+  addProvenance (Provenance scope $ NUnaryAnnF span op val)++mkNVAppOpWithProvenance+  :: MonadCited t f m+  => Scopes m (NValue t f m)+  -> SrcSpan+  -> Maybe (NValue t f m)+  -> Maybe (NValue t f m)+  -> NValue t f m+  -> NValue t f m+mkNVAppOpWithProvenance scope span lval rval =+  addProvenance (Provenance scope $ NAppAnnF span lval rval)++mkNVBinaryOpWithProvenance+  :: MonadCited t f m+  => Scopes m (NValue t f m)+  -> SrcSpan+  -> NBinaryOp+  -> Maybe (NValue t f m)+  -> Maybe (NValue t f m)+  -> NValue t f m+  -> NValue t f m+mkNVBinaryOpWithProvenance scope span op lval rval =+  addProvenance (Provenance scope $ NBinaryAnnF span op lval rval)++type MonadCitedThunks t f m =+  ( MonadThunk t m (NValue t f m)+  , MonadDataErrorContext t f m+  , HasCitations m (NValue t f m) t+  , HasCitations1 m (NValue t f m) f+  )++type MonadNix e t f m =+  ( Has e SrcSpan+  , Has e Options+  , Scoped (NValue t f m) m+  , Framed e m+  , MonadFix m+  , MonadCatch m+  , MonadThrow m+  , Alternative m+  , MonadEffects t f m+  , MonadCitedThunks t f m+  , MonadValue (NValue t f m) m+  )++data ExecFrame t f m = Assertion SrcSpan (NValue t f m)+  deriving (Show, Typeable)++instance MonadDataErrorContext t f m => Exception (ExecFrame t f m)++nverr :: forall e t f s m a . (MonadNix e t f m, Exception s) => s -> m a+nverr = evalError @(NValue t f m)++askSpan :: forall e m . (MonadReader e m, Has e SrcSpan) => m SrcSpan+askSpan = askLocal++wrapExprLoc :: SrcSpan -> NExprLocF r -> NExprLoc+wrapExprLoc span x = Fix $ NSymAnn span "<?>" <$ x+{-# inline wrapExprLoc #-}++--  2021-01-07: NOTE: This instance belongs to be beside MonadEval type class.+-- Currently instance is stuck in orphanage between the requirements to be MonadEval, aka Eval stage, and emposed requirement to be MonadNix (Execution stage). MonadNix constraint tries to put the cart before horse and seems superflous, since Eval in Nix also needs and can throw exceptions. It is between `nverr` and `evalError`.+instance MonadNix e t f m => MonadEval (NValue t f m) m where+  freeVariable var =+    nverr @e @t @f $ ErrorCall $ toString @Text $ "Undefined variable '" <> coerce var <> "'"++  synHole name =+    do+      span  <- askSpan+      scope <- askScopes+      evalError @(NValue t f m) $ SynHole $+        SynHoleInfo+          { _synHoleInfo_expr  = NSynHoleAnn span name+          , _synHoleInfo_scope = scope+          }+++  attrMissing ks ms =+    evalError @(NValue t f m) $ ErrorCall $ toString $+      maybe+        ("Inheriting unknown attribute: " <> attr)+        (\ s -> "Could not look up attribute " <> attr <> " in " <> show (prettyNValue s))+        ms+       where+        attr = Text.intercalate "." $ NE.toList $ coerce ks++  evalCurPos =+    do+      scope                  <- askScopes+      span@(SrcSpan delta _) <- askSpan+      addProvenance @_ @_ @(NValue t f m)+        (Provenance scope . NSymAnnF span $ coerce @Text "__curPos") <$>+          toValue delta++  evaledSym name val =+    do+      scope <- askScopes+      span  <- askSpan+      pure $+        addProvenance @_ @_ @(NValue t f m)+          (Provenance scope $ NSymAnnF span name)+          val++  evalConstant c =+    do+      scope <- askScopes+      span  <- askSpan+      pure $ mkNVConstantWithProvenance scope span c++  evalString =+    maybe+      (nverr $ ErrorCall "Failed to assemble string")+      (\ ns ->+        do+          scope <- askScopes+          span  <- askSpan+          pure $ mkNVStrWithProvenance scope span ns+      )+      <=< assembleString++  evalLiteralPath p =+    do+      scope <- askScopes+      span  <- askSpan+      mkNVPathWithProvenance scope span p <$> toAbsolutePath @t @f @m p++  evalEnvPath p =+    do+      scope <- askScopes+      span  <- askSpan+      mkNVPathWithProvenance scope span p <$> findEnvPath @t @f @m (coerce p)++  evalUnary op arg =+    do+      scope <- askScopes+      span  <- askSpan+      execUnaryOp scope span op arg++  evalBinary op larg rarg =+    do+      scope <- askScopes+      span  <- askSpan+      execBinaryOp scope span op larg rarg++  evalWith c b =+    do+      scope <- askScopes+      span  <- askSpan+      let f = join $ addProvenance . Provenance scope . NWithAnnF span Nothing . pure+      f <$> evalWithAttrSet c b++  evalIf c tVal fVal =+    do+      scope <- askScopes+      span  <- askSpan+      bl <- fromValue c++      let+        fun x y = addProvenance (Provenance scope $ NIfAnnF span (pure c) x y)+        falseVal = (fun Nothing =<< pure) <$> fVal+        trueVal = (flip fun Nothing =<< pure) <$> tVal++      bool+        falseVal+        trueVal+        bl++  evalAssert c body =+    do+      span <- askSpan+      b <- fromValue c+      bool+        (nverr $ Assertion span c)+        (do+          scope <- askScopes+          join (addProvenance . Provenance scope . NAssertAnnF span (pure c) . pure) <$> body+        )+        b++  evalApp f x =+    do+      scope <- askScopes+      span  <- askSpan+      mkNVAppOpWithProvenance scope span (pure f) Nothing <$> (callFunc f =<< defer x)++  evalAbs+    :: Params (m (NValue t f m))+    -> ( forall a+      . m (NValue t f m)+      -> ( AttrSet (m (NValue t f m))+        -> m (NValue t f m)+        -> m (a, NValue t f m)+        )+      -> m (a, NValue t f m)+      )+    -> m (NValue t f m)+  evalAbs p k =+    do+      scope <- askScopes+      span  <- askSpan+      pure $ mkNVClosureWithProvenance scope span (void p) (fmap snd . flip (k @()) (const (fmap (mempty ,))) . pure)++  evalError = throwError++infixl 1 `callFunc`+callFunc+  :: forall e t f m+   . MonadNix e t f m+  => NValue t f m+  -> NValue t f m+  -> m (NValue t f m)+callFunc fun arg =+  do+    frames <- askFrames+    when (length frames > 2000) $ throwError $ ErrorCall "Function call stack exhausted"++    fun' <- demand fun+    case fun' of+      NVBuiltin name f    ->+        do+          span <- askSpan+          withFrame Info ((Calling @m @(NValue t f m)) name span) $ f arg -- Is this cool?+      NVClosure _params f -> f arg+      (NVSet _ m) | Just f <- M.lookup "__functor" m ->+        (`callFunc` arg) =<< (`callFunc` fun') f+      _x -> throwError $ ErrorCall $ "Attempt to call non-function: " <> show _x++execUnaryOp+  :: forall e t f m+   . (Framed e m, MonadCited t f m, Show t)+  => Scopes m (NValue t f m)+  -> SrcSpan+  -> NUnaryOp+  -> NValue t f m+  -> m (NValue t f m)+execUnaryOp scope span op arg =+  case arg of+    NVConstant c ->+      case (op, c) of+        (NNeg, NInt   i) -> mkUnaryOp NInt negate i+        (NNeg, NFloat f) -> mkUnaryOp NFloat negate f+        (NNot, NBool  b) -> mkUnaryOp NBool not b+        _seq ->+          throwError $ ErrorCall $ "unsupported argument type for unary operator " <> show _seq+    _x ->+      throwError $ ErrorCall $ "argument to unary operator must evaluate to an atomic type: " <> show _x+ where+  mkUnaryOp :: (a -> NAtom) -> (a -> a) -> a -> m (NValue t f m)+  mkUnaryOp c b a = pure . mkNVUnaryOpWithProvenance scope span op (pure arg) . NVConstant $ c (b a)++execBinaryOp+  :: forall e t f m+   . (MonadNix e t f m, MonadEval (NValue t f m) m)+  => Scopes m (NValue t f m)+  -> SrcSpan+  -> NBinaryOp+  -> NValue t f m+  -> m (NValue t f m)+  -> m (NValue t f m)+execBinaryOp scope span op lval rarg =+  case op of+    NEq   -> helperEq id+    NNEq  -> helperEq not+    NOr   -> helperLogic flip True+    NAnd  -> helperLogic id   False+    NImpl -> helperLogic id   True+    _     ->+      do+        rval  <- rarg+        rval' <- demand rval+        lval' <- demand lval++        execBinaryOpForced scope span op lval' rval'++ where++  helperEq :: (Bool -> Bool) -> m (NValue t f m)+  helperEq flag =+    do+      rval <- rarg+      eq <- valueEqM lval rval+      boolOp rval $ flag eq++  helperLogic flp flag =+    flp bool+      (bypass flag)+      (do+          rval <- rarg+          x <- fromValue rval+          boolOp rval x+      )+      =<< fromValue lval++  boolOp rval = toBoolOp $ pure rval++  bypass      = toBoolOp Nothing++  toBoolOp :: Maybe (NValue t f m) -> Bool -> m (NValue t f m)+  toBoolOp r b =+    pure $ mkNVBinaryOpWithProvenance scope span op (pure lval) r $ NVConstant $ NBool b++execBinaryOpForced+  :: forall e t f m+   . (MonadNix e t f m, MonadEval (NValue t f m) m)+  => Scopes m (NValue t f m)+  -> SrcSpan+  -> NBinaryOp+  -> NValue t f m+  -> NValue t f m+  -> m (NValue t f m)++execBinaryOpForced scope span op lval rval =+  case op of+    NLt    -> mkCmpOp (<)+    NLte   -> mkCmpOp (<=)+    NGt    -> mkCmpOp (>)+    NGte   -> mkCmpOp (>=)+    NMinus -> mkBinNumOp (-)+    NMult  -> mkBinNumOp (*)+    NDiv   -> mkBinNumOp' div (/)+    NConcat ->+      case (lval, rval) of+        (NVList ls, NVList rs) -> pure $ mkListP $ ls <> rs+        _ -> unsupportedTypes++    NUpdate ->+      case (lval, rval) of+        (NVSet lp ls, NVSet rp rs) -> pure $ mkSetP (rp <> lp) (rs <> ls)+        (NVSet lp ls, NVConstant NNull) -> pure $ mkSetP lp ls+        (NVConstant NNull, NVSet rp rs) -> pure $ mkSetP rp rs+        _ -> unsupportedTypes++    NPlus ->+      case (lval, rval) of+        (NVConstant _, NVConstant _) -> mkBinNumOp (+)+        (NVStr ls, NVStr rs) -> pure $ mkStrP (ls <> rs)+        (NVStr ls, NVPath p) ->+          mkStrP . (ls <>) <$>+            coercePathToNixString CopyToStore p+        (NVPath ls, NVStr rs) ->+          maybe+            (throwError $ ErrorCall "A string that refers to a store path cannot be appended to a path.") -- data/nix/src/libexpr/eval.cc:1412+            (\ rs2 -> mkPathP <$> toAbsolutePath @t @f (ls <> coerce (toString rs2)))+            (getStringNoContext rs)+        (NVPath ls, NVPath rs) -> mkPathP <$> toAbsolutePath @t @f (ls <> rs)++        (ls@NVSet{}, NVStr rs) ->+          mkStrP . (<> rs) <$>+            coerceAnyToNixString callFunc DontCopyToStore ls+        (NVStr ls, rs@NVSet{}) ->+          mkStrP . (ls <>) <$>+            coerceAnyToNixString callFunc DontCopyToStore rs+        _ -> unsupportedTypes+    _other   -> shouldBeAlreadyHandled++ where+  addProv :: NValue t f m -> NValue t f m+  addProv =+    mkNVBinaryOpWithProvenance scope span op (pure lval) (pure rval)++  mkBoolP :: Bool -> m (NValue t f m)+  mkBoolP = pure . addProv . NVConstant . NBool++  mkIntP :: Integer -> m (NValue t f m)+  mkIntP = pure . addProv . NVConstant . NInt++  mkFloatP :: Float -> m (NValue t f m)+  mkFloatP = pure . addProv . NVConstant . NFloat++  mkListP :: [NValue t f m] -> NValue t f m+  mkListP = addProv . NVList++  mkStrP :: NixString -> NValue t f m+  mkStrP = addProv . NVStr++  mkPathP :: Path -> NValue t f m+  mkPathP = addProv . NVPath++  mkSetP :: (PositionSet -> AttrSet (NValue t f m) -> NValue t f m)+  mkSetP x s = addProv $ NVSet x s++  mkCmpOp :: (forall a. Ord a => a -> a -> Bool) -> m (NValue t f m)+  mkCmpOp op = case (lval, rval) of+    (NVConstant l, NVConstant r) -> mkBoolP $ l `op` r+    (NVStr l, NVStr r) -> mkBoolP $ l `op` r+    _ -> unsupportedTypes++  mkBinNumOp :: (forall a. Num a => a -> a -> a) -> m (NValue t f m)+  mkBinNumOp op = mkBinNumOp' op op++  mkBinNumOp'+    :: (Integer -> Integer -> Integer)+    -> (Float -> Float -> Float)+    -> m (NValue t f m)+  mkBinNumOp' intOp floatOp =+    case (lval, rval) of+      (NVConstant l, NVConstant r) ->+        case (l, r) of+          (NInt   li, NInt   ri) -> mkIntP $ li `intOp` ri+          (NInt   li, NFloat rf) -> mkFloatP $ fromInteger li `floatOp` rf+          (NFloat lf, NInt   ri) -> mkFloatP $ lf `floatOp` fromInteger ri+          (NFloat lf, NFloat rf) -> mkFloatP $ lf `floatOp` rf+          _ -> unsupportedTypes+      _ -> unsupportedTypes++  unsupportedTypes = throwError $ ErrorCall $ "Unsupported argument types for binary operator " <> show op <> ": " <> show lval <> ", " <> show rval++  shouldBeAlreadyHandled = throwError $ ErrorCall $ "This cannot happen: operator " <> show op <> " should have been handled in execBinaryOp."+++-- This function is here, rather than in 'Nix.String', because of the need to+-- use 'throwError'.+fromStringNoContext+  :: Framed e m+  => NixString+  -> m Text+fromStringNoContext ns =+  maybe+    (throwError $ ErrorCall $ "expected string with no context, but got " <> show ns)+    pure+    (getStringNoContext ns)++addTracing+  ::( MonadNix e t f m+    , Has e Options+    , Alternative n+    , MonadReader Int n+    , MonadFail n+    )+  => Alg NExprLocF (m a)+  -> Alg NExprLocF (n (m a))+addTracing k v = do+  depth <- ask+  guard $ depth < 2000+  local succ $ do+    v'@(AnnF span x) <- sequenceA v+    pure $ do+      opts <- askOptions+      let+        rendered =+          bool+            (prettyNix $ Fix $ Fix (NSym "?") <$ x)+            (pretty $ PS.ppShow $ void x)+            (getVerbosity opts >= Chatty)+        msg x = pretty ("eval: " <> replicate depth ' ') <> x+      loc <- renderLocation span $ msg rendered <> " ...\n"+      putStr $ show loc+      res <- k v'+      print $ msg rendered <> " ...done"+      pure res++evalWithTracingAndMetaInfo+  :: forall e t f m+  . MonadNix e t f m+  => NExprLoc+  -> ReaderT Int m (m (NValue t f m))+evalWithTracingAndMetaInfo =+  adi+    addMetaInfo+    (addTracing Eval.evalContent)+  where+  addMetaInfo :: (NExprLoc -> ReaderT r m a) -> NExprLoc -> ReaderT r m a+  addMetaInfo = (ReaderT .) . flip . (Eval.addMetaInfo .) . flip . (runReaderT .)++evalExprLoc :: forall e t f m . MonadNix e t f m => NExprLoc -> m (NValue t f m)+evalExprLoc expr =+  do+    opts <- askOptions+    let+      pTracedAdi =+        bool+          Eval.evalWithMetaInfo+          (join . (`runReaderT` (0 :: Int)) . evalWithTracingAndMetaInfo)+          (isTrace opts)+    pTracedAdi expr++exec :: (MonadNix e t f m, MonadInstantiate m) => [Text] -> m (NValue t f m)+exec args = either throwError evalExprLoc =<< exec' args++-- Please, delete `nix` from the name+nixInstantiateExpr+  :: (MonadNix e t f m, MonadInstantiate m) => Text -> m (NValue t f m)+nixInstantiateExpr s = either throwError evalExprLoc =<< instantiateExpr s
src/Nix/Expr.hs view
@@ -1,10 +1,11 @@ -- | Wraps the expression submodules.-module Nix.Expr (-  module Nix.Expr.Types,-  module Nix.Expr.Types.Annotated,-  module Nix.Expr.Shorthands-  ) where+module Nix.Expr+  ( module Nix.Expr.Types+  , module Nix.Expr.Types.Annotated+  , module Nix.Expr.Shorthands+  )+where -import Nix.Expr.Types-import Nix.Expr.Shorthands-import Nix.Expr.Types.Annotated+import           Nix.Expr.Types+import           Nix.Expr.Shorthands+import           Nix.Expr.Types.Annotated
src/Nix/Expr/Shorthands.hs view
@@ -1,231 +1,452 @@-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}---- | A bunch of shorthands for making nix expressions.+-- | Shorthands for making Nix expressions. ----- Functions with an @F@ suffix return a more general type without the outer--- 'Fix' wrapper.+-- Functions with an @F@ suffix return a more general type (base functor @F a@) without the outer+-- 'Fix' wrapper that creates @a@. module Nix.Expr.Shorthands where -import Data.Fix-import Data.List.NonEmpty (NonEmpty(..))-import Data.Monoid-import Data.Text (Text)-import Nix.Atoms-import Nix.Expr.Types-import Text.Megaparsec.Pos (SourcePos)+import           Nix.Prelude+import           Data.Fix+import           Nix.Atoms+import           Nix.Expr.Types --- | Make an integer literal expression.+-- * Basic expression builders++-- | Put @NAtom@ as expression+mkConst :: NAtom -> NExpr+mkConst = Fix . NConstant++-- | Put null.+mkNull :: NExpr+mkNull = Fix mkNullF++-- | Put boolean.+mkBool :: Bool -> NExpr+mkBool = Fix . mkBoolF++-- | Put integer. mkInt :: Integer -> NExpr mkInt = Fix . mkIntF -mkIntF :: Integer -> NExprF a-mkIntF = NConstant . NInt---- | Make an floating point literal expression.+-- | Put floating point number. mkFloat :: Float -> NExpr mkFloat = Fix . mkFloatF -mkFloatF :: Float -> NExprF a-mkFloatF = NConstant . NFloat---- | Make a regular (double-quoted) string.+-- | Put a regular (double-quoted) string. mkStr :: Text -> NExpr-mkStr = Fix . NStr . DoubleQuoted . \case-  "" -> []-  x -> [Plain x]+mkStr = Fix . NStr . DoubleQuoted .+  whenText+    mempty+    (one . Plain) --- | Make an indented string.+-- | Put an indented string. mkIndentedStr :: Int -> Text -> NExpr-mkIndentedStr w = Fix . NStr . Indented w . \case-  "" -> []-  x -> [Plain x]+mkIndentedStr w = Fix . NStr . Indented w .+  whenText+    mempty+    (one . Plain) --- | Make a path. Use 'True' if the path should be read from the--- environment, else 'False'.+-- | Put a path. Use @True@ if the path should be read from the environment, else use @False@. mkPath :: Bool -> FilePath -> NExpr mkPath b = Fix . mkPathF b -mkPathF :: Bool -> FilePath -> NExprF a-mkPathF False = NLiteralPath-mkPathF True = NEnvPath---- | Make a path expression which pulls from the NIX_PATH env variable.+-- | Put a path expression which pulls from the @NIX_PATH@ @env@ variable. mkEnvPath :: FilePath -> NExpr mkEnvPath = Fix . mkEnvPathF -mkEnvPathF :: FilePath -> NExprF a-mkEnvPathF = mkPathF True---- | Make a path expression which references a relative path.+-- | Put a path which references a relative path. mkRelPath :: FilePath -> NExpr mkRelPath = Fix . mkRelPathF -mkRelPathF :: FilePath -> NExprF a-mkRelPathF = mkPathF False---- | Make a variable (symbol)+-- | Put a variable (symbol). mkSym :: Text -> NExpr mkSym = Fix . mkSymF -mkSymF :: Text -> NExprF a-mkSymF = NSym+-- | Put syntactic hole.+mkSynHole :: Text -> NExpr+mkSynHole = Fix . mkSynHoleF  mkSelector :: Text -> NAttrPath NExpr-mkSelector = (:| []) . StaticKey+mkSelector = one . StaticKey . coerce -mkBool :: Bool -> NExpr-mkBool = Fix . mkBoolF+-- | Put a binary operator.+--  @since+mkApp :: NExpr -> NExpr -> NExpr+mkApp a = Fix . NApp a+-- | Put an unary operator. -mkBoolF :: Bool -> NExprF a-mkBoolF = NConstant . NBool+--  @since 0.15.0+mkOp :: NUnaryOp -> NExpr -> NExpr+mkOp op = Fix . NUnary op -mkNull :: NExpr-mkNull = Fix mkNullF+-- | Logical negation: @not@.+mkNot :: NExpr -> NExpr+mkNot = mkOp NNot -mkNullF :: NExprF a-mkNullF = NConstant NNull+-- | Number negation: @-@.+--+-- Negation in the language works with integers and floating point.+--  @since 0.15.0+mkNeg :: NExpr -> NExpr+mkNeg = mkOp NNeg -mkOper :: NUnaryOp -> NExpr -> NExpr-mkOper op = Fix . NUnary op+-- | Put a binary operator.+--  @since 0.15.0+mkOp2 :: NBinaryOp -> NExpr -> NExpr -> NExpr+mkOp2 op a = Fix . NBinary op a -mkOper2 :: NBinaryOp -> NExpr -> NExpr -> NExpr-mkOper2 op a = Fix . NBinary op a+-- | > { x }+--  @since 0.15.0+mkParamSet :: [(Text, Maybe NExpr)] -> Params NExpr+mkParamSet pset = mkGeneralParamSet Nothing pset False -mkParamset :: [(Text, Maybe NExpr)] -> Bool -> Params NExpr-mkParamset params variadic = ParamSet params variadic Nothing+-- | > { x, ... }+--  @since 0.15.0+mkVariadicParamSet :: [(Text, Maybe NExpr)] -> Params NExpr+mkVariadicParamSet pset = mkGeneralParamSet Nothing pset True +-- | > s@{ x }+--  @since 0.15.0+mkNamedParamSet :: Text -> [(Text, Maybe NExpr)] -> Params NExpr+mkNamedParamSet name pset = mkGeneralParamSet (pure name) pset False++-- | > s@{ x, ... }+--  @since 0.15.0+mkNamedVariadicParamSet :: Text -> [(Text, Maybe NExpr)] -> Params NExpr+mkNamedVariadicParamSet name params = mkGeneralParamSet (pure name) params True++-- | Args:+--+-- 1. Maybe name:+--+-- > Nothing  ->   {}+-- > Just "s" -> s@{}+--+-- 2. key:expr pairs+--+-- 3. Is variadic or not:+--+-- > True  -> {...}+-- > False -> {}+--  @since 0.15.0+mkGeneralParamSet :: Maybe Text -> [(Text, Maybe NExpr)] -> Bool -> Params NExpr+mkGeneralParamSet mname params variadic = ParamSet (coerce mname) (Variadic `whenTrue` variadic) (coerce params)++-- | > rec { .. } mkRecSet :: [Binding NExpr] -> NExpr-mkRecSet = Fix . NRecSet+mkRecSet = mkSet Recursive +-- | Put a non-recursive set.+--+-- > { .. } mkNonRecSet :: [Binding NExpr] -> NExpr-mkNonRecSet = Fix . NSet+mkNonRecSet = mkSet mempty -mkLets :: [Binding NExpr] -> NExpr -> NExpr-mkLets bindings = Fix . NLet bindings+-- | General set builder function.+mkSet :: Recursivity -> [Binding NExpr] -> NExpr+mkSet r = Fix . NSet r +-- | Empty set.+--+-- Monoid. Use @//@ operation (shorthand $//) to extend the set.+--  @since 0.15.0+emptySet :: NExpr+emptySet = mkNonRecSet mempty++-- | Put a list. mkList :: [NExpr] -> NExpr mkList = Fix . NList +--  @since 0.15.0+emptyList :: NExpr+emptyList = mkList mempty++-- | Wrap in a @let@.+--+-- (Evaluate the second argument after introducing the bindings.)+--+-- +------------------------+-----------------++-- | Haskell                | Nix             |+-- +========================+=================++-- | @mkLets bindings expr@ | @let bindings;@ |+-- |                        | @in expr@       |+-- +------------------------+-----------------++mkLets :: [Binding NExpr] -> NExpr -> NExpr+mkLets bindings = Fix . NLet bindings++-- | Create a @whith@:+-- 1st expr - what to bring into the scope.+-- 2nd - expression that recieves the scope extention.+--+-- +--------------------+-------------------++-- | Haskell            | Nix               |+-- +====================+===================++-- | @mkWith body main@ | @with body; expr@ |+-- +--------------------+-------------------+ mkWith :: NExpr -> NExpr -> NExpr mkWith e = Fix . NWith e +-- | Create an @assert@:+-- 1st expr - asserting itself, must return @true@.+-- 2nd - main expression to evaluated after assertion.+--+-- +-----------------------+----------------------++-- | Haskell               | Nix                  |+-- +=======================+======================++-- | @mkAssert check eval@ | @assert check; eval@ |+-- +-----------------------+----------------------+ mkAssert :: NExpr -> NExpr -> NExpr-mkAssert e = Fix . NWith e+mkAssert e = Fix . NAssert e +-- | Put:+--+-- > if expr1+-- >   then expr2+-- >   else expr3 mkIf :: NExpr -> NExpr -> NExpr -> NExpr mkIf e1 e2 = Fix . NIf e1 e2 +-- | Lambda function, analog of Haskell's @\\ x -> x@:+--+-- +-----------------------+-----------++-- | Haskell               | Nix       |+-- +=======================+===========++-- | @ mkFunction x expr @ | @x: expr@ |+-- +-----------------------+-----------+ mkFunction :: Params NExpr -> NExpr -> NExpr mkFunction params = Fix . NAbs params -{--mkDot :: NExpr -> Text -> NExpr-mkDot e key = mkDots e [key]+-- | General dot-reference with optional alternative if the key does not exist.+--  @since 0.15.0+getRefOrDefault :: Maybe NExpr -> NExpr -> Text -> NExpr+getRefOrDefault alt obj = Fix . NSelect alt obj . mkSelector --- | Create a dotted expression using only text.-mkDots :: NExpr -> [Text] -> NExpr-mkDots e [] = e-mkDots (Fix (NSelect e keys' x)) keys =-  -- Special case: if the expression in the first argument is already-  -- a dotted expression, just extend it.-  Fix (NSelect e (keys' <> map (StaticKey ?? Nothing) keys) x)-mkDots e keys = Fix $ NSelect e (map (StaticKey ?? Nothing) keys) Nothing--}+-- ** Base functor builders for basic expressions builders *sic --- | An `inherit` clause without an expression to pull from.-inherit :: [NKeyName e] -> SourcePos -> Binding e-inherit = Inherit Nothing+-- | Unfixed @mkNull@.+mkNullF :: NExprF a+mkNullF = NConstant NNull +-- | Unfixed @mkBool@.+mkBoolF :: Bool -> NExprF a+mkBoolF = NConstant . NBool++-- | Unfixed @mkInt@.+mkIntF :: Integer -> NExprF a+mkIntF = NConstant . NInt++-- | Unfixed @mkFloat@.+mkFloatF :: Float -> NExprF a+mkFloatF = NConstant . NFloat++-- | Unfixed @mkPath@.+mkPathF :: Bool -> FilePath -> NExprF a+mkPathF False = NLiteralPath . coerce+mkPathF True  = NEnvPath . coerce++-- | Unfixed @mkEnvPath@.+mkEnvPathF :: FilePath -> NExprF a+mkEnvPathF = mkPathF True++-- | Unfixed @mkRelPath@.+mkRelPathF :: FilePath -> NExprF a+mkRelPathF = mkPathF False++-- | Unfixed @mkSym@.+mkSymF :: Text -> NExprF a+mkSymF = NSym . coerce++-- | Unfixed @mkSynHole@.+mkSynHoleF :: Text -> NExprF a+mkSynHoleF = NSynHole . coerce+++-- * Other+-- (org this better/make a better name for section(s))+ -- | An `inherit` clause with an expression to pull from.-inheritFrom :: e -> [NKeyName e] -> SourcePos -> Binding e-inheritFrom expr = Inherit (Just expr)+--+-- +------------------------+--------------------+------------++-- | Hask                   | Nix                | pseudocode |+-- +========================+====================+============++-- | @inheritFrom x [a, b]@ | @inherit (x) a b;@ | @a = x.a;@ |+-- |                        |                    | @b = x.b;@ |+-- +------------------------+--------------------+------------++inheritFrom :: e -> [VarName] -> Binding e+inheritFrom expr ks = Inherit (pure expr) ks nullPos --- | Shorthand for producing a binding of a name to an expression.-bindTo :: Text -> NExpr -> Binding NExpr-bindTo name x = NamedVar (mkSelector name) x nullPos+-- | An `inherit` clause without an expression to pull from.+--+-- +----------------------+----------------+------------------++-- | Hask                 | Nix            | pseudocode       |+-- +======================+================+==================++-- | @inheritFrom [a, b]@ | @inherit a b;@ | @a = outside.a;@ |+-- |                      |                | @b = outside.b;@ |+-- +----------------------+----------------+------------------++inherit :: [VarName] -> Binding e+inherit ks = Inherit Nothing ks nullPos --- | Infix version of bindTo.+-- | Nix @=@ (bind operator). ($=) :: Text -> NExpr -> Binding NExpr ($=) = bindTo- infixr 2 $= +-- | Shorthand for producing a binding of a name to an expression: Nix's @=@.+bindTo :: Text -> NExpr -> Binding NExpr+bindTo name x = NamedVar (mkSelector name) x nullPos+ -- | Append a list of bindings to a set or let expression.--- For example, adding `[a = 1, b = 2]` to `let c = 3; in 4` produces--- `let a = 1; b = 2; c = 3; in 4`.+-- For example:+-- adding      `[a = 1, b = 2]`+-- to       `let               c = 3; in 4`+-- produces `let a = 1; b = 2; c = 3; in 4`. appendBindings :: [Binding NExpr] -> NExpr -> NExpr-appendBindings newBindings (Fix e) = case e of-  NLet bindings e' -> Fix $ NLet (bindings <> newBindings) e'-  NSet bindings -> Fix $ NSet (bindings <> newBindings)-  NRecSet bindings -> Fix $ NRecSet (bindings <> newBindings)-  _ -> error "Can only append bindings to a set or a let"+appendBindings newBindings (Fix e) =+  case e of+    NLet bindings e'    -> mkLets (bindings <> newBindings) e'+    NSet recur bindings -> Fix $ NSet recur (bindings <> newBindings)+    _                   -> error "Can only append bindings to a set or a let" --- | Applies a transformation to the body of a nix function.+-- | Applies a transformation to the body of a Nix function. modifyFunctionBody :: (NExpr -> NExpr) -> NExpr -> NExpr-modifyFunctionBody f (Fix e) = case e of-  NAbs params body -> Fix $ NAbs params (f body)-  _ -> error "Not a function"+modifyFunctionBody transform (Fix (NAbs params body)) = mkFunction params $ transform body+modifyFunctionBody _ _ = error "Not a function" --- | A let statement with multiple assignments.+-- | A @let@ statement with multiple assignments. letsE :: [(Text, NExpr)] -> NExpr -> NExpr-letsE pairs = Fix . NLet (map (uncurry bindTo) pairs)+letsE pairs = mkLets $ uncurry ($=) <$> pairs  -- | Wrapper for a single-variable @let@. letE :: Text -> NExpr -> NExpr -> NExpr-letE varName varExpr = letsE [(varName, varExpr)]+letE varName varExpr = letsE $ one (varName, varExpr) --- | Make an attribute set (non-recursive).+-- | Make a non-recursive attribute set. attrsE :: [(Text, NExpr)] -> NExpr-attrsE pairs = Fix $ NSet (map (uncurry bindTo) pairs)+attrsE pairs = mkNonRecSet $ uncurry ($=) <$> pairs --- | Make an attribute set (recursive).+-- | Make a recursive attribute set. recAttrsE :: [(Text, NExpr)] -> NExpr-recAttrsE pairs = Fix $ NRecSet (map (uncurry bindTo) pairs)+recAttrsE pairs = mkRecSet $ uncurry ($=) <$> pairs --- | Logical negation.-mkNot :: NExpr -> NExpr-mkNot = Fix . NUnary NNot --- -- | Dot-reference into an attribute set.--- (!.) :: NExpr -> Text -> NExpr--- (!.) = mkDot--- infixl 8 !.--mkBinop :: NBinaryOp -> NExpr -> NExpr -> NExpr-mkBinop op e1 e2 = Fix (NBinary op e1 e2)+-- * Nix binary operators --- | Various nix binary operators-($==), ($!=), ($<), ($<=), ($>), ($>=), ($&&), ($||), ($->),-  ($//), ($+), ($-), ($*), ($/), ($++)+(@@), ($==), ($!=), ($<), ($<=), ($>), ($>=), ($&&), ($||), ($->), ($//), ($+), ($-), ($*), ($/), ($++)   :: NExpr -> NExpr -> NExpr-e1 $== e2 = mkBinop NEq e1 e2-e1 $!= e2 = mkBinop NNEq e1 e2-e1 $< e2 = mkBinop NLt e1 e2-e1 $<= e2 = mkBinop NLte e1 e2-e1 $> e2 = mkBinop NGt e1 e2-e1 $>= e2 = mkBinop NGte e1 e2-e1 $&& e2 = mkBinop NAnd e1 e2-e1 $|| e2 = mkBinop NOr e1 e2-e1 $-> e2 = mkBinop NImpl e1 e2-e1 $// e2 = mkBinop NUpdate e1 e2-e1 $+ e2 = mkBinop NPlus e1 e2-e1 $- e2 = mkBinop NMinus e1 e2-e1 $* e2 = mkBinop NMult e1 e2-e1 $/ e2 = mkBinop NDiv e1 e2-e1 $++ e2 = mkBinop NConcat e1 e2+--  2021-07-10: NOTE: Probably the presedence of some operators is still needs to be tweaked. --- | Function application expression.-(@@) :: NExpr -> NExpr -> NExpr-f @@ arg = mkBinop NApp f arg-infixl 1 @@+-- | Dot-reference into an attribute set: @attrSet.k@+(@.) :: NExpr -> Text -> NExpr+(@.) = getRefOrDefault Nothing+infix 9 @. --- | Lambda shorthand.+-- | Dot-reference into an attribute set with alternative if the key does not exist.+--+-- > s.x or y+--  @since 0.15.0+(@.<|>) :: NExpr -> Text -> NExpr -> NExpr+(@.<|>) obj name alt = getRefOrDefault (pure alt ) obj name+infix 9 @.<|>++-- | Function application (@' '@ in @f x@)+(@@) = mkApp+infixl 8 @@++-- | List concatenation: @++@+($++) = mkOp2 NConcat+infixr 7 $++++-- | Multiplication: @*@+($*)  = mkOp2 NMult+infixl 6 $*++-- | Division: @/@+($/)  = mkOp2 NDiv+infixl 6 $/++-- | Addition: @+@+($+)  = mkOp2 NPlus+infixl 5 $+++-- | Subtraction: @-@+($-)  = mkOp2 NMinus+infixl 5 $-++-- | Extend/override the left attr set, with the right one: @//@+($//) = mkOp2 NUpdate+infixr 5 $//++-- | Greater than: @>@+($>)  = mkOp2 NGt+infix 4 $>++-- | Greater than OR equal: @>=@+infix 4 $>=+($>=) = mkOp2 NGte++-- | Less than OR equal: @<=@+($<=) = mkOp2 NLte+infix 4 $<=++-- | Less than: @<@+($<)  = mkOp2 NLt+infix 4 $<++-- | Equality: @==@+($==) = mkOp2 NEq+infix 3 $==++-- | Inequality: @!=@+($!=) = mkOp2 NNEq+infix 3 $!=++-- | AND: @&&@+($&&) = mkOp2 NAnd+infixl 2 $&&++-- | OR: @||@+($||) = mkOp2 NOr+infixl 2 $||++-- | Logical implication: @->@+($->) = mkOp2 NImpl+infix 1 $->++-- | Lambda function, analog of Haskell's @\\ x -> x@:+--+-- +---------------+-----------++-- | Haskell       | Nix       |+-- +===============+===========++-- | @x ==> expr @ | @x: expr@ |+-- +---------------+-----------+ (==>) :: Params NExpr -> NExpr -> NExpr (==>) = mkFunction- infixr 1 ==> -(@.) :: NExpr -> Text -> NExpr-obj @. name = Fix (NSelect obj (StaticKey name :| []) Nothing)-infixl 2 @.++-- * Under deprecation++-- NOTE: Remove after 2023-07+-- | __@Deprecated@__: Please, use `mkOp`+-- Put an unary operator.+mkOper :: NUnaryOp -> NExpr -> NExpr+mkOper = mkOp++-- NOTE: Remove after 2023-07+-- | __@Deprecated@__: Please, use `mkOp2`+-- | Put a binary operator.+mkOper2 :: NBinaryOp -> NExpr -> NExpr -> NExpr+mkOper2 = mkOp2++-- NOTE: Remove after 2023-07+-- | __@Deprecated@__: Please, use `mkOp2`+-- | Nix binary operator builder.+mkBinop :: NBinaryOp -> NExpr -> NExpr -> NExpr+mkBinop = mkOp2++-- NOTE: Remove after 2023-07+-- | __@Deprecated@__: Please, use:+--   * `mkParamSet` is for closed sets;+--   * `mkVariadicSet` is for variadic;+--   * `mkGeneralParamSet` a general constructor.+mkParamset :: [(Text, Maybe NExpr)] -> Bool -> Params NExpr+mkParamset params variadic = ParamSet Nothing (Variadic `whenTrue` variadic) (coerce params)
+ src/Nix/Expr/Strings.hs view
@@ -0,0 +1,126 @@+-- | Functions for manipulating nix strings.+module Nix.Expr.Strings where++import           Nix.Prelude+import           Relude.Unsafe                 as Unsafe+-- Please, switch things to NonEmpty+import           Data.List                      ( dropWhileEnd+                                                , minimum+                                                , lookup+                                                )+import qualified Data.Text                     as T+import           Nix.Expr.Types++-- | Merge adjacent @Plain@ values with @<>@.+mergePlain :: [Antiquoted Text r] -> [Antiquoted Text r]+mergePlain [] = mempty+mergePlain (Plain a : EscapedNewline : Plain b : xs) =+  mergePlain (Plain (a <> "\n" <> b) : xs)+mergePlain (Plain a : Plain b : xs) = mergePlain (Plain (a <> b) : xs)+mergePlain (x                 : xs) = x : mergePlain xs++-- | Remove 'Plain' values equal to 'mempty', as they don't have any+-- informational content.+removeEmptyPlains :: [Antiquoted Text r] -> [Antiquoted Text r]+removeEmptyPlains = filter f where+  f (Plain x) = x /= mempty+  f _         = True++  -- trimEnd xs+  --     | null xs = xs+  --     | otherwise = case last xs of+  --           Plain x -> init xs <> [Plain (T.dropWhileEnd (== ' ') x)]+  --           _ -> xs++-- | Equivalent to case splitting on 'Antiquoted' strings.+runAntiquoted :: v -> (v -> a) -> (r -> a) -> Antiquoted v r -> a+runAntiquoted _  f _ (Plain v)      = f v+runAntiquoted nl f _ EscapedNewline = f nl+runAntiquoted _  _ k (Antiquoted r) = k r++-- | Split a stream representing a string with antiquotes on line breaks.+splitLines :: forall r . [Antiquoted Text r] -> [[Antiquoted Text r]]+splitLines = uncurry (flip (:)) . go+ where+  go :: [Antiquoted Text r] -> ([[Antiquoted Text r]], [Antiquoted Text r])+  go (Plain t : xs) = (one (Plain l) <>) <$> foldr f (go xs) ls+   where+    (l : ls) = T.split (== '\n') t+    f prefix (finished, current) = ((Plain prefix : current) : finished, mempty)+  go (Antiquoted a   : xs) = (one (Antiquoted a) <>) <$> go xs+  go (EscapedNewline : xs) = (one EscapedNewline <>) <$> go xs+  go []                    = mempty++-- | Join a stream of strings containing antiquotes again. This is the inverse+-- of 'splitLines'.+unsplitLines :: [[Antiquoted Text r]] -> [Antiquoted Text r]+unsplitLines = intercalate $ one $ Plain "\n"++-- | Form an indented string by stripping spaces equal to the minimal indent.+stripIndent :: [Antiquoted Text r] -> NString r+stripIndent [] = Indented 0 mempty+stripIndent xs =+  Indented+    minIndent+    (removeEmptyPlains $+      mergePlain $+        (snd <$>) $+          dropWhileEnd+            cleanup+            $ pairWithLast $ unsplitLines ls'+    )+ where+  pairWithLast ys =+    zip+      (handlePresence+        Nothing+        (pure . Unsafe.last)+        <$> inits ys+      )+      ys++  ls        = stripEmptyOpening $ splitLines xs+  ls'       = dropSpaces minIndent <$> ls++  minIndent =+    handlePresence+      0+      (minimum . (countSpaces . mergePlain <$>))+      (stripEmptyLines ls)++  stripEmptyLines = filter $ \case+    [Plain t] -> not $ T.null $ T.strip t+    _         -> True++  stripEmptyOpening ([Plain t] : ts) | T.null (T.strip t) = ts+  stripEmptyOpening ts = ts++  countSpaces (Antiquoted _   : _) = 0+  countSpaces (EscapedNewline : _) = 0+  countSpaces (Plain t        : _) = T.length . T.takeWhile (== ' ') $ t+  countSpaces []                   = 0++  dropSpaces 0 x              = x+  dropSpaces n (Plain t : cs) = Plain (T.drop n t) : cs+  dropSpaces _ _              = fail "stripIndent: impossible"++  cleanup (Nothing, Plain y) = T.all (== ' ') y+  cleanup (Just (Plain x), Plain y) | "\n" `T.isSuffixOf` x = T.all (== ' ') y+  cleanup _                  = False++escapeCodes :: [(Char, Char)]+escapeCodes =+  [('\n', 'n'), ('\r', 'r'), ('\t', 't'), ('"', '"'), ('$', '$'), ('\\', '\\')]++fromEscapeCode :: Char -> Maybe Char+fromEscapeCode = (`lookup` (swap <$> escapeCodes))++toEscapeCode :: Char -> Maybe Char+toEscapeCode = (`lookup` escapeCodes)++escapeMap :: [(Text, Text)]+escapeMap =+  [("\n", "\\n"), ("\r", "\\r"), ("\t", "\\t"), ("\"", "\\\""), ("${", "\\${"), ("\\", "\\\\")]++escapeString :: Text -> Text+escapeString = applyAll (fmap (uncurry T.replace) escapeMap)
src/Nix/Expr/Types.hs view
@@ -1,567 +1,869 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveFoldable #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DeriveTraversable #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}--{-# OPTIONS_GHC -Wno-orphans #-}-{-# OPTIONS_GHC -Wno-missing-signatures #-}---- | 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-import           Data.Aeson-import           Data.Aeson.TH-import           Data.Binary (Binary)-import qualified Data.Binary as Bin-import           Data.Data-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-import           Data.Maybe (fromMaybe)-import           Data.Monoid-import           Data.Ord.Deriving-import           Data.Text (Text, pack, unpack)-import           Data.Traversable-import           GHC.Exts-import           GHC.Generics-import           Language.Haskell.TH.Syntax-import           Lens.Family2-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---- 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--- them. The actual 'NExpr' type is a fixed point of this functor, defined--- below.-data NExprF r-  = NConstant !NAtom-  -- ^ Constants: ints, bools, URIs, and null.-  | NStr !(NString r)-  -- ^ A string, with interpolated expressions.-  | NSym !VarName-  -- ^ A variable. For example, in the expression @f a@, @f@ is represented-  -- as @NSym "f"@ and @a@ as @NSym "a"@.-  | NList ![r]-  -- ^ A list literal.-  | NSet ![Binding r]-  -- ^ An attribute set literal, not recursive.-  | NRecSet ![Binding r]-  -- ^ An attribute set literal, recursive.-  | NLiteralPath !FilePath-  -- ^ A path expression, which is evaluated to a store path. The path here-  -- can be relative, in which case it's evaluated relative to the file in-  -- which it appears.-  | NEnvPath !FilePath-  -- ^ A path which refers to something in the Nix search path (the NIX_PATH-  -- environment variable. For example, @<nixpkgs/pkgs>@.-  | NUnary !NUnaryOp !r-  -- ^ Application of a unary operator to an expression.-  | NBinary !NBinaryOp !r !r-  -- ^ Application of a binary operator to two expressions.-  | NSelect !r !(NAttrPath r) !(Maybe r)-  -- ^ Dot-reference into an attribute set, optionally providing an-  -- alternative if the key doesn't exist.-  | NHasAttr !r !(NAttrPath r)-  -- ^ Ask if a set contains a given attribute path.-  | NAbs !(Params r) !r-  -- ^ A function literal (lambda abstraction).-  | NLet ![Binding r] !r-  -- ^ Evaluate the second argument after introducing the bindings.-  | NIf !r !r !r-  -- ^ If-then-else statement.-  | NWith !r !r-  -- ^ Evaluate an attribute set, bring its bindings into scope, and-  -- evaluate the second argument.-  | 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,-            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 !SourcePos-  -- ^ An explicit naming, such as @x = y@ or @x.y = z@.-  | 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;@. 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,-            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.-data Params r-  = Param !VarName-  -- ^ For functions with a single named argument, such as @x: x + 1@.-  | ParamSet !(ParamSet r) !Bool !(Maybe VarName)-  -- ^ Explicit parameters (argument must be a set). Might specify a name to-  -- 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, 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.-type ParamSet r = [(VarName, Maybe r)]--instance IsString (Params r) where-  fromString = Param . fromString---- | 'Antiquoted' represents an expression that is either--- 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, Hashable)--#if MIN_VERSION_hashable(1, 2, 5)-instance Hashable v => Hashable1 (Antiquoted v)--instance Hashable2 Antiquoted where-    liftHashWithSalt2 ha _ salt (Plain a) =-        ha (salt `hashWithSalt` (0 :: Int)) a-    liftHashWithSalt2 _ _ salt EscapedNewline =-        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,--- the final string is constructed by concating all the parts.-data NString r-  = DoubleQuoted ![Antiquoted Text r]-  -- ^ Strings wrapped with double-quotes (") can contain literal newline-  -- characters, but the newlines are preserved and no indentation is stripped.-  | Indented !Int ![Antiquoted Text r]-  -- ^ Strings wrapped with two single quotes ('') can contain newlines, and-  --   their indentation will be stripped, but the amount stripped is-  --   remembered.-  deriving (Eq, Ord, Generic, Generic1, Typeable, Data, Functor, Foldable,-            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-  fromString "" = DoubleQuoted []-  fromString string = DoubleQuoted [Plain $ pack string]---- | A 'KeyName' is something that can appear on the left side of an--- equals sign. For example, @a@ is a 'KeyName' in @{ a = 3; }@, @let a = 3;--- in ...@, @{}.a@ or @{} ? a@.------ Nix supports both static keynames (just an identifier) and dynamic--- identifiers. Dynamic identifiers can be either a string (e.g.:--- @{ "a" = 3; }@) or an antiquotation (e.g.: @let a = "example";--- in { ${a} = 3; }.example@).------ Note: There are some places where a dynamic keyname is not allowed.--- In particular, those include:------   * The RHS of a @binding@ inside @let@: @let ${"a"} = 3; in ...@---     produces a syntax error.---   * The attribute names of an 'inherit': @inherit ${"a"};@ is forbidden.------ Note: In Nix, a simple string without antiquotes such as @"foo"@ is--- allowed even if the context requires a static keyname, but the--- parser still considers it a 'DynamicKey' for simplicity.-data NKeyName r-  = DynamicKey !(Antiquoted (NString r) r)-  | StaticKey !VarName-  deriving (Eq, Ord, Generic, Typeable, Data, Show, Read, NFData,-            Hashable)--#ifdef MIN_VERSION_serialise-instance Serialise r => Serialise (NKeyName r)--instance Serialise Pos where-    encode x = Ser.encode (unPos x)-    decode = mkPos <$> Ser.decode--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)--instance Hashable SourcePos where-    hashWithSalt salt (SourcePos f l c) =-        salt `hashWithSalt` f `hashWithSalt` l `hashWithSalt` c--instance Generic1 NKeyName where-  type Rep1 NKeyName = NKeyName-  from1 = id-  to1   = id--#if MIN_VERSION_deepseq(1, 4, 3)-instance NFData1 NKeyName where-    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 = 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 _ _ _ = 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) =-      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---- Deriving this instance automatically is not possible because @r@--- occurs not only as last argument in @Antiquoted (NString r) r@-instance Functor NKeyName where-  fmap = fmapDefault---- Deriving this instance automatically is not possible because @r@--- occurs not only as last argument in @Antiquoted (NString r) r@-instance Foldable NKeyName where-  foldMap = foldMapDefault---- Deriving this instance automatically is not possible because @r@--- occurs not only as last argument in @Antiquoted (NString r) r@-instance Traversable NKeyName where-  traverse f = \case-    DynamicKey (Plain str)    -> DynamicKey . Plain <$> traverse f str-    DynamicKey (Antiquoted e) -> DynamicKey . Antiquoted <$> f e-    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.-type NAttrPath r = NonEmpty (NKeyName r)---- | There are two unary operations: logical not and integer negation.-data NUnaryOp = NNeg | NNot-  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-  = NEq      -- ^ Equality (==)-  | NNEq     -- ^ Inequality (!=)-  | NLt      -- ^ Less than (<)-  | NLte     -- ^ Less than or equal (<=)-  | NGt      -- ^ Greater than (>)-  | NGte     -- ^ Greater than or equal (>=)-  | NAnd     -- ^ Logical and (&&)-  | NOr      -- ^ Logical or (||)-  | NImpl    -- ^ Logical implication (->)-  | NUpdate  -- ^ Joining two attribut sets (//)-  | NPlus    -- ^ Addition (+)-  | NMinus   -- ^ Subtraction (-)-  | NMult    -- ^ Multiplication (*)-  | NDiv     -- ^ Division (/)-  | NConcat  -- ^ List concatenation (++)-  | NApp     -- ^ Apply a function to an argument.-  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)-$(deriveEq1 ''Params)-$(deriveEq1 ''Antiquoted)-$(deriveEq2 ''Antiquoted)--$(deriveOrd1 ''NString)-$(deriveOrd1 ''Params)-$(deriveOrd1 ''Antiquoted)-$(deriveOrd2 ''Antiquoted)--$(deriveRead1 ''NString)-$(deriveRead1 ''Params)-$(deriveRead1 ''Antiquoted)-$(deriveRead2 ''Antiquoted)--$(deriveShow1 ''NExprF)-$(deriveShow1 ''NString)-$(deriveShow1 ''Params)-$(deriveShow1 ''Binding)-$(deriveShow1 ''Antiquoted)-$(deriveShow2 ''Antiquoted)---- $(deriveJSON1 defaultOptions ''NExprF)-$(deriveJSON1 defaultOptions ''NString)-$(deriveJSON1 defaultOptions ''Params)--- $(deriveJSON1 defaultOptions ''Binding)-$(deriveJSON1 defaultOptions ''Antiquoted)-$(deriveJSON2 defaultOptions ''Antiquoted)--instance (Binary v, Binary a) => Binary (Antiquoted v a)-instance Binary a => Binary (NString a)-instance Binary a => Binary (Binding a)-instance Binary Pos where-    put x = Bin.put (unPos x)-    get = mkPos <$> Bin.get-instance Binary SourcePos-instance Binary a => Binary (NKeyName a)-instance Binary a => Binary (Params a)-instance Binary NAtom-instance Binary NUnaryOp-instance Binary NBinaryOp-instance Binary a => Binary (NExprF a)--instance (ToJSON v, ToJSON a) => ToJSON (Antiquoted v a)-instance ToJSON a => ToJSON (NString a)-instance ToJSON a => ToJSON (Binding a)-instance ToJSON Pos where-    toJSON x = toJSON (unPos x)-instance ToJSON SourcePos-instance ToJSON a => ToJSON (NKeyName a)-instance ToJSON a => ToJSON (Params a)-instance ToJSON NAtom-instance ToJSON NUnaryOp-instance ToJSON NBinaryOp-instance ToJSON a => ToJSON (NExprF a)-instance ToJSON NExpr--instance (FromJSON v, FromJSON a) => FromJSON (Antiquoted v a)-instance FromJSON a => FromJSON (NString a)-instance FromJSON a => FromJSON (Binding a)-instance FromJSON Pos where-    parseJSON = fmap mkPos . parseJSON-instance FromJSON SourcePos-instance FromJSON a => FromJSON (NKeyName a)-instance FromJSON a => FromJSON (Params a)-instance FromJSON NAtom-instance FromJSON NUnaryOp-instance FromJSON NBinaryOp-instance FromJSON a => FromJSON (NExprF a)-instance FromJSON NExpr--$(makeTraversals ''NExprF)-$(makeTraversals ''Binding)-$(makeTraversals ''Params)-$(makeTraversals ''Antiquoted)-$(makeTraversals ''NString)-$(makeTraversals ''NKeyName)-$(makeTraversals ''NUnaryOp)-$(makeTraversals ''NBinaryOp)---- $(makeLenses ''Fix)--class NExprAnn ann g | g -> ann where-    fromNExpr :: g r -> (NExprF r, ann)-    toNExpr :: (NExprF r, ann) -> g r--ekey :: NExprAnn ann g-     => NonEmpty Text-     -> SourcePos-     -> Lens' (Fix g) (Maybe (Fix g))-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) pos f v--        _ -> f Nothing <&> \case-            Nothing -> e-            Just v  ->-                let entry = NamedVar (NE.map StaticKey keys) v pos-                in Fix (toNExpr (NSet (entry : xs), ann))-  where-    go xs = do-        let keys' = NE.toList keys-        (ks, rest) <- zip (inits keys') (tails keys')-        case ks of-            [] -> empty-            j:js -> do-                NamedVar ns v _p <- xs-                guard $ (j:js) == (NE.toList ns ^.. traverse._StaticKey)-                return (v, rest)--ekey _ _ f e = fromMaybe e <$> f Nothing--stripPositionInfo :: NExpr -> NExpr-stripPositionInfo = transport phi-  where-    phi (NSet binds)         = NSet (map go binds)-    phi (NRecSet binds)      = NRecSet (map go binds)-    phi (NLet binds body)    = NLet (map go binds) body-    phi x = x--    go (NamedVar path r _pos)  = NamedVar path r nullPos-    go (Inherit ms names _pos) = Inherit ms names nullPos--nullPos :: SourcePos-nullPos = SourcePos "<string>" (mkPos 1) (mkPos 1)+{-# language ConstraintKinds #-}+{-# language CPP #-}+{-# language DeriveAnyClass #-}+{-# language FunctionalDependencies #-}+{-# language RankNTypes #-}+{-# language TemplateHaskell #-}+{-# language TypeFamilies #-}++{-# options_ghc -Wno-orphans #-}+{-# options_ghc -Wno-name-shadowing #-}+{-# options_ghc -Wno-missing-signatures #-}++-- | The Nix expression type and supporting types.+--+-- [Brief introduction of the Nix expression language.](https://nixos.org/nix/manual/#ch-expression-language)+--+-- This module is a beginning of a deep embedding (term) of a Nix language into Haskell.+-- [Brief on shallow & deep embedding.](https://web.archive.org/web/20201112031804/https://alessandrovermeulen.me/2013/07/13/the-difference-between-shallow-and-deep-embedding/)+--+-- (additiona info for dev): Big use of TemplateHaskell in the module requires proper (top-down) organization of declarations.+module Nix.Expr.Types+  ( module Nix.Expr.Types+  , SourcePos(..)+  , unPos+  , mkPos+  )+where++import           Nix.Prelude+import qualified Codec.Serialise               as Serialise+import           Codec.Serialise                ( Serialise )+import           Control.DeepSeq                ( NFData1(..) )+import           Data.Aeson+import qualified Data.Binary                   as Binary+import           Data.Binary                    ( Binary )+import           Data.Data+import           Data.Fix                       ( Fix(..) )+import           Data.Functor.Classes+import           Data.Hashable.Lifted+import qualified Data.HashMap.Lazy             as MapL+import qualified Data.Set                      as Set+import qualified Data.List.NonEmpty            as NE+import qualified Text.Show+import           Data.Traversable               ( fmapDefault, foldMapDefault )+import           GHC.Generics+import qualified Language.Haskell.TH.Syntax    as TH+import           Lens.Family2+import           Lens.Family2.TH+import           Text.Megaparsec.Pos            ( Pos+                                                , mkPos+                                                , unPos+                                                , SourcePos(SourcePos)+                                                )+import           Text.Show.Deriving             ( deriveShow1, deriveShow2 )+import           Text.Read.Deriving             ( deriveRead1, deriveRead2 )+import           Data.Eq.Deriving               ( deriveEq1  , deriveEq2   )+import           Data.Ord.Deriving              ( deriveOrd1 , deriveOrd2  )+import           Data.Aeson.TH                  ( deriveJSON2 )+import qualified Type.Reflection               as Reflection+import           Nix.Atoms+#if !MIN_VERSION_text(1,2,4)+-- NOTE: Remove package @th-lift-instances@ removing this+import           Instances.TH.Lift              ()  -- importing Lift Text for GHC 8.6+#endif+++-- * utils++newtype NPos = NPos Pos+ deriving+   ( Eq, Ord+   , Read, Show+   , Data, NFData+   , Generic+   )++instance Semigroup NPos where+  (NPos x) <> (NPos y) = NPos (x <> y)++-- | Represents source positions.+-- Source line & column positions change intensively during parsing,+-- so they are declared strict to avoid memory leaks.+--+-- The data type is a reimplementation of 'Text.Megaparsec.Pos' 'SourcePos'.+data NSourcePos =+  NSourcePos+  { -- | Name of source file+    getSourceName :: Path,+    -- | Line number+    getSourceLine :: !NPos,+    -- | Column number+    getSourceColumn :: !NPos+  }+ deriving+   ( Eq, Ord+   , Read, Show+   , Data, NFData+   , Generic+   )++-- | Helper for 'SourcePos' -> 'NSourcePos' coersion.+toNSourcePos :: SourcePos -> NSourcePos+toNSourcePos (SourcePos f l c) =+  NSourcePos (coerce f) (coerce l) (coerce c)++-- | Helper for 'NSourcePos' -> 'SourcePos' coersion.+toSourcePos :: NSourcePos -> SourcePos+toSourcePos (NSourcePos f l c) =+  SourcePos (coerce f) (coerce l) (coerce c)++--  2021-07-16: NOTE: Should replace @ParamSet@ List+-- | > Hashmap VarName -- type synonym+type AttrSet = HashMap VarName++-- | Holds file positionng information for abstrations.+-- A type synonym for @HashMap VarName NSourcePos@.+type PositionSet = AttrSet NSourcePos++-- ** Additional N{,Source}Pos instances++-- Placed here because TH inference depends on declaration sequence.++instance Serialise NPos where+  encode = Serialise.encode . unPos . coerce+  decode = coerce . mkPos <$> Serialise.decode++instance Serialise NSourcePos where+  encode (NSourcePos f l c) =+    coerce $+    Serialise.encode f <>+    Serialise.encode l <>+    Serialise.encode c+  decode =+    liftA3 NSourcePos+      Serialise.decode+      Serialise.decode+      Serialise.decode++instance Hashable NPos where+  hashWithSalt salt = hashWithSalt salt . unPos . coerce++instance Hashable NSourcePos where+  hashWithSalt salt (NSourcePos f l c) =+    salt+      `hashWithSalt` f+      `hashWithSalt` l+      `hashWithSalt` c++instance Binary NPos where+  put = (Binary.put @Int) . unPos . coerce+  get = coerce . mkPos <$> Binary.get+instance Binary NSourcePos++instance ToJSON NPos where+  toJSON = toJSON . unPos . coerce+instance ToJSON NSourcePos++instance FromJSON NPos where+  parseJSON = coerce . fmap mkPos . parseJSON+instance FromJSON NSourcePos++-- * Components of Nix expressions++-- NExpr is a composition of+--   * direct reuse of the Haskell types (list, Path, Text)+--   * NAtom+--   * Types in this section+--   * Fixpoint nature++-- ** newtype VarName++newtype VarName = VarName Text+  deriving+    ( Eq, Ord, Generic+    , Typeable, Data, NFData, Serialise, Binary, ToJSON, FromJSON+    , Show, Read, Hashable+    )++instance IsString VarName where+  fromString = coerce . fromString @Text++instance ToString VarName where+  toString = toString @Text . coerce++-- ** data Params++-- *** utils++-- This uses an association list because nix XML serialization preserves the+-- order of the param set.+type ParamSet r = [(VarName, Maybe r)]++data Variadic = Closed | Variadic+  deriving+    ( Eq, Ord, Generic+    , Typeable, Data, NFData, Serialise, Binary, ToJSON, FromJSON+    , Show, Read, Hashable+    )++instance Semigroup Variadic where+  (<>) Closed Closed = Closed+  (<>) _      _      = Variadic++instance Monoid Variadic where+  mempty = Closed++-- *** data Params++-- | @Params@ represents all the ways the formal parameters to a+-- function can be represented.+data Params r+  = Param !VarName+  -- ^ For functions with a single named argument, such as @x: x + 1@.+  --+  -- > Param "x"                                  ~  x+  | ParamSet !(Maybe VarName) !Variadic !(ParamSet r)+  -- ^ Explicit parameters (argument must be a set). Might specify a name to+  -- bind to the set in the function body. The bool indicates whether it is+  -- variadic or not.+  --+  -- > ParamSet  Nothing   False [("x",Nothing)]  ~  { x }+  -- > ParamSet (pure "s") True  [("x", pure y)]  ~  s@{ x ? y, ... }+  deriving+    ( Eq, Ord, Generic, Generic1+    , Typeable, Data, NFData, NFData1, Serialise, Binary, ToJSON, ToJSON1, FromJSON, FromJSON1+    , Functor, Foldable, Traversable+    , Show, Read, Hashable+    )++instance IsString (Params r) where+  fromString = Param . fromString++$(deriveShow1 ''Params)+$(deriveRead1 ''Params)+$(deriveEq1   ''Params)+$(deriveOrd1  ''Params)++deriving instance Hashable1 Params++-- *** lens traversals++$(makeTraversals ''Params)+++-- ** data Antiquoted++-- | 'Antiquoted' represents an expression that is either+-- antiquoted (surrounded by ${...}) or plain (not antiquoted).+data Antiquoted (v :: Type) (r :: Type)+  = Plain !v+  | EscapedNewline+  -- ^ 'EscapedNewline' corresponds to the special newline form+  --+  -- > ''\n+  --+  -- in an indented string. It is equivalent to a single newline character:+  --+  -- > ''''\n''  ≡  "\n"+  | Antiquoted !r+  deriving+    ( Eq, Ord, Generic, Generic1+    , Typeable, Data, NFData, NFData1, Serialise, Binary+    , ToJSON, ToJSON1, FromJSON, FromJSON1+    , Functor, Foldable, Traversable+    , Show, Read, Hashable+    )++$(deriveShow1 ''Antiquoted)+$(deriveShow2 ''Antiquoted)+$(deriveRead1 ''Antiquoted)+$(deriveRead2 ''Antiquoted)+$(deriveEq1   ''Antiquoted)+$(deriveEq2   ''Antiquoted)+$(deriveOrd1  ''Antiquoted)+$(deriveOrd2  ''Antiquoted)+$(deriveJSON2 defaultOptions ''Antiquoted)++instance Hashable2 Antiquoted where+  liftHashWithSalt2 ha _  salt (Plain a)      = ha (salt `hashWithSalt` (0 :: Int)) a+  liftHashWithSalt2 _  _  salt EscapedNewline =     salt `hashWithSalt` (1 :: Int)+  liftHashWithSalt2 _  hb salt (Antiquoted b) = hb (salt `hashWithSalt` (2 :: Int)) b++deriving instance (Hashable v) => Hashable1 (Antiquoted (v :: Type))++-- *** lens traversals++$(makeTraversals ''Antiquoted)+++-- ** data NString++-- | An 'NString' is a list of things that are either a plain string+-- or an antiquoted expression. After the antiquotes have been evaluated,+-- the final string is constructed by concatenating all the parts.+data NString r+  = DoubleQuoted ![Antiquoted Text r]+  -- ^ Strings wrapped with double-quotes (__@"@__) can contain literal newline+  -- characters, but the newlines are preserved and no indentation is stripped.+  --+  -- > DoubleQuoted [Plain "x",Antiquoted y]   ~  "x${y}"+  | Indented !Int ![Antiquoted Text r]+  -- ^ Strings wrapped with two single quotes (__@''@__) can contain newlines, and+  --   their indentation will be stripped, but the amount stripped is+  --   remembered.+  --+  -- > Indented 1 [Plain "x"]                  ~  '' x''+  -- >+  -- > Indented 0 [EscapedNewline]             ~  ''''\n''+  -- >+  -- > Indented 0 [Plain "x\n ",Antiquoted y]  ~  ''+  -- >                                            x+  -- >                                             ${y}''+  deriving+    ( Eq, Ord, Generic, Generic1+    , Typeable, Data, NFData, NFData1, Serialise, Binary, ToJSON, ToJSON1, FromJSON, FromJSON1+    , Functor, Foldable, Traversable+    , Show, Read, Hashable+    )++-- | For the the 'IsString' instance, we use a plain doublequoted string.+instance IsString (NString r) where+  fromString ""     = DoubleQuoted mempty+  fromString string = DoubleQuoted $ one $ Plain $ fromString string++$(deriveShow1 ''NString)+$(deriveRead1 ''NString)+$(deriveEq1   ''NString)+$(deriveOrd1  ''NString)++deriving instance Hashable1 NString++-- *** lens traversals++$(makeTraversals ''NString)+++-- ** data NKeyName++-- | A 'KeyName' is something that can appear on the left side of an+-- equals sign. For example, @a@ is a 'KeyName' in @{ a = 3; }@, @let a = 3;+-- in ...@, @{}.a@ or @{} ? a@.+--+-- Nix supports both static keynames (just an identifier) and dynamic+-- identifiers. Dynamic identifiers can be either a string (e.g.:+-- @{ "a" = 3; }@) or an antiquotation (e.g.: @let a = "example";+-- in { ${a} = 3; }.example@).+--+-- Note: There are some places where a dynamic keyname is not allowed.+-- In particular, those include:+--+--   * The RHS of a @binding@ inside @let@: @let ${"a"} = 3; in ...@+--     produces a syntax fail.+--   * The attribute names of an 'inherit': @inherit ${"a"};@ is forbidden.+--+-- Note: In Nix, a simple string without antiquotes such as @"foo"@ is+-- allowed even if the context requires a static keyname, but the+-- parser still considers it a 'DynamicKey' for simplicity.+data NKeyName r+  = DynamicKey !(Antiquoted (NString r) r)+  -- ^+  -- > DynamicKey (Plain (DoubleQuoted [Plain "x"]))     ~  "x"+  -- > DynamicKey (Antiquoted x)                         ~  ${x}+  -- > DynamicKey (Plain (DoubleQuoted [Antiquoted x]))  ~  "${x}"+  | StaticKey !VarName+  -- ^+  -- > StaticKey "x"                                     ~  x+  deriving+    ( Eq, Ord, Generic+    , Typeable, Data, NFData, Serialise, Binary, ToJSON, FromJSON+    , Show, Read, Hashable+    )++instance NFData1 NKeyName where+  liftRnf _ (StaticKey  !_            ) = mempty+  liftRnf _ (DynamicKey (Plain !_)    ) = mempty+  liftRnf _ (DynamicKey EscapedNewline) = mempty+  liftRnf k (DynamicKey (Antiquoted r)) = k r++-- | Most key names are just static text, so this instance is convenient.+instance IsString (NKeyName r) where+  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 _  _              _              = False++-- | @since 0.10.1+instance Ord1 NKeyName where+  liftCompare cmp (DynamicKey a) (DynamicKey b) = liftCompare2 (liftCompare cmp) cmp a b+  liftCompare _   (DynamicKey _) (StaticKey  _) = LT+  liftCompare _   (StaticKey  _) (DynamicKey _) = GT+  liftCompare _   (StaticKey  a) (StaticKey  b) = compare a b++instance Hashable1 NKeyName where+  liftHashWithSalt h salt (DynamicKey a) =+    liftHashWithSalt2 (liftHashWithSalt h) h (salt `hashWithSalt` (0 :: Int)) a+  liftHashWithSalt _ salt (StaticKey n) =+    salt `hashWithSalt` (1 :: Int) `hashWithSalt` n++-- 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 Text.Show.showsPrec "StaticKey" p t++-- Deriving this instance automatically is not possible because @r@+-- occurs not only as last argument in @Antiquoted (NString r) r@+instance Functor NKeyName where+  fmap = fmapDefault++-- Deriving this instance automatically is not possible because @r@+-- occurs not only as last argument in @Antiquoted (NString r) r@+instance Foldable NKeyName where+  foldMap = foldMapDefault++-- Deriving this instance automatically is not possible because @r@+-- occurs not only as last argument in @Antiquoted (NString r) r@+instance Traversable NKeyName where+  traverse f = \case+    DynamicKey (Plain      str) -> DynamicKey . Plain <$> traverse f str+    DynamicKey (Antiquoted e  ) -> DynamicKey . Antiquoted <$> f e+    DynamicKey EscapedNewline   -> pure $ DynamicKey EscapedNewline+    StaticKey  key              -> pure $ StaticKey key++-- *** lens traversals++$(makeTraversals ''NKeyName)+++-- ** type NAttrPath++-- | A selector (for example in a @let@ or an attribute set) is made up+-- of strung-together key names.+--+-- > StaticKey "x" :| [DynamicKey (Antiquoted y)]  ~  x.${y}+type NAttrPath r = NonEmpty (NKeyName r)+++-- ** data Binding++#if !MIN_VERSION_hashable(1,3,1)+-- Required by Hashable Binding deriving. There was none of this Hashable instance before mentioned version, remove this in year >2022+instance Hashable1 NonEmpty+#endif++-- | A single line of the bindings section of a let expression or of a set.+data Binding r+  = NamedVar !(NAttrPath r) !r !NSourcePos+  -- ^ An explicit naming.+  --+  -- > NamedVar (StaticKey "x" :| [StaticKey "y"]) z NSourcePos{}  ~  x.y = z;+  | Inherit !(Maybe r) ![VarName] !NSourcePos+  -- ^ Inheriting an attribute (binding) into the attribute set from the other scope (attribute set). No denoted scope means to inherit from the closest outside scope.+  --+  -- +----------------------------------------------------------------+--------------------+-----------------------++  -- | Hask                                                           | Nix                | pseudocode            |+  -- +================================================================+====================+=======================++  -- | @Inherit Nothing  [StaticKey "a"] NSourcePos{}@                | @inherit a;@       | @a = outside.a;@      |+  -- +----------------------------------------------------------------+--------------------+-----------------------++  -- | @Inherit (pure x) [StaticKey "a"] NSourcePos{}@                | @inherit (x) a;@   | @a = x.a;@            |+  -- +----------------------------------------------------------------+--------------------+-----------------------++  -- | @Inherit (pure x) [StaticKey "a", StaticKey "b"] NSourcePos{}@ | @inherit (x) a b;@ | @a = x.a;@            |+  -- |                                                                |                    | @b = x.b;@            |+  -- +----------------------------------------------------------------+--------------------+-----------------------++  --+  -- (2021-07-07 use details):+  -- Inherits the position of the first name through @unsafeGetAttrPos@. The position of the scope inherited from else - the position of the first member of the binds list.+  deriving+    ( Eq, Ord, Generic, Generic1+    , Typeable, Data, NFData, NFData1, Serialise, Binary, ToJSON, FromJSON+    , Functor, Foldable, Traversable+    , Show, Hashable+    )++$(deriveShow1 ''Binding)+$(deriveEq1   ''Binding)+$(deriveOrd1  ''Binding)+--x $(deriveJSON1 defaultOptions ''Binding)++deriving instance Hashable1 Binding++-- *** lens traversals++$(makeTraversals ''Binding)+++-- ** data Recursivity++-- | Distinguishes between recursive and non-recursive. Mainly for attribute+-- sets.+data Recursivity+  = NonRecursive  -- ^ >     { ... }+  | Recursive     -- ^ > rec { ... }+  deriving+    ( Eq, Ord, Enum, Bounded, Generic+    , Typeable, Data, NFData, Serialise, Binary, ToJSON, FromJSON+    , Show, Read, Hashable+    )++instance Semigroup Recursivity where+  (<>) NonRecursive NonRecursive = NonRecursive+  (<>) _ _ = Recursive++instance Monoid Recursivity where+  mempty = NonRecursive++-- ** data NUnaryOp++-- | There are two unary operations: logical not and integer negation.+data NUnaryOp+  = NNeg  -- ^ @-@+  | NNot  -- ^ @!@+  deriving+    ( Eq, Ord, Enum, Bounded, Generic+    , Typeable, Data, NFData, Serialise, Binary, ToJSON, FromJSON+    , Show, Read, Hashable+    )++-- *** lens traversals++$(makeTraversals ''NUnaryOp)++-- ** data NBinaryOp++-- | Binary operators expressible in the nix language.+data NBinaryOp+  = NEq      -- ^ Equality (@==@)+  | NNEq     -- ^ Inequality (@!=@)+  | NLt      -- ^ Less than (@<@)+  | NLte     -- ^ Less than or equal (@<=@)+  | NGt      -- ^ Greater than (@>@)+  | NGte     -- ^ Greater than or equal (@>=@)+  | NAnd     -- ^ Logical and (@&&@)+  | NOr      -- ^ Logical or (@||@)+  | NImpl    -- ^ Logical implication (@->@)+  | NUpdate  -- ^ Get the left attr set, extend it with the right one & override equal keys (@//@)+  | NPlus    -- ^ Addition (@+@)+  | NMinus   -- ^ Subtraction (@-@)+  | NMult    -- ^ Multiplication (@*@)+  | NDiv     -- ^ Division (@/@)+  | NConcat  -- ^ List concatenation (@++@)+  deriving+    ( Eq, Ord, Enum, Bounded, Generic+    , Typeable, Data, NFData, Serialise, Binary, ToJSON, FromJSON+    , Show, Read, Hashable+    )++-- *** lens traversals++$(makeTraversals ''NBinaryOp)+++-- * data NExprF - Nix expressions, base functor++-- | The main Nix expression type. As it is polimorphic, has a functor,+-- which allows to traverse expressions and map functions over them.+-- The actual 'NExpr' type is a fixed point of this functor, defined+-- below.+data NExprF r+  = NConstant !NAtom+  -- ^ Constants: ints, floats, bools, URIs, and null.+  | NStr !(NString r)+  -- ^ A string, with interpolated expressions.+  | NSym !VarName+  -- ^ A variable. For example, in the expression @f a@, @f@ is represented+  -- as @NSym "f"@ and @a@ as @NSym "a"@.+  --+  -- > NSym "x"                                    ~  x+  | NList ![r]+  -- ^ A list literal.+  --+  -- > NList [x,y]                                 ~  [ x y ]+  | NSet !Recursivity ![Binding r]+  -- ^ An attribute set literal+  --+  -- > NSet Recursive    [NamedVar x y _]         ~  rec { x = y; }+  -- > NSet NonRecursive [Inherit Nothing [x] _]  ~  { inherit x; }+  | NLiteralPath !Path+  -- ^ A path expression, which is evaluated to a store path. The path here+  -- can be relative, in which case it's evaluated relative to the file in+  -- which it appears.+  --+  -- > NLiteralPath "/x"                           ~  /x+  -- > NLiteralPath "x/y"                          ~  x/y+  | NEnvPath !Path+  -- ^ A path which refers to something in the Nix search path (the NIX_PATH+  -- environment variable. For example, @<nixpkgs/pkgs>@.+  --+  -- > NEnvPath "x"                                ~  <x>+  | NApp !r !r+  -- ^ Functional application (aka F.A., apply a function to an argument).+  --+  -- > NApp f x  ~  f x+  | NUnary !NUnaryOp !r+  -- ^ Application of a unary operator to an expression.+  --+  -- > NUnary NNeg x                               ~  - x+  -- > NUnary NNot x                               ~  ! x+  | NBinary !NBinaryOp !r !r+  -- ^ Application of a binary operator to two expressions.+  --+  -- > NBinary NPlus x y                           ~  x + y+  -- > NBinary NApp  f x                           ~  f x+  | NSelect !(Maybe r) !r !(NAttrPath r)+  -- ^ Dot-reference into an attribute set, optionally providing an+  -- alternative if the key doesn't exist.+  --+  -- > NSelect Nothing  s (x :| [])                ~  s.x+  -- > NSelect (pure y) s (x :| [])                ~  s.x or y+  | NHasAttr !r !(NAttrPath r)+  -- ^ Ask if a set contains a given attribute path.+  --+  -- > NHasAttr s (x :| [])                        ~  s ? x+  | NAbs !(Params r) !r+  -- ^ A function literal (lambda abstraction).+  --+  -- > NAbs (Param "x") y                          ~  x: y+  | NLet ![Binding r] !r+  -- ^ Evaluate the second argument after introducing the bindings.+  --+  -- > NLet []                    x                ~  let in x+  -- > NLet [NamedVar x y _]      z                ~  let x = y; in z+  -- > NLet [Inherit Nothing x _] y                ~  let inherit x; in y+  | NIf !r !r !r+  -- ^ If-then-else statement.+  --+  -- > NIf x y z                                   ~  if x then y else z+  | NWith !r !r+  -- ^ Evaluate an attribute set, bring its bindings into scope, and+  -- evaluate the second argument.+  --+  -- > NWith x y                                   ~  with x; y+  | NAssert !r !r+  -- ^ Checks that the first argument is a predicate that is @true@ before evaluating the second argument.+  --+  -- > NAssert x y                                 ~  assert x; y+  | NSynHole !VarName+  -- ^ Syntactic hole.+  --+  -- See <https://github.com/haskell-nix/hnix/issues/197> for context.+  --+  -- > NSynHole "x"                                ~  ^x+  deriving+    ( Eq, Ord, Generic, Generic1+    , Typeable, Data, NFData, NFData1, Serialise, Binary, ToJSON, FromJSON+    , Functor, Foldable, Traversable+    , Show, Hashable+    )+++$(deriveShow1 ''NExprF)+$(deriveEq1   ''NExprF)+$(deriveOrd1  ''NExprF)+--x $(deriveJSON1 defaultOptions ''NExprF)++deriving instance Hashable1 NExprF++-- ** lens traversals++$(makeTraversals ''NExprF)+++-- ** type NExpr++-- | The monomorphic expression type is a fixed point of the polymorphic one.+type NExpr = Fix NExprF++-- | 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++instance Serialise NExpr++instance TH.Lift NExpr where+  lift =+    TH.dataToExpQ+      (\b ->+        do+          -- Binding on constructor ensures type match and gives type inference to TH.+          -- Reflection is the ability of a process to examine, introspect, and modify its own structure and behavior.+          -- Reflection is a key strategy in metaprogramming.+          -- <https://en.wikipedia.org/wiki/Reflective_programming>+          HRefl <-+            Reflection.eqTypeRep+              (Reflection.typeRep @Text)+              (Reflection.typeOf  b    )+          pure [| $(TH.lift b) |]+      )+#if MIN_VERSION_template_haskell(2,17,0)+  liftTyped = TH.unsafeCodeCoerce . TH.lift+#elif MIN_VERSION_template_haskell(2,16,0)+  liftTyped = TH.unsafeTExpCoerce . TH.lift+#endif+++-- ** Methods++#if __GLASGOW_HASKELL__ >= 900+hashAt+  :: Functor f+  => VarName+  -> (Maybe v -> f (Maybe v))+  -> AttrSet v+  -> f (AttrSet v)+#else+hashAt :: VarName -> Lens' (AttrSet v) (Maybe v)+#endif+hashAt = alterF+ where+  alterF+    :: (Functor f)+    => VarName+    -> (Maybe v -> f (Maybe v))+    -> AttrSet v+    -> f (AttrSet v)+  alterF (coerce -> k) f m =+    maybe+      (MapL.delete k m)+      (\ v -> MapL.insert k v m)+      <$> f (MapL.lookup k m)++-- | Get the name out of the parameter (there might be none).+paramName :: Params r -> Maybe VarName+paramName (Param name        ) = pure name+paramName (ParamSet mname _ _) = mname++stringParts :: NString r -> [Antiquoted Text r]+stringParts (DoubleQuoted parts) = parts+stringParts (Indented _   parts) = parts++stripPositionInfo :: NExpr -> NExpr+stripPositionInfo = transport phi+ where+  transport f (Fix x) = Fix $ transport f <$> f x++  phi (NSet recur binds) = NSet recur $ erasePositions <$> binds+  phi (NLet binds body) = NLet (erasePositions <$> binds) body+  phi x                 = x++  erasePositions (NamedVar path r     _pos) = NamedVar path r     nullPos+  erasePositions (Inherit  ms   names _pos) = Inherit  ms   names nullPos++nullPos :: NSourcePos+nullPos = on (NSourcePos "<string>") (coerce . mkPos) 1 1++-- * Dead code++-- ** class NExprAnn++class NExprAnn ann g | g -> ann where+  fromNExpr :: g r -> (NExprF r, ann)+  toNExpr :: (NExprF r, ann) -> g r++-- ** Other++ekey+  :: forall ann g+  . NExprAnn ann g+  => NonEmpty VarName+  -> NSourcePos+  -> Lens' (Fix g) (Maybe (Fix g))+ekey keys pos f e@(Fix x)+  | (NSet NonRecursive xs, ann) <- fromNExpr x =+    let+      vals :: [(Fix g, [VarName])]+      vals =+        do+          let keys' = NE.toList keys+          (ks, rest) <- zip (inits keys') (tails keys')+          handlePresence+            mempty+            (\ (j : js) ->+              do+                NamedVar ns v _p <- xs+                guard $ (j : js) == (NE.toList ns ^.. traverse . _StaticKey)+                pure (v, rest)+            )+            ks+    in+    case vals of+      ((v, []      ) : _) -> fromMaybe e <$> f (pure v)+      ((v, r : rest) : _) -> ekey (r :| rest) pos f v++      _                   ->+        maybe+          e+          (\ v ->+            let entry = NamedVar (StaticKey <$> keys) v pos in+            Fix $ toNExpr ( NSet mempty $ one entry <> xs, ann )+          )+        <$> f Nothing+ekey _ _ f e = fromMaybe e <$> f Nothing+++getFreeVars :: NExpr -> Set VarName+getFreeVars e =+  case unFix e of+    (NConstant    _               ) -> mempty+    (NStr         string          ) -> mapFreeVars string+    (NSym         var             ) -> one var+    (NList        list            ) -> mapFreeVars list+    (NSet   NonRecursive  bindings) -> bindFreeVars bindings+    (NSet   Recursive     bindings) -> diffBetween bindFreeVars bindDefs bindings+    (NLiteralPath _               ) -> mempty+    (NEnvPath     _               ) -> mempty+    (NUnary       _    expr       ) -> getFreeVars expr+    (NApp         left right      ) -> collectFreeVars left right+    (NBinary      _    left right ) -> collectFreeVars left right+    (NSelect      orExpr expr path) ->+      Set.unions+        [ getFreeVars expr+        , pathFree path+        , getFreeVars `whenJust` orExpr+        ]+    (NHasAttr expr            path) -> getFreeVars expr <> pathFree path+    (NAbs     (Param varname) expr) -> Set.delete varname (getFreeVars expr)+    (NAbs (ParamSet varname _ pset) expr) ->+      Set.difference+        -- Include all free variables from the expression and the default arguments+        (getFreeVars expr <> Set.unions (getFreeVars <$> mapMaybe snd pset))+        -- But remove the argument name if existing, and all arguments in the parameter set+        ((one `whenJust` varname) <> Set.fromList (fst <$> pset))+    (NLet         bindings expr   ) ->+      Set.difference+        (getFreeVars expr <> bindFreeVars bindings)+        (bindDefs bindings)+    (NIf          cond th   el    ) -> Set.unions $ getFreeVars <$> [cond, th, el]+    -- Evaluation is needed to find out whether x is a "real" free variable in `with y; x`, we just include it+    -- This also makes sense because its value can be overridden by `x: with y; x`+    (NWith        set  expr       ) -> collectFreeVars set expr+    (NAssert      assertion expr  ) -> collectFreeVars assertion expr+    (NSynHole     _               ) -> mempty+ where+  diffBetween :: (a -> Set VarName) -> (a -> Set VarName) -> a -> Set VarName+  diffBetween g f b = Set.difference (g b) (f b)++  collectFreeVars :: NExpr -> NExpr -> Set VarName+  collectFreeVars = (<>) `on` getFreeVars++  bindDefs :: Foldable t => t (Binding NExpr) -> Set VarName+  bindDefs = foldMap bind1Def+   where+    bind1Def :: Binding r -> Set VarName+    bind1Def (Inherit   Nothing                  _    _) = mempty+    bind1Def (Inherit  (Just _                 ) keys _) = Set.fromList keys+    bind1Def (NamedVar (StaticKey  varname :| _) _    _) = one varname+    bind1Def (NamedVar (DynamicKey _       :| _) _    _) = mempty++  bindFreeVars :: Foldable t => t (Binding NExpr) -> Set VarName+  bindFreeVars = foldMap bind1Free+   where+    bind1Free :: Binding NExpr -> Set VarName+    bind1Free (Inherit  Nothing     keys _) = Set.fromList keys+    bind1Free (Inherit (Just scope) _    _) = getFreeVars scope+    bind1Free (NamedVar path        expr _) = pathFree path <> getFreeVars expr++  pathFree :: NAttrPath NExpr -> Set VarName+  pathFree = foldMap mapFreeVars++  mapFreeVars :: Foldable t => t NExpr -> Set VarName+  mapFreeVars = foldMap getFreeVars
src/Nix/Expr/Types/Annotated.hs view
@@ -1,241 +1,305 @@-{-# LANGUAGE CPP                #-}-{-# LANGUAGE DeriveAnyClass     #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveFoldable     #-}-{-# LANGUAGE DeriveFunctor      #-}-{-# LANGUAGE DeriveGeneric      #-}-{-# LANGUAGE DeriveTraversable  #-}-{-# LANGUAGE FlexibleInstances  #-}-{-# LANGUAGE KindSignatures     #-}-{-# LANGUAGE LambdaCase         #-}-{-# LANGUAGE OverloadedStrings  #-}-{-# LANGUAGE PatternSynonyms    #-}-{-# LANGUAGE RankNTypes         #-}-{-# LANGUAGE TemplateHaskell    #-}+{-# language CPP                #-}+{-# language DeriveAnyClass     #-}+{-# language KindSignatures     #-}+{-# language PatternSynonyms    #-}+{-# language RankNTypes         #-}+{-# language TemplateHaskell    #-}  -- | The source location annotated nix expression type and supporting types. -- module Nix.Expr.Types.Annotated   ( module Nix.Expr.Types.Annotated   , module Data.Functor.Compose-  , SourcePos(..), unPos, mkPos-  )where+  )+where -#ifdef MIN_VERSION_serialise-import Codec.Serialise-#endif-import Control.DeepSeq-import Data.Aeson (ToJSON(..), FromJSON(..))-import Data.Aeson.TH-import Data.Binary (Binary(..))-import Data.Data-import Data.Eq.Deriving-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)-import GHC.Generics-import Nix.Atoms-import Nix.Expr.Types-import Text.Megaparsec (unPos, mkPos)-import Text.Megaparsec.Pos (SourcePos(..))-import Text.Read.Deriving-import Text.Show.Deriving+import           Nix.Prelude+import           Codec.Serialise+import           Control.DeepSeq+import           Data.Aeson                     ( ToJSON(..)+                                                , FromJSON(..)+                                                )+import           Data.Aeson.TH+import           Data.Binary                    ( Binary(..) )+import           Data.Data+import           Data.Eq.Deriving+import           Data.Fix                       ( Fix(..)+                                                , unfoldFix+                                                )+import           Data.Functor.Compose+import           Data.Hashable.Lifted+import           Data.Ord.Deriving+import           GHC.Generics+import           Nix.Atoms+import           Nix.Expr.Types+import           Text.Read.Deriving+import           Text.Show.Deriving --- | A location in a source file+-- * data type @SrcSpan@ - a zone in a source file++-- | Demarcation of a chunk in a source file. data SrcSpan = SrcSpan-    { spanBegin :: SourcePos-    , spanEnd   :: SourcePos-    }-    deriving (Ord, Eq, Generic, Typeable, Data, Show, NFData,-              Hashable)+  { getSpanBegin :: NSourcePos+  , getSpanEnd   :: NSourcePos+  }+ deriving (Ord, Eq, Generic, Typeable, Data, Show, NFData, Hashable) -#ifdef MIN_VERSION_serialise+-- ** Instances++instance Semigroup SrcSpan where+  s1 <> s2 =+    SrcSpan+      (on min getSpanBegin s1 s2)+      (on max getSpanEnd   s1 s2)++instance Binary SrcSpan+instance ToJSON SrcSpan+instance FromJSON SrcSpan+ instance Serialise SrcSpan-#endif +-- * data type @Ann@++--  2021-08-02: NOTE: Annotation needs to be after what is annotated. -- | A type constructor applied to a type along with an annotation -- -- Intended to be used with 'Fix':--- @type MyType = Fix (Compose (Ann Annotation) F)@-data Ann ann a = Ann-    { annotation :: ann-    , annotated  :: a-    }-    deriving (Ord, Eq, Data, Generic, Generic1, Typeable, Functor, Foldable,-              Traversable, Read, Show, NFData, Hashable)+-- @type MyType = Fix (Compose (AnnUnit Annotation) F)@+data AnnUnit ann expr = AnnUnit+  { annotation :: ann+  , annotated  :: expr+  }+ deriving+  ( Eq, Ord, Data, Typeable, Hashable+  , Generic, Generic1, NFData+  , Functor, Foldable, Traversable+  , Show, Read+  ) -#if MIN_VERSION_hashable(1, 2, 5)-instance Hashable ann => Hashable1 (Ann ann)-#endif+type AnnF ann f = Compose (AnnUnit ann) f -#ifdef MIN_VERSION_serialise-instance (Serialise ann, Serialise a) => Serialise (Ann ann a)-#endif+-- | Pattern: @(Compose (AnnUnit _ _))@.+pattern AnnF+  :: ann+  -> f a+  -> Compose (AnnUnit ann) f a+pattern AnnF ann f = Compose (AnnUnit ann f)+{-# complete AnnF #-} -#if MIN_VERSION_deepseq(1, 4, 3)-instance NFData ann => NFData1 (Ann ann)-#endif -$(deriveEq1   ''Ann)-$(deriveEq2   ''Ann)-$(deriveOrd1  ''Ann)-$(deriveOrd2  ''Ann)-$(deriveRead1 ''Ann)-$(deriveRead2 ''Ann)-$(deriveShow1 ''Ann)-$(deriveShow2 ''Ann)-$(deriveJSON1 defaultOptions ''Ann)-$(deriveJSON2 defaultOptions ''Ann)+type Ann ann f = Fix (AnnF ann f) -instance Semigroup SrcSpan where-  s1 <> s2 = SrcSpan ((min `on` spanBegin) s1 s2)-                     ((max `on` spanEnd) s1 s2)+-- | Pattern: @Fix (Compose (AnnUnit _ _))@.+-- Fix composes units of (annotations & the annotated) into one object.+-- Giving annotated expression.+pattern Ann+  :: forall ann (f :: Type -> Type)+  . ann+  -> f (Ann ann f)+  -> Ann ann f+pattern Ann ann a = Fix (AnnF ann a)+{-# complete Ann #-} -type AnnF ann f = Compose (Ann ann) f+annUnitToAnn :: AnnUnit ann (f (Ann ann f)) -> Ann ann f+annUnitToAnn (AnnUnit ann a) = Ann ann a -annToAnnF :: Ann ann (f (Fix (AnnF ann f))) -> Fix (AnnF ann f)-annToAnnF (Ann ann a) = AnnE ann a+-- ** Instances -type NExprLocF = AnnF SrcSpan NExprF+instance NFData ann => NFData1 (AnnUnit ann) --- | A nix expression with source location at each subexpression.-type NExprLoc = Fix NExprLocF+instance (Binary ann, Binary a) => Binary (AnnUnit ann a) -#if !MIN_VERSION_deepseq(1, 4, 3)-instance (NFData (f (g a)), NFData (g a)) => NFData (Compose f g a)-#endif+$(deriveEq1   ''AnnUnit)+$(deriveEq2   ''AnnUnit)+$(deriveOrd1  ''AnnUnit)+$(deriveOrd2  ''AnnUnit)+$(deriveRead1 ''AnnUnit)+$(deriveRead2 ''AnnUnit)+$(deriveShow1 ''AnnUnit)+$(deriveShow2 ''AnnUnit)+$(deriveJSON1 defaultOptions ''AnnUnit)+$(deriveJSON2 defaultOptions ''AnnUnit) -instance NFData NExprLoc+instance Hashable ann => Hashable1 (AnnUnit ann) -#ifdef MIN_VERSION_serialise-instance Serialise NExprLoc-#endif+instance (Serialise ann, Serialise a) => Serialise (AnnUnit ann a) -#if MIN_VERSION_hashable(1, 2, 5)-instance Hashable NExprLoc-#endif+-- ** @NExprLoc{,F}@ - annotated Nix expression -instance Binary SrcSpan-instance (Binary ann, Binary a) => Binary (Ann ann a)+type NExprLocF = AnnF SrcSpan NExprF++instance Serialise r => Serialise (NExprLocF r) where+  encode (AnnF ann a) = encode ann <> encode a+  decode =+    liftA2 AnnF+      decode+      decode+ instance Binary r => Binary (NExprLocF r)-instance Binary NExprLoc -instance ToJSON SrcSpan-instance FromJSON SrcSpan+-- | Annotated Nix expression (each subexpression direct to its source location).+type NExprLoc = Fix NExprLocF -#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+instance Serialise NExprLoc -pattern AnnE :: forall ann (g :: * -> *). ann-             -> g (Fix (Compose (Ann ann) g)) -> Fix (Compose (Ann ann) g)-pattern AnnE ann a = Fix (Compose (Ann ann a))+instance Binary NExprLoc -stripAnnotation :: Functor f => Fix (AnnF ann f) -> Fix f-stripAnnotation = ana (annotated . getCompose . unFix)+-- * Other -stripAnn :: AnnF ann f r -> f r-stripAnn = annotated . getCompose+stripAnnF :: AnnF ann f r -> f r+stripAnnF = annotated . getCompose -nUnary :: Ann SrcSpan NUnaryOp -> NExprLoc -> NExprLoc-nUnary (Ann s1 u) e1@(AnnE s2 _) = AnnE (s1 <> s2) (NUnary u e1)-nUnary _ _ = error "nUnary: unexpected"+stripAnnotation :: Functor f => Ann ann f -> Fix f+stripAnnotation = unfoldFix (stripAnnF . unFix) -nBinary :: Ann SrcSpan NBinaryOp -> NExprLoc -> NExprLoc -> NExprLoc-nBinary (Ann s1 b) e1@(AnnE s2 _) e2@(AnnE s3 _) =-  AnnE (s1 <> s2 <> s3) (NBinary b e1 e2)-nBinary _ _ _ = error "nBinary: unexpected"+annNUnary :: AnnUnit SrcSpan NUnaryOp -> NExprLoc -> NExprLoc+annNUnary (AnnUnit s1 u) e1@(Ann s2 _) = NUnaryAnn (s1 <> s2) u e1+{-# inline annNUnary #-} -nSelectLoc :: NExprLoc -> Ann SrcSpan (NAttrPath NExprLoc) -> Maybe NExprLoc-           -> NExprLoc-nSelectLoc e1@(AnnE s1 _) (Ann s2 ats) d = case d of-  Nothing               -> AnnE (s1 <> s2) (NSelect e1 ats Nothing)-  Just (e2@(AnnE s3 _)) -> AnnE (s1 <> s2 <> s3) (NSelect e1 ats (Just e2))-  _ -> error "nSelectLoc: unexpected"-nSelectLoc _ _ _ = error "nSelectLoc: unexpected"+annNBinary :: AnnUnit SrcSpan NBinaryOp -> NExprLoc -> NExprLoc -> NExprLoc+annNBinary (AnnUnit s1 b) e1@(Ann s2 _) e2@(Ann s3 _) = NBinaryAnn (s1 <> s2 <> s3) b e1 e2 -nHasAttr :: NExprLoc -> Ann SrcSpan (NAttrPath NExprLoc) -> NExprLoc-nHasAttr e1@(AnnE s1 _) (Ann s2 ats) = AnnE (s1 <> s2) (NHasAttr e1 ats)-nHasAttr _ _ = error "nHasAttr: unexpected"+annNSelect+  :: Maybe NExprLoc -> NExprLoc -> AnnUnit SrcSpan (NAttrPath NExprLoc) -> NExprLoc+annNSelect  Nothing             e2@(Ann s2 _) (AnnUnit s1 ats) = NSelectAnn (      s2 <> s1)  Nothing  e2 ats+annNSelect (Just e3@(Ann s3 _)) e2@(Ann s2 _) (AnnUnit s1 ats) = NSelectAnn (s3 <> s2 <> s1) (pure e3) e2 ats -nApp :: NExprLoc -> NExprLoc -> NExprLoc-nApp e1@(AnnE s1 _) e2@(AnnE s2 _) = AnnE (s1 <> s2) (NBinary NApp e1 e2)-nApp _ _ = error "nApp: unexpected"+annNHasAttr :: NExprLoc -> AnnUnit SrcSpan (NAttrPath NExprLoc) -> NExprLoc+annNHasAttr e1@(Ann s1 _) (AnnUnit s2 ats) = NHasAttrAnn (s1 <> s2) e1 ats -nAbs :: Ann SrcSpan (Params NExprLoc) -> NExprLoc -> NExprLoc-nAbs (Ann s1 ps) e1@(AnnE s2 _) = AnnE (s1 <> s2) (NAbs ps e1)-nAbs _ _ = error "nAbs: unexpected"+annNApp :: NExprLoc -> NExprLoc -> NExprLoc+annNApp e1@(Ann s1 _) e2@(Ann s2 _) = NAppAnn (s1 <> s2) e1 e2 -nStr :: Ann SrcSpan (NString NExprLoc) -> NExprLoc-nStr (Ann s1 s) = AnnE s1 (NStr s)+annNAbs :: AnnUnit SrcSpan (Params NExprLoc) -> NExprLoc -> NExprLoc+annNAbs (AnnUnit s1 ps) e1@(Ann s2 _) = NAbsAnn (s1 <> s2) ps e1 -deltaInfo :: SourcePos -> (Text, Int, Int)-deltaInfo (SourcePos fp l c) = (pack fp, unPos l, unPos c)+annNStr :: AnnUnit SrcSpan (NString NExprLoc) -> NExprLoc+annNStr (AnnUnit s1 s) = NStrAnn s1 s -nNull :: NExprLoc-nNull = Fix (Compose (Ann nullSpan (NConstant NNull)))+deltaInfo :: NSourcePos -> (Text, Int, Int)+deltaInfo (NSourcePos fp l c) = (fromString $ coerce fp, unPos $ coerce l, unPos $ coerce c) +annNNull :: NExprLoc+annNNull = NConstantAnn nullSpan NNull+{-# inline annNNull #-}+ nullSpan :: SrcSpan nullSpan = SrcSpan nullPos nullPos+{-# inline nullSpan #-} --- | Pattern systems for matching on NExprLocF constructions.+-- ** Patterns -pattern NSym_ :: SrcSpan -> VarName -> NExprLocF r-pattern NSym_ ann x = Compose (Ann ann (NSym x))+-- *** Patterns to match on 'NExprLocF' constructions (for 'SrcSpan'-based annotations). -pattern NConstant_ :: SrcSpan -> NAtom -> NExprLocF r-pattern NConstant_ ann x = Compose (Ann ann (NConstant x))+pattern NConstantAnnF    :: SrcSpan -> NAtom -> NExprLocF r+pattern NConstantAnnF    ann x      = AnnF ann (NConstant x) -pattern NStr_ :: SrcSpan -> NString r -> NExprLocF r-pattern NStr_ ann x = Compose (Ann ann (NStr x))+pattern NStrAnnF         :: SrcSpan -> NString r -> NExprLocF r+pattern NStrAnnF         ann x      = AnnF ann (NStr x) -pattern NList_ :: SrcSpan -> [r] -> NExprLocF r-pattern NList_ ann x = Compose (Ann ann (NList x))+pattern NSymAnnF         :: SrcSpan -> VarName -> NExprLocF r+pattern NSymAnnF         ann x      = AnnF ann (NSym x) -pattern NSet_ :: SrcSpan -> [Binding r] -> NExprLocF r-pattern NSet_ ann x = Compose (Ann ann (NSet x))+pattern NListAnnF        :: SrcSpan -> [r] -> NExprLocF r+pattern NListAnnF        ann x      = AnnF ann (NList x) -pattern NRecSet_ :: SrcSpan -> [Binding r] -> NExprLocF r-pattern NRecSet_ ann x = Compose (Ann ann (NRecSet x))+pattern NSetAnnF         :: SrcSpan -> Recursivity -> [Binding r] -> NExprLocF r+pattern NSetAnnF         ann rec x  = AnnF ann (NSet rec x) -pattern NLiteralPath_ :: SrcSpan -> FilePath -> NExprLocF r-pattern NLiteralPath_ ann x = Compose (Ann ann (NLiteralPath x))+pattern NLiteralPathAnnF :: SrcSpan -> Path -> NExprLocF r+pattern NLiteralPathAnnF ann x      = AnnF ann (NLiteralPath x) -pattern NEnvPath_ :: SrcSpan -> FilePath -> NExprLocF r-pattern NEnvPath_ ann x = Compose (Ann ann (NEnvPath x))+pattern NEnvPathAnnF     :: SrcSpan -> Path -> NExprLocF r+pattern NEnvPathAnnF     ann x      = AnnF ann (NEnvPath x) -pattern NSelect_ :: SrcSpan -> r -> NAttrPath r -> Maybe r -> NExprLocF r-pattern NSelect_ ann x p v = Compose (Ann ann (NSelect x p v))+pattern NUnaryAnnF       :: SrcSpan -> NUnaryOp -> r -> NExprLocF r+pattern NUnaryAnnF       ann op x   = AnnF ann (NUnary op x) -pattern NHasAttr_ :: SrcSpan -> r -> NAttrPath r -> NExprLocF r-pattern NHasAttr_ ann x p = Compose (Ann ann (NHasAttr x p))+pattern NAppAnnF         :: SrcSpan -> r -> r -> NExprLocF r+pattern NAppAnnF         ann x y    = AnnF ann (NApp x y) -pattern NAbs_ :: SrcSpan -> Params r-> r -> NExprLocF r-pattern NAbs_ ann x b = Compose (Ann ann (NAbs x b))+pattern NBinaryAnnF      :: SrcSpan -> NBinaryOp -> r -> r -> NExprLocF r+pattern NBinaryAnnF      ann op x y = AnnF ann (NBinary op x y) -pattern NLet_ :: SrcSpan -> [Binding r] -> r -> NExprLocF r-pattern NLet_ ann x b = Compose (Ann ann (NLet x b))+pattern NSelectAnnF      :: SrcSpan ->  Maybe r -> r -> NAttrPath r -> NExprLocF r+pattern NSelectAnnF      ann v x p  = AnnF ann (NSelect v x p) -pattern NIf_ :: SrcSpan -> r -> r -> r -> NExprLocF r-pattern NIf_ ann c t e = Compose (Ann ann (NIf c t e))+pattern NHasAttrAnnF     :: SrcSpan -> r -> NAttrPath r -> NExprLocF r+pattern NHasAttrAnnF     ann x p    = AnnF ann (NHasAttr x p) -pattern NWith_ :: SrcSpan -> r -> r -> NExprLocF r-pattern NWith_ ann x y = Compose (Ann ann (NWith x y))+pattern NAbsAnnF         :: SrcSpan -> Params r-> r -> NExprLocF r+pattern NAbsAnnF         ann x b    = AnnF ann (NAbs x b) -pattern NAssert_ :: SrcSpan -> r -> r -> NExprLocF r-pattern NAssert_ ann x y = Compose (Ann ann (NAssert x y))+pattern NLetAnnF         :: SrcSpan -> [Binding r] -> r -> NExprLocF r+pattern NLetAnnF         ann x b    = AnnF ann (NLet x b) -pattern NUnary_ :: SrcSpan -> NUnaryOp -> r -> NExprLocF r-pattern NUnary_ ann op x = Compose (Ann ann (NUnary op x))+pattern NIfAnnF          :: SrcSpan -> r -> r -> r -> NExprLocF r+pattern NIfAnnF          ann c t e  = AnnF ann (NIf c t e) -pattern NBinary_ :: SrcSpan -> NBinaryOp -> r -> r -> NExprLocF r-pattern NBinary_ ann op x y = Compose (Ann ann (NBinary op x y))+pattern NWithAnnF        :: SrcSpan -> r -> r -> NExprLocF r+pattern NWithAnnF        ann x y    = AnnF ann (NWith x y)++pattern NAssertAnnF      :: SrcSpan -> r -> r -> NExprLocF r+pattern NAssertAnnF      ann x y    = AnnF ann (NAssert x y)++pattern NSynHoleAnnF     :: SrcSpan -> VarName -> NExprLocF r+pattern NSynHoleAnnF     ann x      = AnnF ann (NSynHole x)+{-# complete NConstantAnnF, NStrAnnF, NSymAnnF, NListAnnF, NSetAnnF, NLiteralPathAnnF, NEnvPathAnnF, NUnaryAnnF, NBinaryAnnF, NSelectAnnF, NHasAttrAnnF, NAbsAnnF, NLetAnnF, NIfAnnF, NWithAnnF, NAssertAnnF, NSynHoleAnnF #-}+++-- *** Patterns to match on 'NExprLoc' constructions (for 'SrcSpan'-based annotations).++pattern NConstantAnn    :: SrcSpan -> NAtom -> NExprLoc+pattern NConstantAnn    ann x      = Ann ann (NConstant x)++pattern NStrAnn         :: SrcSpan -> NString NExprLoc -> NExprLoc+pattern NStrAnn         ann x      = Ann ann (NStr x)++pattern NSymAnn         :: SrcSpan -> VarName -> NExprLoc+pattern NSymAnn         ann x      = Ann ann (NSym x)++pattern NListAnn        :: SrcSpan -> [NExprLoc] -> NExprLoc+pattern NListAnn        ann x      = Ann ann (NList x)++pattern NSetAnn         :: SrcSpan -> Recursivity -> [Binding NExprLoc] -> NExprLoc+pattern NSetAnn         ann rec x  = Ann ann (NSet rec x)++pattern NLiteralPathAnn :: SrcSpan -> Path -> NExprLoc+pattern NLiteralPathAnn ann x      = Ann ann (NLiteralPath x)++pattern NEnvPathAnn     :: SrcSpan -> Path -> NExprLoc+pattern NEnvPathAnn     ann x      = Ann ann (NEnvPath x)++pattern NUnaryAnn       :: SrcSpan -> NUnaryOp -> NExprLoc -> NExprLoc+pattern NUnaryAnn       ann op x   = Ann ann (NUnary op x)++pattern NAppAnn         :: SrcSpan -> NExprLoc -> NExprLoc -> NExprLoc+pattern NAppAnn         ann x y    = Ann ann (NApp x y)++pattern NBinaryAnn      :: SrcSpan -> NBinaryOp -> NExprLoc -> NExprLoc -> NExprLoc+pattern NBinaryAnn      ann op x y = Ann ann (NBinary op x y)++pattern NSelectAnn      :: SrcSpan ->  Maybe NExprLoc -> NExprLoc -> NAttrPath NExprLoc -> NExprLoc+pattern NSelectAnn      ann v x p  = Ann ann (NSelect v x p)++pattern NHasAttrAnn     :: SrcSpan -> NExprLoc -> NAttrPath NExprLoc -> NExprLoc+pattern NHasAttrAnn     ann x p    = Ann ann (NHasAttr x p)++pattern NAbsAnn         :: SrcSpan -> Params NExprLoc -> NExprLoc -> NExprLoc+pattern NAbsAnn         ann x b    = Ann ann (NAbs x b)++pattern NLetAnn         :: SrcSpan -> [Binding NExprLoc] -> NExprLoc -> NExprLoc+pattern NLetAnn         ann x b    = Ann ann (NLet x b)++pattern NIfAnn          :: SrcSpan -> NExprLoc -> NExprLoc -> NExprLoc -> NExprLoc+pattern NIfAnn          ann c t e  = Ann ann (NIf c t e)++pattern NWithAnn        :: SrcSpan -> NExprLoc -> NExprLoc -> NExprLoc+pattern NWithAnn        ann x y    = Ann ann (NWith x y)++pattern NAssertAnn      :: SrcSpan -> NExprLoc -> NExprLoc -> NExprLoc+pattern NAssertAnn      ann x y    = Ann ann (NAssert x y)++pattern NSynHoleAnn     :: SrcSpan -> VarName -> NExprLoc+pattern NSynHoleAnn     ann x      = Ann ann (NSynHole x)+{-# complete NConstantAnn, NStrAnn, NSymAnn, NListAnn, NSetAnn, NLiteralPathAnn, NEnvPathAnn, NUnaryAnn, NBinaryAnn, NSelectAnn, NHasAttrAnn, NAbsAnn, NLetAnn, NIfAnn, NWithAnn, NAssertAnn, NSynHoleAnn #-}
src/Nix/Frames.hs view
@@ -1,46 +1,58 @@-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE ScopedTypeVariables #-}+{-# language ConstraintKinds #-}+{-# language ExistentialQuantification #-} -module Nix.Frames (NixLevel(..), Frames, Framed, NixFrame(..),-                   NixException(..), withFrame, throwError,-                   module Data.Typeable,-                   module Control.Exception) where+-- | Definitions of Frames. Frames are messages that gather and ship themself with a context related to the message. For example - the message about some exception would also gather, keep and bring with it the tracing information.+module Nix.Frames+  ( NixLevel(..)+  , Frames+  , askFrames+  , Framed+  , NixFrame(..)+  , NixException(..)+  , withFrame+  , throwError+  , module Data.Typeable+  )+where -import Control.Exception hiding (catch, evaluate)-import Control.Monad.Catch-import Control.Monad.Reader-import Data.Typeable hiding (typeOf)-import Nix.Utils+import           Nix.Prelude+import           Data.Typeable           hiding ( typeOf )+import           Control.Monad.Catch            ( MonadThrow(..) )+import qualified Text.Show  data NixLevel = Fatal | Error | Warning | Info | Debug-    deriving (Ord, Eq, Bounded, Enum, Show)+  deriving (Ord, Eq, Bounded, Enum, Show) -data NixFrame = NixFrame+data NixFrame =+  NixFrame     { frameLevel :: NixLevel     , frame      :: SomeException     }  instance Show NixFrame where-    show (NixFrame level f) =-        "Nix frame at level " ++ show level ++ ": "++ show f+  show (NixFrame level f) =+    "Nix frame at level " <> show level <> ": " <> show f  type Frames = [NixFrame] +askFrames :: forall e m . (MonadReader e m, Has e Frames) => m Frames+askFrames = askLocal+ type Framed e m = (MonadReader e m, Has e Frames, MonadThrow m)  newtype NixException = NixException Frames-    deriving Show+  deriving Show  instance Exception NixException -withFrame :: forall s e m a. (Framed e m, Exception s) => NixLevel -> s -> m a -> m a-withFrame level f = local (over hasLens (NixFrame level (toException f) :))+withFrame+  :: forall s e m a . (Framed e m, Exception s) => NixLevel -> s -> m a -> m a+withFrame level f = local $ over hasLens (NixFrame level (toException f) :) -throwError :: forall s e m a. (Framed e m, Exception s, MonadThrow m) => s -> m a-throwError err = do-    context <- asks (view hasLens)-    traceM "Throwing error..."-    throwM $ NixException (NixFrame Error (toException err):context)+throwError+  :: forall s e m a . (Framed e m, Exception s, MonadThrow m) => s -> m a+throwError err =+  do+    context <- askLocal+    traceM "Throwing fail..."+    throwM $ NixException $ NixFrame Error (toException err) : context
+ src/Nix/Fresh.hs view
@@ -0,0 +1,63 @@+{-# language CPP #-}+{-# language GeneralizedNewtypeDeriving #-}+{-# language TypeFamilies #-}+{-# language UndecidableInstances #-}++{-# options_ghc -Wno-orphans #-}+++module Nix.Fresh where++import           Nix.Prelude+import           Control.Monad.Base   ( MonadBase(..) )+import           Control.Monad.Catch  ( MonadCatch+                                      , MonadMask+                                      , MonadThrow+                                      )+import           Control.Monad.Fix    ( MonadFix )+import           Control.Monad.Ref    ( MonadAtomicRef(..)+                                      , MonadRef(Ref)+                                      )++import           Nix.Thunk++newtype FreshIdT i m a = FreshIdT (ReaderT (Ref m i) m a)+  deriving+    ( Functor+    , Applicative+    , Alternative+    , Monad+    , MonadFail+    , MonadPlus+    , MonadFix+    , MonadRef+    , MonadAtomicRef+    , MonadIO+    , MonadCatch+    , MonadThrow+    , MonadMask+    )++instance MonadTrans (FreshIdT i) where+  lift = FreshIdT . lift++instance MonadBase b m => MonadBase b (FreshIdT i m) where+  liftBase = FreshIdT . liftBase++instance+  ( MonadAtomicRef m+  , Eq i+  , Ord i+  , Show i+  , Enum i+  , Typeable i+  )+  => MonadThunkId (FreshIdT i m)+ where+  type ThunkId (FreshIdT i m) = i+  freshId = FreshIdT $ do+    v <- ask+    atomicModifyRef v (\i -> (succ i, i))++runFreshIdT :: Functor m => FreshIdT i m a -> Ref m i -> m a+runFreshIdT = runReaderT . coerce
+ src/Nix/Fresh/Basic.hs view
@@ -0,0 +1,64 @@+{-# language CPP #-}++{-# options_ghc -Wno-orphans #-}+++module Nix.Fresh.Basic where++#if !MIN_VERSION_base(4,13,0)+import           Control.Monad.Fail ( MonadFail )+#endif+import           Nix.Prelude+import           Nix.Effects+import           Nix.Render+import           Nix.Fresh+import           Nix.Value++type StdIdT = FreshIdT Int++-- NOTE: These would be removed by: https://github.com/haskell-nix/hnix/pull/804+instance (MonadFail m, MonadFile m) => MonadFile (StdIdT m)+instance MonadIntrospect m => MonadIntrospect (StdIdT m)+instance MonadStore m => MonadStore (StdIdT m)+instance MonadPutStr m => MonadPutStr (StdIdT m)+instance MonadHttp m => MonadHttp (StdIdT m)+instance MonadEnv m => MonadEnv (StdIdT m)+instance MonadPaths m => MonadPaths (StdIdT m)+instance MonadInstantiate m => MonadInstantiate (StdIdT m)+instance MonadExec m => MonadExec (StdIdT m)++instance (MonadEffects t f m, MonadDataContext f m)+  => MonadEffects t f (StdIdT m) where++  toAbsolutePath :: Path -> StdIdT m Path+  toAbsolutePath = lift . toAbsolutePath @t @f @m++  findEnvPath :: String -> StdIdT m Path+  findEnvPath      = lift . findEnvPath @t @f @m++  findPath :: [NValue t f (StdIdT m)] -> Path -> StdIdT m Path+  findPath vs path =+    do+      i <- FreshIdT ask+      lift $ findPath @t @f @m (unliftNValue (`runFreshIdT` i) <$> vs) path++  importPath :: Path -> StdIdT m (NValue t f (StdIdT m))+  importPath path =+    do+      i <- FreshIdT ask+      lift $ liftNValue (`runFreshIdT` i) <$> (importPath @t @f @m $ path)++  pathToDefaultNix :: Path -> StdIdT m Path+  pathToDefaultNix = lift . pathToDefaultNix @t @f @m++  derivationStrict :: NValue t f (StdIdT m) -> StdIdT m (NValue t f (StdIdT m))+  derivationStrict v =+    do+      i <- FreshIdT ask+      let+        fresh :: FreshIdT Int m a -> m a+        fresh = (`runFreshIdT` i)+      lift $ liftNValue fresh <$> (derivationStrict @t @f @m . unliftNValue fresh $ v)++  traceEffect :: String -> StdIdT m ()+  traceEffect = lift . traceEffect @t @f @m
+ src/Nix/Json.hs view
@@ -0,0 +1,82 @@+{-# language CPP #-}++module Nix.Json where++import           Nix.Prelude+import qualified Data.Aeson                    as A+import qualified Data.Aeson.Encoding           as A+import qualified Data.Vector                   as V+import qualified Data.HashMap.Strict           as HM+#if MIN_VERSION_aeson(2,0,0)+import qualified Data.Aeson.Key                as AKM+import qualified Data.Aeson.KeyMap             as AKM+#endif+import           Nix.Atoms+import           Nix.Effects+import           Nix.Exec+import           Nix.Frames+import           Nix.String+import           Nix.Value+import           Nix.Value.Monad+import           Nix.Expr.Types++-- This was moved from Utils.+toEncodingSorted :: A.Value -> A.Encoding+toEncodingSorted = \case+  A.Object m ->+    A.pairs+      . foldMap+      (\(k, v) -> A.pair k $ toEncodingSorted v)+      . sortWith fst $+#if MIN_VERSION_aeson(2,0,0)+          AKM.toList+#else+          HM.toList+#endif+            m+  A.Array l -> A.list toEncodingSorted $ V.toList l+  v         -> A.toEncoding v++toJSONNixString :: MonadNix e t f m => NValue t f m -> m NixString+toJSONNixString =+  runWithStringContextT .+    fmap+      ( decodeUtf8+      -- This is completely not optimal, but seems we do not have better encoding analog (except for @unsafe*@), Aeson gatekeeps through this.+      . A.encodingToLazyByteString+      . toEncodingSorted+      )++      . toJSON++toJSON :: MonadNix e t f m => NValue t f m -> WithStringContextT m A.Value+toJSON = \case+  NVConstant (NInt   n) -> pure $ A.toJSON n+  NVConstant (NFloat n) -> pure $ A.toJSON n+  NVConstant (NBool  b) -> pure $ A.toJSON b+  NVConstant NNull      -> pure   A.Null+  NVStr      ns         -> A.toJSON <$> extractNixString ns+  NVList l -> A.Array . V.fromList <$> traverse intoJson l+  NVSet _ m ->+    maybe+      (A.Object <$> traverse intoJson kmap)+      intoJson+      (lkup "outPath" kmap)+   where+#if MIN_VERSION_aeson(2,0,0)+    lkup = AKM.lookup+    kmap = AKM.fromHashMap $ HM.mapKeys (AKM.fromText . coerce) m+#else+    lkup = HM.lookup+    kmap = HM.mapKeys (coerce @VarName @Text) m+#endif+  NVPath p ->+    do+      fp <- lift $ coerce <$> addPath p+      addSingletonStringContext $ StringContext DirectPath $ fromString fp+      pure $ A.toJSON fp+  v -> lift $ throwError $ CoercionToJson v++ where+  intoJson :: MonadNix e t f m => NValue t f m -> WithStringContextT m A.Value+  intoJson nv = join $ lift $ toJSON <$> demand nv
src/Nix/Lint.hs view
@@ -1,54 +1,45 @@-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE DeriveFoldable #-}-{-# LANGUAGE DeriveTraversable #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE MultiWayIf #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}+{-# language ConstraintKinds #-}+{-# language CPP #-}+{-# language DataKinds #-}+{-# language GeneralizedNewtypeDeriving #-}+{-# language TypeFamilies #-}+{-# language UndecidableInstances #-} -{-# OPTIONS_GHC -fno-warn-name-shadowing #-}-{-# OPTIONS_GHC -Wno-missing-methods #-}+{-# options_ghc -fno-warn-name-shadowing #-}+{-# options_ghc -Wno-missing-methods #-}  module Nix.Lint where -import           Control.Exception-import           Control.Monad+import           Nix.Prelude+import           Relude.Unsafe                 as Unsafe ( head )+import           Control.Exception              ( throw )+import           GHC.Exception                  ( ErrorCall(ErrorCall) )+import           Control.Monad                  ( foldM ) import           Control.Monad.Catch import           Control.Monad.Fix-import           Control.Monad.Reader (MonadReader)+import           Control.Monad.Ref import           Control.Monad.ST-import           Control.Monad.Trans.Reader-import           Data.Coerce-import           Data.HashMap.Lazy (HashMap)-import qualified Data.HashMap.Lazy as M-import           Data.List-import qualified Data.List.NonEmpty as NE-import           Data.STRef-import           Data.Text (Text)-import qualified Data.Text as Text+import qualified Data.HashMap.Lazy             as M+-- Plese, use NonEmpty+import           Data.List                      ( intersect )+import qualified Data.List.NonEmpty            as NE+import qualified Data.Text                     as Text+import qualified Text.Show import           Nix.Atoms import           Nix.Context import           Nix.Convert-import           Nix.Eval (MonadEval(..))-import qualified Nix.Eval as Eval-import           Nix.Expr+import           Nix.Eval                       ( MonadEval(..) )+import qualified Nix.Eval                      as Eval+import           Nix.Expr.Types+import           Nix.Expr.Types.Annotated import           Nix.Frames+import           Nix.Fresh+import           Nix.String import           Nix.Options import           Nix.Scope import           Nix.Thunk-import           Nix.Utils+import           Nix.Thunk.Basic+import           Nix.Value.Monad  data TAtom   = TInt@@ -57,143 +48,205 @@   | TNull   deriving (Show, Eq, Ord) -data NTypeF (m :: * -> *) r-    = TConstant [TAtom]-    | TStr-    | TList r-    | TSet (Maybe (HashMap Text r))-    | TClosure (Params ())-    | TPath-    | TBuiltin String (SThunk m -> m (Symbolic m))-    deriving Functor+data NTypeF (m :: Type -> Type) r+  = TConstant [TAtom]+  | TStr+  | TList r+  | TSet (Maybe (AttrSet r))+  | TClosure (Params ())+  | TPath+  | TBuiltin Text (Symbolic m -> m r)+  deriving Functor  compareTypes :: NTypeF m r -> NTypeF m r -> Ordering-compareTypes (TConstant _)   (TConstant _)   = EQ-compareTypes (TConstant _)   _               = LT-compareTypes _               (TConstant _)   = GT-compareTypes TStr            TStr            = EQ-compareTypes TStr            _               = LT-compareTypes _               TStr            = GT-compareTypes (TList _)       (TList _)       = EQ-compareTypes (TList _)       _               = LT-compareTypes _               (TList _)       = GT-compareTypes (TSet _)        (TSet _)        = EQ-compareTypes (TSet _)        _               = LT-compareTypes _               (TSet _)        = GT-compareTypes TClosure {}     TClosure {}     = EQ-compareTypes TClosure {}     _               = LT-compareTypes _               TClosure {}     = GT-compareTypes TPath           TPath           = EQ-compareTypes TPath            _              = LT-compareTypes _               TPath           = GT-compareTypes (TBuiltin _ _)  (TBuiltin _ _)  = EQ+compareTypes (TConstant _)  (TConstant _)  = EQ+compareTypes (TConstant _)  _              = LT+compareTypes _              (TConstant _)  = GT+compareTypes TStr           TStr           = EQ+compareTypes TStr           _              = LT+compareTypes _              TStr           = GT+compareTypes (TList _)      (TList _)      = EQ+compareTypes (TList _)      _              = LT+compareTypes _              (TList _)      = GT+compareTypes (TSet _)       (TSet  _)      = EQ+compareTypes (TSet _)       _              = LT+compareTypes _              (TSet _)       = GT+compareTypes TClosure{}     TClosure{}     = EQ+compareTypes TClosure{}     _              = LT+compareTypes _              TClosure{}     = GT+compareTypes TPath          TPath          = EQ+compareTypes TPath          _              = LT+compareTypes _              TPath          = GT+compareTypes (TBuiltin _ _) (TBuiltin _ _) = EQ  data NSymbolicF r-    = NAny-    | NMany [r]-    deriving (Show, Eq, Ord, Functor, Foldable, Traversable)+  = NAny+  | NMany [r]+  deriving (Show, Eq, Ord, Functor, Foldable, Traversable) -newtype SThunk m = SThunk { getSThunk :: Thunk m (Symbolic m) }+type SThunk (m :: Type -> Type) = NThunkF m (Symbolic m) -newtype Symbolic m =-    Symbolic { getSymbolic :: Var m (NSymbolicF (NTypeF m (SThunk m))) }+type SValue (m :: Type -> Type) = Ref m (NSymbolicF (NTypeF m (Symbolic m))) +data Symbolic m = SV { getSV :: SValue m } | ST { getST :: SThunk m }+ instance Show (Symbolic m) where-    show _ = "<symbolic>"+  show _ = "<symbolic>" -everyPossible :: MonadVar m => m (Symbolic m)+everyPossible+  :: MonadAtomicRef m+  => m (Symbolic m) everyPossible = packSymbolic NAny -mkSymbolic :: MonadVar m => [NTypeF m (SThunk m)] -> m (Symbolic m)-mkSymbolic xs = packSymbolic (NMany xs)+mkSymbolic+  :: MonadAtomicRef m+  => [NTypeF m (Symbolic m)]+  -> m (Symbolic m)+mkSymbolic = packSymbolic . NMany -packSymbolic :: MonadVar m-             => NSymbolicF (NTypeF m (SThunk m)) -> m (Symbolic m)-packSymbolic = fmap coerce . newVar+mkSymbolic1+  :: MonadAtomicRef m+  => NTypeF m (Symbolic m)+  -> m (Symbolic m)+mkSymbolic1 = mkSymbolic . one -unpackSymbolic :: MonadVar m-               => Symbolic m -> m (NSymbolicF (NTypeF m (SThunk m)))-unpackSymbolic = readVar . coerce+packSymbolic+  :: MonadAtomicRef m+  => NSymbolicF (NTypeF m (Symbolic m))+  -> m (Symbolic m)+packSymbolic = fmap SV . newRef -type MonadLint e m = (Scoped e (SThunk m) m, Framed e m, MonadVar m)+unpackSymbolic+  :: (MonadAtomicRef m, MonadThunkId m, MonadCatch m)+  => Symbolic m+  -> m (NSymbolicF (NTypeF m (Symbolic m)))+unpackSymbolic = readRef . getSV <=< demand -symerr :: forall e m a. MonadLint e m => String -> m a-symerr = evalError @(Symbolic m) . ErrorCall+type MonadLint e m =+  ( Scoped (Symbolic m) m+  , Framed e m+  , MonadAtomicRef m+  , MonadCatch m+  , MonadThunkId m+  ) -renderSymbolic :: MonadLint e m => Symbolic m -> m String-renderSymbolic = unpackSymbolic >=> \case-    NAny -> return "<any>"-    NMany xs -> fmap (intercalate ", ") $ forM xs $ \case-        TConstant ys  -> fmap (intercalate ", ") $ forM ys $ \case-            TInt   -> return "int"-            TFloat -> return "float"-            TBool  -> return "bool"-            TNull  -> return "null"-        TStr            -> return "string"-        TList r         -> do-            x <- force r renderSymbolic-            return $ "[" ++ x ++ "]"-        TSet Nothing    -> return "<any set>"-        TSet (Just s)   -> do-            x <- traverse (`force` renderSymbolic) s-            return $ "{" ++ show x ++ "}"-        f@(TClosure p) -> do-            (args, sym) <- do-                f' <- mkSymbolic [f]-                lintApp (NAbs (void p) ()) f' everyPossible-            args' <- traverse renderSymbolic args-            sym'  <- renderSymbolic sym-            return $ "(" ++ show args' ++ " -> " ++ sym' ++ ")"-        TPath           -> return "path"-        TBuiltin _n _f    -> return "<builtin function>"+symerr :: forall e m a . MonadLint e m => Text -> m a+symerr = evalError @(Symbolic m) . ErrorCall . toString +renderSymbolic :: MonadLint e m => Symbolic m -> m Text+renderSymbolic =+  (\case+    NAny     -> pure "<any>"+    NMany xs ->+      Text.intercalate ", " <$>+        traverse+          (\case+            TConstant ys ->+              pure $+                Text.intercalate ", "+                  (fmap+                    (\case+                      TInt   -> "int"+                      TFloat -> "float"+                      TBool  -> "bool"+                      TNull  -> "null"+                    )+                    ys+                  )+            TStr    -> pure "string"+            TList r ->+              fmap brackets $ renderSymbolic =<< demand r+            TSet Nothing  -> pure "<any set>"+            TSet (Just s) ->+              braces . show <$> traverse (renderSymbolic <=< demand) s+            f@(TClosure p) ->+              do+                (args, sym) <-+                  do+                    f' <- mkSymbolic1 f+                    lintApp (NAbs p mempty) f' everyPossible+                args' <- traverse renderSymbolic args+                sym'  <- renderSymbolic sym+                pure $ parens $ show args' <> " -> " <> sym'+            TPath          -> pure "path"+            TBuiltin _n _f -> pure "<builtin function>"+          )+          xs+  ) <=< unpackSymbolic+ where+  between a b c = a <> b <> c+  parens   = between "(" ")"+  brackets = between "[" "]"+  braces   = between "{" "}"+ -- This function is order and uniqueness preserving (of types).-merge :: forall e m. MonadLint e m-      => NExprF () -> [NTypeF m (SThunk m)] -> [NTypeF m (SThunk m)]-      -> m [NTypeF m (SThunk m)]+merge+  :: forall e m+   . MonadLint e m+  => NExprF ()+  -> [NTypeF m (Symbolic m)]+  -> [NTypeF m (Symbolic m)]+  -> m [NTypeF m (Symbolic m)] merge context = go-  where-    go :: [NTypeF m (SThunk m)] -> [NTypeF m (SThunk m)]-       -> m [NTypeF m (SThunk m)]-    go [] _ = return []-    go _ [] = return []-    go (x:xs) (y:ys) = case (x, y) of-        (TStr,  TStr)  -> (TStr :)  <$> go xs ys-        (TPath, TPath) -> (TPath :) <$> go xs ys-        (TConstant ls, TConstant rs) ->-            (TConstant (ls `intersect` rs) :) <$> go xs ys-        (TList l, TList r) -> force l $ \l' -> force r $ \r' -> do-            m <- thunk $ unify context l' r'-            (TList m :) <$> go xs ys-        (TSet x, TSet Nothing) -> (TSet x :) <$> go xs ys-        (TSet Nothing, TSet x) -> (TSet x :) <$> go xs ys-        (TSet (Just l), TSet (Just r)) -> do-            m <- sequenceA $ M.intersectionWith-                (\i j -> i >>= \i' -> j >>= \j' ->-                        force i' $ \i'' -> force j' $ \j'' ->-                            thunk $ unify context i'' j'')-                (return <$> l) (return <$> r)-            if M.null m-                then go xs ys-                else (TSet (Just m) :) <$> go xs ys-        (TClosure {}, TClosure {}) ->-            throwError $ ErrorCall "Cannot unify functions"-        (TBuiltin _ _, TBuiltin _ _) ->-            throwError $ ErrorCall "Cannot unify builtin functions"-        _ | compareTypes x y == LT -> go xs (y:ys)-          | compareTypes x y == GT -> go (x:xs) ys-          | otherwise              -> error "impossible"+ where+  go+    :: [NTypeF m (Symbolic m)]+    -> [NTypeF m (Symbolic m)]+    -> m [NTypeF m (Symbolic m)]+  go []       _        = stub+  go _        []       = stub+  go xxs@(x : xs) yys@(y : ys) = case (x, y) of+    (TStr , TStr ) -> (one TStr <>) <$> rest+    (TPath, TPath) -> (one TPath <>) <$> rest+    (TConstant ls, TConstant rs) ->+      (one (TConstant (ls `intersect` rs)) <>) <$> rest+    (TList l, TList r) ->+      do+        l' <- demand l+        r' <- demand r+        m <- defer $ unify context l' r'+        (one (TList m) <>) <$> rest+    (TSet x       , TSet Nothing ) -> (one (TSet x) <>) <$> rest+    (TSet Nothing , TSet x       ) -> (one (TSet x) <>) <$> rest+    (TSet (Just l), TSet (Just r)) -> do+      hm <-+        sequenceA $+          M.intersectionWith+            (\ i j ->+              do+                i'' <- i+                j'' <- j+                defer $ unify context i'' j''+            )+            (fmap demand l)+            (fmap demand r)+      handlePresence+        id+        (const ((one (TSet $ pure hm) <>) <$>))+        hm+        rest +    (TClosure{}, TClosure{}) ->+      throwError $ ErrorCall "Cannot unify functions"+    (TBuiltin _ _, TBuiltin _ _) ->+      throwError $ ErrorCall "Cannot unify builtin functions"+    _ | compareTypes x y == LT -> go xs yys+      | compareTypes x y == GT -> go xxs ys+      | otherwise              -> error "impossible"+   where+    rest :: m [NTypeF m (Symbolic m)]+    rest = go xs ys+ {-     mergeFunctions pl nl fl pr fr xs ys = do         m <- sequenceA $ M.intersectionWith             (\i j -> i >>= \i' -> j >>= \j' -> case (i', j') of-                    (Nothing, Nothing) -> return $ Just Nothing-                    (_, Nothing) -> return Nothing-                    (Nothing, _) -> return Nothing+                    (Nothing, Nothing) -> stub+                    (_, Nothing) -> stub+                    (Nothing, _) -> stub                     (Just i'', Just j'') ->-                        Just . Just <$> unify context i'' j'')-            (return <$> pl) (return <$> pr)+                        pure . pure <$> unify context i'' j'')+            (pure <$> pl) (pure <$> pr)         let Just m' = sequenceA $ M.filter isJust m         if M.null m'             then go xs ys@@ -203,216 +256,281 @@                     <$> go xs ys -} --- | unify raises an error if the result is would be 'NMany []'.-unify :: forall e m. MonadLint e m-      => NExprF () -> Symbolic m -> Symbolic m -> m (Symbolic m)-unify context (Symbolic x) (Symbolic y) = do-    x' <- readVar x-    y' <- readVar y-    case (x', y') of-        (NAny, _) -> do-            writeVar x y'-            return $ Symbolic y-        (_, NAny) -> do-            writeVar y x'-            return $ Symbolic x-        (NMany xs, NMany ys) -> do-            m <- merge context xs ys-            if null m-                then do-                    -- x' <- renderSymbolic (Symbolic x)-                    -- y' <- renderSymbolic (Symbolic y)-                    throwError $ ErrorCall "Cannot unify "-                        -- ++ show x' ++ " with " ++ show y'-                        --  ++ " in context: " ++ show context-                else do-                    writeVar x (NMany m)-                    writeVar y (NMany m)-                    packSymbolic (NMany m)+-- | Result @== NMany []@ -> @unify@ fails.+unify+  :: forall e m a+   . MonadLint e m+  => NExprF a+  -> Symbolic m+  -> Symbolic m+  -> m (Symbolic m)+unify (void -> context) (SV x) (SV y) = do+  x' <- readRef x+  y' <- readRef y+  case (x', y') of+    (NAny, _) ->+      do+        writeRef x y'+        pure $ SV y+    (_, NAny) ->+      do+        writeRef y x'+        pure $ SV x+    (NMany xs, NMany ys) ->+      handlePresence+        (+          -- x' <- renderSymbolic (Symbolic x)+          -- y' <- renderSymbolic (Symbolic y)+          throwError $ ErrorCall "Cannot unify "+                  -- <> show x' <> " with " <> show y'+                  --  <> " in context: " <> show context+        )+        (\ m ->+          do+            let+              nm = NMany m+            writeRef x   nm+            writeRef y   nm+            packSymbolic nm+        )+        =<< merge context xs ys+unify _ _ _ = error "The unexpected hath transpired!"  -- These aren't worth defining yet, because once we move to Hindley-Milner, -- we're not going to be managing Symbolic values this way anymore.  instance ToValue Bool m (Symbolic m) where -instance ToValue [SThunk m] m (Symbolic m) where+instance ToValue [Symbolic m] m (Symbolic m) where -instance FromValue (Text, DList Text) m (Symbolic m) where+instance FromValue NixString m (Symbolic m) where -instance FromValue (AttrSet (SThunk m), AttrSet SourcePos) m (Symbolic m) where+instance FromValue (AttrSet (Symbolic m), PositionSet) m (Symbolic m) where -instance ToValue (AttrSet (SThunk m), AttrSet SourcePos) m (Symbolic m) where+instance ToValue (AttrSet (Symbolic m), PositionSet) m (Symbolic m) where -instance MonadLint e m => MonadThunk (Symbolic m) (SThunk m) m where-    thunk = fmap coerce . buildThunk-    force = forceThunk . coerce-    value = coerce . valueRef+instance (MonadThunkId m, MonadAtomicRef m, MonadCatch m)+  => MonadValue (Symbolic m) m where +  defer :: m (Symbolic m) -> m (Symbolic m)+  defer = fmap ST . thunk++  demand :: Symbolic m -> m (Symbolic m)+  demand (ST v) = demand =<< force v+  demand (SV v) = pure (SV v)+++instance (MonadThunkId m, MonadAtomicRef m, MonadCatch m)+  => MonadValueF (Symbolic m) m where++  demandF :: (Symbolic m -> m r) -> Symbolic m -> m r+  demandF f (ST v) = demandF f =<< force v+  demandF f (SV v) = f (SV v)++ instance MonadLint e m => MonadEval (Symbolic m) m where-    freeVariable var = symerr $-        "Undefined variable '" ++ Text.unpack var ++ "'"+  freeVariable var = symerr $ "Undefined variable '" <> coerce var <> "'" -    attrMissing ks Nothing =-        evalError @(Symbolic m) $ ErrorCall $-            "Inheriting unknown attribute: "-                ++ intercalate "." (map Text.unpack (NE.toList ks))+  attrMissing ks ms =+    evalError @(Symbolic m) . ErrorCall . toString $+      maybe+        ("Inheriting unknown attribute: " <> attr)+        (\ s ->  "Could not look up attribute " <> attr <> " in " <> show s)+        ms+   where+    attr = Text.intercalate "." $ NE.toList $ coerce ks -    attrMissing ks (Just s) =-        evalError @(Symbolic m) $ ErrorCall $ "Could not look up attribute "-            ++ intercalate "." (map Text.unpack (NE.toList ks))-            ++ " in " ++ show s+  evalCurPos =+    do+      f <- mkSymbolic1 TPath+      l <- mkSymbolic1 $ TConstant $ one TInt+      c <- mkSymbolic1 $ TConstant $ one TInt+      mkSymbolic1 $ TSet . pure $ M.fromList [("file", f), ("line", l), ("col", c)] -    evalCurPos = do-        f <- value <$> mkSymbolic [TPath]-        l <- value <$> mkSymbolic [TConstant [TInt]]-        c <- value <$> mkSymbolic [TConstant [TInt]]-        mkSymbolic [TSet (Just (M.fromList (go f l c)))]-      where-        go f l c =-            [ (Text.pack "file", f)-            , (Text.pack "line", l)-            , (Text.pack "col",  c) ]+  evalConstant c = mkSymbolic1 $ fun c+   where+    fun =+      \case+        NURI   _ -> TStr+        NInt   _ -> TConstant $ one TInt+        NFloat _ -> TConstant $ one TFloat+        NBool  _ -> TConstant $ one TBool+        NNull    -> TConstant $ one TNull -    evalConstant c  = mkSymbolic [TConstant [go c]]-      where-        go = \case-          NInt _   -> TInt-          NFloat _ -> TFloat-          NBool _  -> TBool-          NNull    -> TNull+  evalString      = const $ mkSymbolic1 TStr+  evalLiteralPath = const $ mkSymbolic1 TPath+  evalEnvPath     = const $ mkSymbolic1 TPath -    evalString      = const $ mkSymbolic [TStr]-    evalLiteralPath = const $ mkSymbolic [TPath]-    evalEnvPath     = const $ mkSymbolic [TPath]+  evalUnary op arg =+    unify (NUnary op arg) arg =<< mkSymbolic1 (TConstant [TInt, TBool]) -    evalUnary op arg =-        unify (void (NUnary op arg)) arg-            =<< mkSymbolic [TConstant [TInt, TBool]]+  evalBinary = lintBinaryOp -    evalBinary = lintBinaryOp+  -- 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.+  evalWith scope body =+    do+      s <- unpackSymbolic =<< demand =<< defer scope -    evalWith scope 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.-        s <- thunk scope-        pushWeakScope ?? body $ force s $ unpackSymbolic >=> \case-            NMany [TSet (Just s')] -> return s'-            NMany [TSet Nothing] -> error "NYI: with unknown"-            _ -> throwError $ ErrorCall "scope must be a set in with statement"+      pushWeakScope+        (case s of+          NMany [TSet (Just (coerce -> scope))] -> pure scope+          NMany [TSet Nothing] -> error "NYI: with unknown"+          _ -> throwError $ ErrorCall "scope must be a set in with statement"+        )+        body -    evalIf cond t f = do-        t' <- t-        f' <- f-        let e = NIf cond t' f'-        _ <- unify (void e) cond =<< mkSymbolic [TConstant [TBool]]-        unify (void e) t' f'+  evalIf cond t f =+    do+      t' <- t+      f' <- f+      let e = unify (NIf cond t' f')+      e t' f' <* (e cond =<< mkSymbolic1 (TConstant $ one TBool)) -    evalAssert cond body = do-        body' <- body-        let e = NAssert cond body'-        _ <- unify (void e) cond =<< mkSymbolic [TConstant [TBool]]-        pure body'+  evalAssert cond body =+    do+      body' <- body+      body' <$ (unify (NAssert cond body') cond =<< mkSymbolic1 (TConstant $ one TBool)) -    evalApp = (fmap snd .) . lintApp (NBinary NApp () ())-    evalAbs params _ = mkSymbolic [TClosure (void params)]+  evalApp = (fmap snd .) . lintApp (join NApp mempty)+  evalAbs params _ = mkSymbolic1 (TClosure $ void params) -    evalError = throwError+  evalError = throwError  lintBinaryOp-    :: forall e m. (MonadLint e m, MonadEval (Symbolic m) m)-    => NBinaryOp -> Symbolic m -> m (Symbolic m) -> m (Symbolic m)-lintBinaryOp op lsym rarg = do+  :: forall e m+   . (MonadLint e m, MonadEval (Symbolic m) m)+  => NBinaryOp+  -> Symbolic m+  -> m (Symbolic m)+  -> m (Symbolic m)+lintBinaryOp op lsym rarg =+  do     rsym <- rarg-    y <- thunk everyPossible-    case op of-        NApp   -> symerr "lintBinaryOp:NApp: should never get here"-        NEq    -> check lsym rsym [ TConstant [TInt, TBool, TNull]-                                 , TStr-                                 , TList y ]-        NNEq   -> check lsym rsym [ TConstant [TInt, TBool, TNull]-                                 , TStr-                                 , TList y ]+    y    <- defer everyPossible -        NLt    -> check lsym rsym [ TConstant [TInt, TBool, TNull] ]-        NLte   -> check lsym rsym [ TConstant [TInt, TBool, TNull] ]-        NGt    -> check lsym rsym [ TConstant [TInt, TBool, TNull] ]-        NGte   -> check lsym rsym [ TConstant [TInt, TBool, TNull] ]+    check lsym rsym $+      case op of+        NEq     -> [TConstant [TInt, TBool, TNull], TStr, TList y]+        NNEq    -> [TConstant [TInt, TBool, TNull], TStr, TList y] -        NAnd   -> check lsym rsym [ TConstant [TBool] ]-        NOr    -> check lsym rsym [ TConstant [TBool] ]-        NImpl  -> check lsym rsym [ TConstant [TBool] ]+        NLt     -> one $ TConstant [TInt, TBool, TNull]+        NLte    -> one $ TConstant [TInt, TBool, TNull]+        NGt     -> one $ TConstant [TInt, TBool, TNull]+        NGte    -> one $ TConstant [TInt, TBool, TNull] +        NAnd    -> one $ TConstant $ one TBool+        NOr     -> one $ TConstant $ one TBool+        NImpl   -> one $ TConstant $ one TBool+         -- jww (2018-04-01): NYI: Allow Path + Str-        NPlus  -> check lsym rsym [ TConstant [TInt], TStr, TPath ]-        NMinus -> check lsym rsym [ TConstant [TInt] ]-        NMult  -> check lsym rsym [ TConstant [TInt] ]-        NDiv   -> check lsym rsym [ TConstant [TInt] ]+        NPlus   -> [TConstant $ one TInt, TStr, TPath]+        NMinus  -> one $ TConstant $ one TInt+        NMult   -> one $ TConstant $ one TInt+        NDiv    -> one $ TConstant $ one TInt -        NUpdate -> check lsym rsym [ TSet Nothing ]+        NUpdate -> one $ TSet mempty -        NConcat -> check lsym rsym [ TList y ]-  where-    check lsym rsym xs = do-        let e = NBinary op lsym rsym-        m <- mkSymbolic xs-        _ <- unify (void e) lsym m-        _ <- unify (void e) rsym m-        unify (void e) lsym rsym+        NConcat -> one $ TList y+#if __GLASGOW_HASKELL__ < 810+        _ -> fail "Should not be possible"  -- symerr or this fun signature should be changed to work in type scope+#endif -infixl 1 `lintApp`-lintApp :: forall e m. MonadLint e m-        => NExprF () -> Symbolic m -> m (Symbolic m)-        -> m (HashMap VarName (Symbolic m), Symbolic m)-lintApp context fun arg = unpackSymbolic fun >>= \case-    NAny -> throwError $ ErrorCall-        "Cannot apply something not known to be a function"-    NMany xs -> do-        (args:_, ys) <- fmap unzip $ forM xs $ \case-            TClosure _params -> arg >>= unpackSymbolic >>= \case-                NAny -> do-                    error "NYI" -                NMany [TSet (Just _)] -> do-                    error "NYI" -                NMany _ -> throwError $ ErrorCall "NYI: lintApp NMany not set"-            TBuiltin _ _f -> throwError $ ErrorCall "NYI: lintApp builtin"-            TSet _m -> throwError $ ErrorCall "NYI: lintApp Set"-            _x -> throwError $ ErrorCall "Attempt to call non-function"+ where+  check lsym rsym xs =+    do+      let+        contextUnify = unify $ NBinary op lsym rsym -        y <- everyPossible-        (args,) <$> foldM (unify context) y ys+      m <- mkSymbolic xs+      _ <- contextUnify lsym m+      _ <- contextUnify rsym m+      contextUnify lsym rsym -newtype Lint s a = Lint-    { runLint :: ReaderT (Context (Lint s) (SThunk (Lint s))) (ST s) a }-    deriving (Functor, Applicative, Monad, MonadFix,-              MonadReader (Context (Lint s) (SThunk (Lint s))))+infixl 1 `lintApp`+lintApp+  :: forall e m+   . MonadLint e m+  => NExprF ()+  -> Symbolic m+  -> m (Symbolic m)+  -> m (HashMap VarName (Symbolic m), Symbolic m)+lintApp context fun arg =+  (\case+    NAny ->+      throwError $ ErrorCall "Cannot apply something not known to be a function"+    NMany xs ->+      do+        (args, ys) <-+          unzip <$>+            traverse+              (\case+                TClosure _params ->+                  (\case+                    NAny                  -> error "NYI"+                    NMany [TSet (Just _)] -> error "NYI"+                    NMany _               -> throwError $ ErrorCall "NYI: lintApp NMany not set"+                  ) =<< unpackSymbolic =<< arg+                TBuiltin _ _f -> throwError $ ErrorCall "NYI: lintApp builtin"+                TSet _m       -> throwError $ ErrorCall "NYI: lintApp Set"+                _x            -> throwError $ ErrorCall "Attempt to call non-function"+              )+              xs -instance MonadVar (Lint s) where-    type Var (Lint s) = STRef s+        y <- everyPossible+        (Unsafe.head args, ) <$> foldM (unify context) y ys+  ) =<< unpackSymbolic fun -    newVar x     = Lint $ ReaderT $ \_ -> newSTRef x-    readVar x    = Lint $ ReaderT $ \_ -> readSTRef x-    writeVar x y = Lint $ ReaderT $ \_ -> writeSTRef x y-    atomicModifyVar x f = Lint $ ReaderT $ \_ -> do-        res <- snd . f <$> readSTRef x-        _ <- modifySTRef x (fst . f)-        return res+newtype Lint s a = Lint+  { runLint :: ReaderT (Context (Lint s) (Symbolic (Lint s))) (FreshIdT Int (ST s)) a }+  deriving+    ( Functor+    , Applicative+    , Monad+    , MonadFix+    , MonadReader (Context (Lint s) (Symbolic (Lint s)))+    , MonadThunkId+    , MonadRef+    , MonadAtomicRef+    )  instance MonadThrow (Lint s) where-    throwM e = Lint $ ReaderT $ \_ -> throw e+  throwM :: forall e a . Exception e => e -> Lint s a+  throwM e = Lint $ ReaderT $ const (throw e) +instance MonadCatch (Lint s) where+  catch _m _h = Lint $ ReaderT $ const (error "Cannot catch in 'Lint s'")+ runLintM :: Options -> Lint s a -> ST s a-runLintM opts = flip runReaderT (newContext opts) . runLint+runLintM opts action =+  runFreshIdT ((`runReaderT` newContext opts) $ runLint action) =<< newRef (1 :: Int) -symbolicBaseEnv :: Monad m => m (Scopes m (SThunk m))-symbolicBaseEnv = return emptyScopes+symbolicBaseEnv+  :: Monad m+  => m (Scopes m (Symbolic m))+symbolicBaseEnv = stub  lint :: Options -> NExprLoc -> ST s (Symbolic (Lint s))-lint opts expr = runLintM opts $-    symbolicBaseEnv-        >>= (`pushScopes`-                adi (Eval.eval . annotated . getCompose)-                    Eval.addSourcePositions expr)+lint opts expr =+  runLintM opts $+    do+      basis <- symbolicBaseEnv++      pushScopes+        basis+        (adi+          Eval.addSourcePositions+          Eval.evalContent+          expr+        )++instance+  Scoped (Symbolic (Lint s)) (Lint s) where+  askScopes = askScopesReader+  clearScopes   = clearScopesReader @(Lint s) @(Symbolic (Lint s))+  pushScopes    = pushScopesReader+  lookupVar     = lookupVarReader
src/Nix/Normal.hs view
@@ -1,98 +1,204 @@-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}+{-# language AllowAmbiguousTypes #-}+{-# language ConstraintKinds #-}+{-# language DataKinds #-}+{-# language TypeFamilies #-}+{-# language RankNTypes #-} +-- | Code for normalization (reduction into a normal form) of Nix expressions.+-- Nix language allows recursion, so some expressions do not converge.+-- And so do not converge into a normal form. module Nix.Normal where -import           Control.Monad-import           Data.Fix-import qualified Data.HashMap.Lazy as M-import           Data.Text (Text)-import qualified Data.Text as Text-import           Nix.Atoms-import           Nix.Effects+import           Nix.Prelude+import           Control.Monad.Free        ( Free(..) )+import           Data.Set                  ( member+                                           , insert+                                           )+import           Nix.Cited import           Nix.Frames import           Nix.Thunk-import           Nix.Utils import           Nix.Value -newtype NormalLoop m = NormalLoop (NValue m)-    deriving Show+newtype NormalLoop t f m = NormalLoop (NValue t f m)+  deriving Show -instance Typeable m => Exception (NormalLoop m)+instance MonadDataErrorContext t f m => Exception (NormalLoop t f m) -normalFormBy-    :: forall e m. (Framed e m, MonadVar m, Typeable m)-    => (forall r. NThunk m -> (NValue m -> m r) -> m r)-    -> Int-    -> NValue m-    -> m (NValueNF m)-normalFormBy k n v = do-    when (n > 2000) $ throwError $ NormalLoop v-    case v of-        NVConstant a     -> return $ Fix $ NVConstantF a-        NVStr t s        -> return $ Fix $ NVStrF t s-        NVList l         ->-            fmap (Fix . NVListF) $ forM (zip [0..] l) $ \(i :: Int, t) -> do-                traceM $ replicate n ' ' ++ "normalFormBy: List[" ++ show i ++ "]"-                t `k` normalFormBy k (succ n)-        NVSet s p        ->-            fmap (Fix . flip NVSetF p) $ sequence $ flip M.mapWithKey s $ \ky t -> do-                traceM $ replicate n ' ' ++ "normalFormBy: Set{" ++ show ky ++ "}"-                t `k` normalFormBy k (succ n)-        NVClosure p f    -> return $ Fix $ NVClosureF p f-        NVPath fp        -> return $ Fix $ NVPathF fp-        NVBuiltin name f -> return $ Fix $ NVBuiltinF name f-        _ -> error "Pattern synonyms mask complete matches"+-- | Normalize the value as much as possible, leaving only detected cycles.+normalizeValue+  :: forall e t m f+   . ( Framed e m+     , MonadThunk t m (NValue t f m)+     , MonadDataErrorContext t f m+     , Ord (ThunkId m)+     )+  => NValue t f m+  -> m (NValue t f m)+normalizeValue v = run $ iterNValueM run go (fmap Free . sequenceNValue' run) v+ where+  start = 0 :: Int+  maxDepth = 2000+  table = mempty -normalForm :: (Framed e m, MonadVar m, Typeable m,-              MonadThunk (NValue m) (NThunk m) m)-           => NValue m -> m (NValueNF m)-normalForm = normalFormBy force 0+  run :: ReaderT Int (StateT (Set (ThunkId m)) m) r -> m r+  run = (`evalStateT` table) . (`runReaderT` start) -embed :: forall m. (MonadThunk (NValue m) (NThunk m) m)-      => NValueNF m -> m (NValue m)-embed (Fix x) = case x of-    NVConstantF a     -> return $ nvConstant a-    NVStrF t s        -> return $ nvStr t s-    NVListF l         -> nvList . fmap (value @_ @_ @m)-        <$> traverse embed l-    NVSetF s p        -> flip nvSet p . fmap (value @_ @_ @m)-        <$> traverse embed s-    NVClosureF p f    -> return $ nvClosure p f-    NVPathF fp        -> return $ nvPath fp-    NVBuiltinF name f -> return $ nvBuiltin name f+  go+    :: (  NValue t f m+       -> ReaderT Int (StateT (Set (ThunkId m)) m) (NValue t f m)+       )+    -> t+    -> ReaderT Int (StateT (Set (ThunkId m)) m) (NValue t f m)+  go k tnk  =+    bool+      (do+        i <- ask+        when (i > maxDepth) $ fail $ "Exceeded maximum normalization depth of " <> show maxDepth <> " levels."+        (lifted . lifted)+          (=<< force tnk)+          (local (+1) . k)+      )+      (pure $ pure tnk)+      =<< seen tnk+   where+    seen :: t -> ReaderT Int (StateT (Set (ThunkId m)) m) Bool+    seen t =+      do+        let tnkid = thunkId t+        lift $+          do+            thunkWasVisited <- gets $ member tnkid+            when (not thunkWasVisited) $ modify $ insert tnkid+            pure thunkWasVisited -valueText :: forall e m. (Framed e m, MonadEffects m, Typeable m)-          => Bool -> NValueNF m -> m (Text, DList Text)-valueText addPathsToStore = cata phi-  where-    phi :: NValueF m (m (Text, DList Text)) -> m (Text, DList Text)-    phi (NVConstantF a) = pure (atomText a, mempty)-    phi (NVStrF t c)    = pure (t, c)-    phi v@(NVListF _)   = coercionFailed v-    phi v@(NVSetF s _)-      | Just asString <- M.lookup "__asString" s = asString-      | otherwise = coercionFailed v-    phi v@NVClosureF {} = coercionFailed v-    phi (NVPathF originalPath)-        | addPathsToStore = do-            storePath <- addPath originalPath-            pure (Text.pack $ unStorePath storePath, mempty)-        | otherwise = pure (Text.pack originalPath, mempty)-    phi v@(NVBuiltinF _ _) = coercionFailed v+-- 2021-05-09: NOTE: This seems a bit excessive. If these functorial versions are not used for recursion schemes - just free from it.+-- | Normalization HOF (functorial) version of @normalizeValue@. Accepts the special thunk operating/forcing/nirmalizing function & internalizes it.+normalizeValueF+  :: forall e t m f+   . ( Framed e m+     , MonadThunk t m (NValue t f m)+     , MonadDataErrorContext t f m+     , Ord (ThunkId m)+     )+  => (forall r . t -> (NValue t f m -> m r) -> m r)+  -> NValue t f m+  -> m (NValue t f m)+normalizeValueF f = run . iterNValueM run go (fmap Free . sequenceNValue' run)+ where+  start = 0 :: Int+  maxDepth = 2000+  table = mempty -    coercionFailed v =-        throwError $ Coercion @m (valueType v) TString+  run :: ReaderT Int (StateT (Set (ThunkId m)) m) r -> m r+  run = (`evalStateT` table) . (`runReaderT` start) -valueTextNoContext :: (Framed e m, MonadEffects m, Typeable m)-                   => Bool -> NValueNF m -> m Text-valueTextNoContext addPathsToStore = fmap fst . valueText addPathsToStore+  go+    :: (  NValue t f m+       -> ReaderT Int (StateT (Set (ThunkId m)) m) (NValue t f m)+       )+    -> t+    -> ReaderT Int (StateT (Set (ThunkId m)) m) (NValue t f m)+  go k tnk  =+    bool+      (do+        i <- ask+        when (i > maxDepth) $ fail $ "Exceeded maximum normalization depth of " <> show maxDepth <> " levels."+        (lifted . lifted)+          (f tnk)+          (local (+1) . k)+      )+      (pure $ pure tnk)+      =<< seen tnk+   where+    seen :: t -> ReaderT Int (StateT (Set (ThunkId m)) m) Bool+    seen t =+      do+        let tnkid = thunkId t+        lift $+          do+            thunkWasVisited <- gets $ member tnkid+            when (not thunkWasVisited) $ modify $ insert tnkid+            pure thunkWasVisited++-- | Normalize value.+-- Detect cycles.+-- If cycles were detected - put a stub on them.+normalForm+  :: ( Framed e m+     , MonadThunk t m (NValue t f m)+     , MonadDataErrorContext t f m+     , HasCitations m (NValue t f m) t+     , HasCitations1 m (NValue t f m) f+     , Ord (ThunkId m)+     )+  => NValue t f m+  -> m (NValue t f m)+normalForm t = stubCycles <$> normalizeValue t++-- | Monadic context of the result.+normalForm_+  :: ( Framed e m+     , MonadThunk t m (NValue t f m)+     , MonadDataErrorContext t f m+     , Ord (ThunkId m)+     )+  => NValue t f m+  -> m ()+normalForm_ t = void $ normalizeValue t++opaqueVal :: NVConstraint f => NValue t f m+opaqueVal = mkNVStrWithoutContext "<cycle>"++-- | Detect cycles & stub them.+stubCycles+  :: forall t f m+   . ( MonadDataContext f m+     , HasCitations m (NValue t f m) t+     , HasCitations1 m (NValue t f m) f+     )+  => NValue t f m+  -> NValue t f m+stubCycles =+  iterNValue+    (\_ t ->+      Free $+        NValue' $+          foldl'+            (flip $ addProvenance1 @m @(NValue t f m))+            cyc+            (citations @m @(NValue t f m) t)+    )+    Free+ where+  Free (NValue' cyc) = opaqueVal++thunkStubVal :: NVConstraint f => NValue t f m+thunkStubVal = mkNVStrWithoutContext thunkStubText++-- | Check if thunk @t@ is computed,+-- then bind it into first arg.+-- else bind the thunk stub val.+bindComputedThunkOrStub+  :: ( NVConstraint f+    , MonadThunk t m (NValue t f m)+    )+  => (NValue t f m -> m a)+  -> t+  -> m a+bindComputedThunkOrStub = (<=< query (pure thunkStubVal))++removeEffects+  :: (MonadThunk t m (NValue t f m), MonadDataContext f m)+  => NValue t f m+  -> m (NValue t f m)+removeEffects =+  iterNValueM+    id+    bindComputedThunkOrStub+    (fmap Free . sequenceNValue' id)++dethunk+  :: (MonadThunk t m (NValue t f m), MonadDataContext f m)+  => t+  -> m (NValue t f m)+dethunk = bindComputedThunkOrStub removeEffects
src/Nix/Options.hs view
@@ -1,70 +1,80 @@+{-# language StrictData #-}++-- | Definitions & defaults for the CLI options module Nix.Options where -import           Data.Text (Text)+import           Nix.Prelude import           Data.Time -data Options = Options-    { verbose      :: Verbosity-    , tracing      :: Bool-    , thunks       :: Bool-    , values       :: Bool-    , reduce       :: Maybe FilePath-    , reduceSets   :: Bool-    , reduceLists  :: Bool-    , parse        :: Bool-    , parseOnly    :: Bool-    , finder       :: Bool-    , findFile     :: Maybe FilePath-    , strict       :: Bool-    , evaluate     :: Bool-    , json         :: Bool-    , xml          :: Bool-    , attr         :: Maybe Text-    , include      :: [FilePath]-    , check        :: Bool-    , readFrom     :: Maybe FilePath-    , cache        :: Bool-    , repl         :: Bool-    , ignoreErrors :: Bool-    , expression   :: Maybe Text-    , arg          :: [(Text, Text)]-    , argstr       :: [(Text, Text)]-    , fromFile     :: Maybe FilePath-    , currentTime  :: UTCTime-    , filePaths    :: [FilePath]+--  2021-07-15: NOTE: What these are? They need to be documented.+-- Also need better names. Foe example, Maybes & lists names need to show their type in the name.+data Options =+  Options+    { getVerbosity   :: Verbosity+    , isTrace        :: Bool+    , isThunks       :: Bool+    , isValues       :: Bool+    , isShowScopes   :: Bool+    , getReduce      :: Maybe Path+    , isReduceSets   :: Bool+    , isReduceLists  :: Bool+    , isParse        :: Bool+    , isParseOnly    :: Bool+    , isFinder       :: Bool+    , getFindFile    :: Maybe Path+    , isStrict       :: Bool+    , isEvaluate     :: Bool+    , isJson         :: Bool+    , isXml          :: Bool+    , getAttr        :: Maybe Text+    , getInclude     :: [Path]+    , isCheck        :: Bool+    , getReadFrom    :: Maybe Path+    , isCache        :: Bool+    , isRepl         :: Bool+    , isIgnoreErrors :: Bool+    , getExpression  :: Maybe Text+    , getArg         :: [(Text, Text)]+    , getArgstr      :: [(Text, Text)]+    , getFromFile    :: Maybe Path+    , getTime        :: UTCTime+    -- ^ The time can be set to reproduce time-dependent states.+    , getFilePaths   :: [Path]     }     deriving Show  defaultOptions :: UTCTime -> Options-defaultOptions current = Options-    { verbose      = ErrorsOnly-    , tracing      = False-    , thunks       = False-    , values       = False-    , reduce       = Nothing-    , reduceSets   = False-    , reduceLists  = False-    , parse        = False-    , parseOnly    = False-    , finder       = False-    , findFile     = Nothing-    , strict       = False-    , evaluate     = False-    , json         = False-    , xml          = False-    , attr         = Nothing-    , include      = []-    , check        = False-    , readFrom     = Nothing-    , cache        = False-    , repl         = False-    , ignoreErrors = False-    , expression   = Nothing-    , arg          = []-    , argstr       = []-    , fromFile     = Nothing-    , currentTime  = current-    , filePaths    = []+defaultOptions currentTime =+  Options+    { getVerbosity   = ErrorsOnly+    , isTrace        = False+    , isThunks       = False+    , isValues       = False+    , isShowScopes   = False+    , getReduce      = mempty+    , isReduceSets   = False+    , isReduceLists  = False+    , isParse        = False+    , isParseOnly    = False+    , isFinder       = False+    , getFindFile    = mempty+    , isStrict       = False+    , isEvaluate     = False+    , isJson         = False+    , isXml          = False+    , getAttr        = mempty+    , getInclude     = mempty+    , isCheck        = False+    , getReadFrom    = mempty+    , isCache        = False+    , isRepl         = False+    , isIgnoreErrors = False+    , getExpression  = mempty+    , getArg         = mempty+    , getArgstr      = mempty+    , getFromFile    = mempty+    , getTime        = currentTime+    , getFilePaths   = mempty     }  data Verbosity@@ -75,3 +85,6 @@     | DebugInfo     | Vomit     deriving (Eq, Ord, Enum, Bounded, Show)++askOptions :: forall e m . (MonadReader e m, Has e Options) => m Options+askOptions = askLocal
src/Nix/Options/Parser.hs view
@@ -1,14 +1,24 @@+{-# language TemplateHaskell #-}++-- | Code that configures presentation parser for the CLI options 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.Prelude+import           Relude.Unsafe                  ( read )+import           GHC.Err                        ( errorWithoutStackTrace )+import           Data.Char                      ( isDigit )+import qualified Data.Text                     as Text+import           Data.Time                      ( UTCTime+                                                , defaultTimeLocale+                                                , parseTimeOrError+                                                ) import           Nix.Options-import           Options.Applicative hiding (ParserResult(..))-import           Text.PrettyPrint.ANSI.Leijen hiding ((<$>))+import           Options.Applicative     hiding ( ParserResult(..) )+import           Data.Version                   ( showVersion )+import           Development.GitRev             ( gitCommitDate+                                                , gitBranch+                                                , gitHash )+import           Paths_hnix                     ( version )  decodeVerbosity :: Int -> Verbosity decodeVerbosity 0 = ErrorsOnly@@ -19,109 +29,203 @@ 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+argPair =+  option $+    do+      s <- str+      maybe+        (errorWithoutStackTrace "Format of --arg/--argstr in hnix is: name=expr")+        (pure . second Text.tail . (`Text.splitAt` s))+        (Text.findIndex (== '=') 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")))+nixOptions current =+  Options <$>+    (fromMaybe Informational <$>+      optional+        (option++          (do+            a <- str+            bool+              (fail "Argument to -v/--verbose must be a number")+              (pure $ decodeVerbosity $ read a)+              (all isDigit a)+          )++          (  short 'v'+          <> long "verbose"+          <> help "Verbose output"+          )++        )+      )     <*> switch-        (   long "trace"-         <> help "Enable tracing code (even more can be seen if built with --flags=tracing)")+        (  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")+        (  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"))+        (  long "values"+        <> help "Enable reporting of value provenance in error messages"+        )     <*> switch-        (   long "reduce-sets"-         <> help "Reduce set members that aren't used; breaks if hasAttr is used")+        (  long "scopes"+        <> help "Enable reporting of scopes in evaluation traces"+        )+    <*> optional+        (strOption+          (  long "reduce"+          <> help "When done evaluating, output the evaluated part of the expression to FILE"+          )+        )     <*> switch-        (   long "reduce-lists"-         <> help "Reduce list members that aren't used; breaks if elemAt is used")+        (  long "reduce-sets"+        <> help "Reduce set members that aren't used; breaks if hasAttr is used"+        )     <*> switch-        (   long "parse"-         <> help "Whether to parse the file (also the default right now)")+        (  long "reduce-lists"+        <> help "Reduce list members that aren't used; breaks if elemAt is used"+        )     <*> switch-        (   long "parse-only"-         <> help "Whether to parse only, no pretty printing or checking")+        (  long "parse"+        <> help "Whether to parse the file (also the default right now)"+        )     <*> 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"))+        (  long "parse-only"+        <> help "Whether to parse only, no pretty printing or checking"+        )     <*> switch-        (   long "strict"-         <> help "When used with --eval, recursively evaluate list elements and attributes")+        (  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 "eval"-         <> help "Whether to evaluate, or just pretty-print")+        (  long "strict"+        <> help "When used with --eval, recursively evaluate list elements and attributes"+        )     <*> switch-        (   long "json"-         <> help "Print the resulting value as an JSON representation")+        (  long "eval"+        <> help "Whether to evaluate, or just pretty-print"+        )     <*> 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"))+        (  long "json"+        <> help "Print the resulting value as an JSON representation"+        )     <*> 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"))+        (  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 "cache"-         <> help "Write out the parsed expression tree to a binary cache")+        (  long "check"+        <> help "Whether to check for syntax fails after parsing"+        )+    <*> optional+        (strOption+          (  long "read"+          <> help "Read in an expression tree from a binary cache"+          )+        )     <*> switch-        (   long "repl"-         <> help "After performing any indicated actions, enter the REPL")+        (  long "cache"+        <> help "Write out the parsed expression tree to a binary cache"+        )     <*> 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"))+        (  long "repl"+        <> help "After performing any indicated actions, enter the REPL"+        )+    <*> switch+        (  long "ignore-fails"+        <> help "Continue parsing files, even if there are fails"+        )+    <*> 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"+          )+        ) +--  2020-09-12: CLI --version option mechanism is tied to meta modules specificly generated by Cabal. It is possible to use Template Haskell to resolve the version, as also a g+versionOpt :: Parser (a -> a)+versionOpt = shortVersionOpt <*> debugVersionOpt+ where+  shortVersionOpt :: Parser (a -> a)+  shortVersionOpt =+    infoOption+      (showVersion version)+      (  long "version"+      <> help "Show release version"+      )++  --  2020-09-13: NOTE: Does not work for direct `nix-build`s, works for `nix-shell` `cabal` builds.+  debugVersionOpt :: Parser (a -> a)+  debugVersionOpt =+    infoOption+      ( fold+          [ "Version: ", showVersion version+          , "\nCommit: ", $(gitHash)+          , "\n  date: ", $(gitCommitDate)+          , "\n  branch: ", $(gitBranch)+          ]+      )+      (  long "long-version"+      <> help "Show long debug version form"+      )+ nixOptionsInfo :: UTCTime -> ParserInfo Options nixOptionsInfo current =-    info (helper <*> nixOptions current)-         (fullDesc <> progDesc "" <> header "hnix")+  info+    (helper <*> versionOpt <*> nixOptions current)+    (fullDesc <> progDesc mempty <> header "hnix")
src/Nix/Parser.hs view
@@ -1,551 +1,1006 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}--{-# OPTIONS_GHC -fno-warn-name-shadowing #-}-{-# OPTIONS_GHC -Wno-missing-signatures #-}--module Nix.Parser-    ( parseNixFile-    , parseNixFileLoc-    , parseNixText-    , parseNixTextLoc-    , parseFromFileEx-    , parseFromText-    , Result(..)-    , reservedNames-    , OperatorInfo(..)-    , NSpecialOp(..)-    , NAssoc(..)-    , NOperatorDef-    , getUnaryOperator-    , getBinaryOperator-    , getSpecialOperator-    ) where--import           Control.Applicative hiding (many, some)-import           Control.DeepSeq-import           Control.Monad-import           Control.Monad.IO.Class-import           Data.Char (isAlpha, isDigit, isSpace)-import           Data.Data (Data(..))-import           Data.Foldable (concat)-import           Data.Functor-import           Data.Functor.Identity-import           Data.HashSet (HashSet)-import qualified Data.HashSet as HashSet-import           Data.List.NonEmpty (NonEmpty(..))-import qualified Data.List.NonEmpty as NE-import qualified Data.Map as Map-import           Data.Text (Text)-import           Data.Text hiding (map, foldr1, concat, concatMap, zipWith)-import qualified Data.Text.IO as T-import           Data.Typeable (Typeable)-import           Data.Void-import           GHC.Generics hiding (Prefix)-import           Nix.Expr hiding (($>))-import           Nix.Strings-import           Text.Megaparsec-import           Text.Megaparsec.Char-import qualified Text.Megaparsec.Char.Lexer as L-import           Text.Megaparsec.Expr-import           Text.PrettyPrint.ANSI.Leijen (Doc, text)--infixl 3 <+>-(<+>) :: MonadPlus m => m a -> m a -> m a-(<+>) = mplus------------------------------------------------------------------------------------nixExprLoc :: Parser NExprLoc-nixExprLoc = makeExprParser nixTerm $ map (map snd) (nixOperators nixSelector)--antiStart :: Parser Text-antiStart = symbol "${" <?> show ("${" :: String)--nixAntiquoted :: Parser a -> Parser (Antiquoted a NExprLoc)-nixAntiquoted p =-        Antiquoted <$> (antiStart *> nixToplevelForm <* symbol "}")-    <+> Plain <$> p-    <?> "anti-quotation"--selDot :: Parser ()-selDot = try (symbol "." *> notFollowedBy nixPath) <?> "."--nixSelect :: Parser NExprLoc -> Parser NExprLoc-nixSelect term = do-    res <- build-        <$> term-        <*> optional ((,) <$> (selDot *> nixSelector)-                          <*> optional (reserved "or" *> nixTerm))-    continues <- optional $ lookAhead selDot-    case continues of-        Nothing -> pure res-        Just _  -> nixSelect (pure res)- where-  build :: NExprLoc-        -> Maybe (Ann SrcSpan (NAttrPath NExprLoc), Maybe NExprLoc)-        -> NExprLoc-  build t Nothing = t-  build t (Just (s,o)) = nSelectLoc t s o--nixSelector :: Parser (Ann SrcSpan (NAttrPath NExprLoc))-nixSelector = annotateLocation $ do-    (x:xs) <- keyName `sepBy1` selDot-    return $ x :| xs--nixTerm :: Parser NExprLoc-nixTerm = do-    c <- try $ lookAhead $ satisfy $ \x ->-        pathChar x ||-        x == '(' ||-        x == '{' ||-        x == '[' ||-        x == '<' ||-        x == '/' ||-        x == '"' ||-        x == '\''-    case c of-        '('  -> nixSelect nixParens-        '{'  -> nixSelect nixSet-        '['  -> nixList-        '<'  -> nixSPath-        '/'  -> nixPath-        '"'  -> nixStringExpr-        '\'' -> nixStringExpr-        _    -> msum $-            [ nixSelect nixSet | c == 'r' ] ++-            [ nixPath | pathChar c ] ++-            if isDigit c-            then [ nixFloat-                 , nixInt ]-            else [ nixUri | isAlpha c ] ++-                 [ nixBool | c == 't' || c == 'f' ] ++-                 [ nixNull | c == 'n' ] ++-                 [ nixSelect nixSym ]--nixToplevelForm :: Parser NExprLoc-nixToplevelForm = keywords <+> nixLambda <+> nixExprLoc-  where-    keywords = nixLet <+> nixIf <+> nixAssert <+> nixWith--nixSym :: Parser NExprLoc-nixSym = annotateLocation1 $ mkSymF <$> identifier--nixInt :: Parser NExprLoc-nixInt = annotateLocation1 (mkIntF <$> integer <?> "integer")--nixFloat :: Parser NExprLoc-nixFloat = annotateLocation1 (try (mkFloatF . realToFrac <$> float) <?> "float")--nixBool :: Parser NExprLoc-nixBool = annotateLocation1 (bool "true" True <+>-                             bool "false" False) <?> "bool" where-  bool str b = mkBoolF b <$ reserved str--nixNull :: Parser NExprLoc-nixNull = annotateLocation1 (mkNullF <$ reserved "null" <?> "null")--nixParens :: Parser NExprLoc-nixParens = parens nixToplevelForm <?> "parens"--nixList :: Parser NExprLoc-nixList = annotateLocation1 (brackets (NList <$> many nixTerm) <?> "list")--pathChar :: Char -> Bool-pathChar x = isAlpha x || isDigit x || x == '.' || x == '_' || x == '-' || x == '+' || x == '~'--slash :: Parser Char-slash = try (char '/' <* notFollowedBy (satisfy (\x -> x == '/' || x == '*' || isSpace x)))-    <?> "slash"---- | A path surrounded by angle brackets, indicating that it should be--- looked up in the NIX_PATH environment variable at evaluation.-nixSPath :: Parser NExprLoc-nixSPath = annotateLocation1-    (mkPathF True <$> try (char '<' *> many (satisfy pathChar <+> slash) <* symbol ">")-         <?> "spath")--pathStr :: Parser FilePath-pathStr = lexeme $ liftM2 (++) (many (satisfy pathChar))-    (Prelude.concat <$> some (liftM2 (:) slash (some (satisfy pathChar))))--nixPath :: Parser NExprLoc-nixPath = annotateLocation1 (try (mkPathF False <$> pathStr) <?> "path")--nixLet :: Parser NExprLoc-nixLet = annotateLocation1 (reserved "let"-    *> (letBody <+> letBinders)-    <?> "let block")-  where-    letBinders = NLet-        <$> nixBinders-        <*> (reserved "in" *> nixToplevelForm)-    -- Let expressions `let {..., body = ...}' are just desugared-    -- into `(rec {..., body = ...}).body'.-    letBody = (\x -> NSelect x (StaticKey "body" :| []) Nothing) <$> aset-    aset = annotateLocation1 $ NRecSet <$> braces nixBinders--nixIf :: Parser NExprLoc-nixIf = annotateLocation1 (NIf-     <$> (reserved "if" *> nixExprLoc)-     <*> (reserved "then" *> nixToplevelForm)-     <*> (reserved "else" *> nixToplevelForm)-     <?> "if")--nixAssert :: Parser NExprLoc-nixAssert = annotateLocation1 (NAssert-  <$> (reserved "assert" *> nixExprLoc)-  <*> (semi *> nixToplevelForm)-  <?> "assert")--nixWith :: Parser NExprLoc-nixWith = annotateLocation1 (NWith-  <$> (reserved "with" *> nixToplevelForm)-  <*> (semi *> nixToplevelForm)-  <?> "with")--nixLambda :: Parser NExprLoc-nixLambda = nAbs <$> annotateLocation (try argExpr) <*> nixToplevelForm--nixStringExpr :: Parser NExprLoc-nixStringExpr = nStr <$> annotateLocation nixString--nixUri :: Parser NExprLoc-nixUri = annotateLocation1 $ lexeme $ try $ do-    start <- letterChar-    protocol <- many $ satisfy $ \x ->-        isAlpha x || isDigit x || x `elem` ("+-." :: String)-    _ <- string ":"-    address  <- some $ satisfy $ \x ->-        isAlpha x || isDigit x || x `elem` ("%/?:@&=+$,-_.!~*'" :: String)-    return $ NStr $-        DoubleQuoted [Plain $ pack $ start : protocol ++ ':' : address]--nixString :: Parser (NString NExprLoc)-nixString = lexeme (doubleQuoted <+> indented <?> "string")-  where-    doubleQuoted :: Parser (NString NExprLoc)-    doubleQuoted = DoubleQuoted . removePlainEmpty . mergePlain-                <$> (doubleQ *> many (stringChar doubleQ (void $ char '\\')-                                                 doubleEscape)-                             <* doubleQ)-                <?> "double quoted string"--    doubleQ = void (char '"')-    doubleEscape = Plain . singleton <$> (char '\\' *> escapeCode)--    indented :: Parser (NString NExprLoc)-    indented = stripIndent-            <$> (indentedQ *> many (stringChar indentedQ indentedQ-                                               indentedEscape)-                           <* indentedQ)-            <?> "indented string"--    indentedQ = void (string "''" <?> "\"''\"")-    indentedEscape = try $ do-        indentedQ-        (Plain <$> ("''" <$ char '\'' <+> "$"  <$ char '$')) <+> do-            _ <- char '\\'-            c <- escapeCode-            pure $ if c == '\n'-                   then EscapedNewline-                   else Plain $ singleton c--    stringChar end escStart esc =-            Antiquoted <$> (antiStart *> nixToplevelForm <* char '}')-        <+> Plain . singleton <$> char '$'-        <+> esc-        <+> Plain . pack <$> some plainChar-     where-       plainChar =-           notFollowedBy (end <+> void (char '$') <+> escStart) *> anyChar--    escapeCode = msum [ c <$ char e | (c,e) <- escapeCodes ] <+> anyChar---- | Gets all of the arguments for a function.-argExpr :: Parser (Params NExprLoc)-argExpr = msum [atLeft, onlyname, atRight] <* symbol ":" where-  -- An argument not in curly braces. There's some potential ambiguity-  -- in the case of, for example `x:y`. Is it a lambda function `x: y`, or-  -- a URI `x:y`? Nix syntax says it's the latter. So we need to fail if-  -- there's a valid URI parse here.-  onlyname = msum [nixUri >> unexpected (Label ('v' NE.:| "alid uri")),-                     Param <$> identifier]--  -- Parameters named by an identifier on the left (`args @ {x, y}`)-  atLeft = try $ do-    name <- identifier <* symbol "@"-    (variadic, params) <- params-    return $ ParamSet params variadic (Just name)--  -- Parameters named by an identifier on the right, or none (`{x, y} @ args`)-  atRight = do-    (variadic, params) <- params-    name <- optional $ symbol "@" *> identifier-    return $ ParamSet params variadic name--  -- Return the parameters set.-  params = do-    (args, dotdots) <- braces getParams-    return (dotdots, args)--  -- Collects the parameters within curly braces. Returns the parameters and-  -- a boolean indicating if the parameters are variadic.-  getParams :: Parser ([(Text, Maybe NExprLoc)], Bool)-  getParams = go [] where-    -- Attempt to parse `...`. If this succeeds, stop and return True.-    -- Otherwise, attempt to parse an argument, optionally with a-    -- default. If this fails, then return what has been accumulated-    -- so far.-    go acc = ((acc, True) <$ symbol "...") <+> getMore acc-    getMore acc =-      -- Could be nothing, in which just return what we have so far.-      option (acc, False) $ do-        -- Get an argument name and an optional default.-        pair <- liftM2 (,) identifier (optional $ question *> nixToplevelForm)-        -- Either return this, or attempt to get a comma and restart.-        option (acc ++ [pair], False) $ comma >> go (acc ++ [pair])--nixBinders :: Parser [Binding NExprLoc]-nixBinders = (inherit <+> namedVar) `endBy` semi where-  inherit = do-      -- We can't use 'reserved' here because it would consume the whitespace-      -- after the keyword, which is not exactly the semantics of C++ Nix.-      try $ string "inherit" *> lookAhead (void (satisfy reservedEnd))-      p <- getPosition-      x <- whiteSpace *> optional scope-      Inherit x <$> many keyName <*> pure p <?> "inherited binding"-  namedVar = do-      p <- getPosition-      NamedVar <$> (annotated <$> nixSelector)-               <*> (equals *> nixToplevelForm)-               <*> pure p-               <?> "variable binding"-  scope = parens nixToplevelForm <?> "inherit scope"--keyName :: Parser (NKeyName NExprLoc)-keyName = dynamicKey <+> staticKey where-  staticKey = StaticKey <$> identifier-  dynamicKey = DynamicKey <$> nixAntiquoted nixString--nixSet :: Parser NExprLoc-nixSet = annotateLocation1 ((isRec <*> braces nixBinders) <?> "set") where-  isRec = (reserved "rec" $> NRecSet <?> "recursive set")-       <+> pure NSet--parseNixFile :: MonadIO m => FilePath -> m (Result NExpr)-parseNixFile =-    parseFromFileEx $ stripAnnotation <$> (whiteSpace *> nixToplevelForm <* eof)--parseNixFileLoc :: MonadIO m => FilePath -> m (Result NExprLoc)-parseNixFileLoc = parseFromFileEx (whiteSpace *> nixToplevelForm <* eof)--parseNixText :: Text -> Result NExpr-parseNixText =-    parseFromText $ stripAnnotation <$> (whiteSpace *> nixToplevelForm <* eof)--parseNixTextLoc :: Text -> Result NExprLoc-parseNixTextLoc = parseFromText (whiteSpace *> nixToplevelForm <* eof)--{- Parser.Library -}--skipLineComment' :: Tokens Text -> Parser ()-skipLineComment' prefix =-  string prefix-      *> void (takeWhileP (Just "character") (\x -> x /= '\n' && x /= '\r'))--whiteSpace :: Parser ()-whiteSpace = L.space space1 lineCmnt blockCmnt-  where-    lineCmnt  = skipLineComment' "#"-    blockCmnt = L.skipBlockComment "/*" "*/"--lexeme :: Parser a -> Parser a-lexeme p = p <* whiteSpace--symbol :: Text -> Parser Text-symbol = lexeme . string--reservedEnd :: Char -> Bool-reservedEnd x = isSpace x ||-    x == '{' || x == '(' || x == '[' ||-    x == '}' || x == ')' || x == ']' ||-    x == ';' || x == ':' || x == '.' ||-    x == '"' || x == '\'' || x == ','--reserved :: Text -> Parser ()-reserved n = lexeme $ try $-    string n *> lookAhead (void (satisfy reservedEnd) <|> eof)--identifier = lexeme $ try $ do-    ident <- cons <$> satisfy (\x -> isAlpha x || x == '_')-                 <*> takeWhileP Nothing identLetter-    guard (not (ident `HashSet.member` reservedNames))-    return ident-  where-    identLetter x = isAlpha x || isDigit x || x == '_' || x == '\'' || x == '-'--parens    = between (symbol "(") (symbol ")")-braces    = between (symbol "{") (symbol "}")--- angles    = between (symbol "<") (symbol ">")-brackets  = between (symbol "[") (symbol "]")-semi      = symbol ";"-comma     = symbol ","--- colon     = symbol ":"--- dot       = symbol "."-equals    = symbol "="-question  = symbol "?"--integer :: Parser Integer-integer = lexeme L.decimal--float :: Parser Double-float = lexeme L.float--reservedNames :: HashSet Text-reservedNames = HashSet.fromList-    [ "let", "in"-    , "if", "then", "else"-    , "assert"-    , "with"-    , "rec"-    , "inherit"-    , "true", "false" ]--type Parser = ParsecT Void Text Identity--data Result a = Success a | Failure Doc deriving Show--parseFromFileEx :: MonadIO m => Parser a -> FilePath -> m (Result a)-parseFromFileEx p path = do-    txt <- liftIO (T.readFile path)-    return $ either (Failure . text . parseErrorPretty' txt) Success-           $ parse p path txt--parseFromText :: Parser a -> Text -> Result a-parseFromText p txt =-    either (Failure . text . parseErrorPretty' txt) Success $-        parse p "<string>" txt--{- Parser.Operators -}--data NSpecialOp = NHasAttrOp | NSelectOp-  deriving (Eq, Ord, Generic, Typeable, Data, Show, NFData)--data NAssoc = NAssocNone | NAssocLeft | NAssocRight-  deriving (Eq, Ord, Generic, Typeable, Data, Show, NFData)--data NOperatorDef-  = NUnaryDef Text NUnaryOp-  | NBinaryDef Text NBinaryOp NAssoc-  | NSpecialDef Text NSpecialOp NAssoc-  deriving (Eq, Ord, Generic, Typeable, Data, Show, NFData)--annotateLocation :: Parser a -> Parser (Ann SrcSpan a)-annotateLocation p = do-  begin <- getPosition-  res   <- p-  end   <- getPosition-  pure $ Ann (SrcSpan begin end) res--annotateLocation1 :: Parser (NExprF NExprLoc) -> Parser NExprLoc-annotateLocation1 = fmap annToAnnF . annotateLocation--manyUnaryOp f = foldr1 (.) <$> some f--operator "-" = lexeme . try $ string "-" <* notFollowedBy (char '>')-operator "/" = lexeme . try $ string "/" <* notFollowedBy (char '/')-operator "<" = lexeme . try $ string "<" <* notFollowedBy (char '=')-operator ">" = lexeme . try $ string ">" <* notFollowedBy (char '=')-operator n   = symbol n--opWithLoc :: Text -> o -> (Ann SrcSpan o -> a) -> Parser a-opWithLoc name op f = do-    Ann ann _ <- annotateLocation $ {- dbg (unpack name) $ -} operator name-    return $ f (Ann ann op)--binaryN name op = (NBinaryDef name op NAssocNone,-                   InfixN  (opWithLoc name op nBinary))-binaryL name op = (NBinaryDef name op NAssocLeft,-                   InfixL  (opWithLoc name op nBinary))-binaryR name op = (NBinaryDef name op NAssocRight,-                   InfixR  (opWithLoc name op nBinary))-prefix  name op = (NUnaryDef name op,-                   Prefix  (manyUnaryOp (opWithLoc name op nUnary)))--- postfix name op = (NUnaryDef name op,---                    Postfix (opWithLoc name op nUnary))--nixOperators-    :: Parser (Ann SrcSpan (NAttrPath NExprLoc))-    -> [[(NOperatorDef, Operator Parser NExprLoc)]]-nixOperators selector =-  [ -- This is not parsed here, even though technically it's part of the-    -- expression table. The problem is that in some cases, such as list-    -- membership, it's also a term. And since terms are effectively the-    -- highest precedence entities parsed by the expression parser, it ends up-    -- working out that we parse them as a kind of "meta-term".--    -- {-  1 -} [ (NSpecialDef "." NSelectOp NAssocLeft,-    --             Postfix $ do-    --                    sel <- seldot *> selector-    --                    mor <- optional (reserved "or" *> term)-    --                    return $ \x -> nSelectLoc x sel mor) ]--    {-  2 -} [ (NBinaryDef " " NApp NAssocLeft,-                -- Thanks to Brent Yorgey for showing me this trick!-                InfixL $ nApp <$ symbol "") ]-  , {-  3 -} [ prefix  "-"  NNeg ]-  , {-  4 -} [ (NSpecialDef "?" NHasAttrOp NAssocLeft,-                Postfix $ symbol "?" *> (flip nHasAttr <$> selector)) ]-  , {-  5 -} [ binaryR "++" NConcat ]-  , {-  6 -} [ binaryL "*"  NMult-             , binaryL "/"  NDiv ]-  , {-  7 -} [ binaryL "+"  NPlus-             , binaryL "-"  NMinus ]-  , {-  8 -} [ prefix  "!"  NNot ]-  , {-  9 -} [ binaryR "//" NUpdate ]-  , {- 10 -} [ binaryL "<"  NLt-             , binaryL ">"  NGt-             , binaryL "<=" NLte-             , binaryL ">=" NGte ]-  , {- 11 -} [ binaryN "==" NEq-             , binaryN "!=" NNEq ]-  , {- 12 -} [ binaryL "&&" NAnd ]-  , {- 13 -} [ binaryL "||" NOr ]-  , {- 14 -} [ binaryN "->" NImpl ]-  ]--data OperatorInfo = OperatorInfo-  { precedence    :: Int-  , associativity :: NAssoc-  , operatorName  :: Text-  } deriving (Eq, Ord, Generic, Typeable, Data, Show)--getUnaryOperator :: NUnaryOp -> OperatorInfo-getUnaryOperator = (m Map.!) where-  m = Map.fromList $ concat $ zipWith buildEntry [1..]-          (nixOperators (error "unused"))-  buildEntry i = concatMap $ \case-    (NUnaryDef name op, _) -> [(op, OperatorInfo i NAssocNone name)]-    _ -> []--getBinaryOperator :: NBinaryOp -> OperatorInfo-getBinaryOperator = (m Map.!) where-  m = Map.fromList $ concat $ zipWith buildEntry [1..]-          (nixOperators (error "unused"))-  buildEntry i = concatMap $ \case-    (NBinaryDef name op assoc, _) -> [(op, OperatorInfo i assoc name)]-    _ -> []--getSpecialOperator :: NSpecialOp -> OperatorInfo-getSpecialOperator NSelectOp = OperatorInfo 1 NAssocLeft "."-getSpecialOperator o = m Map.! o where-  m = Map.fromList $ concat $ zipWith buildEntry [1..]-          (nixOperators (error "unused"))-  buildEntry i = concatMap $ \case-    (NSpecialDef name op assoc, _) -> [(op, OperatorInfo i assoc name)]-    _ -> []+{-# language CPP #-}+{-# language DeriveAnyClass #-}++{-# options_ghc -fno-warn-name-shadowing #-}++-- | Main module for parsing Nix expressions.+module Nix.Parser+  ( parseNixFile+  , parseNixFileLoc+  , parseNixText+  , parseNixTextLoc+  , parseExpr+  , parseFromFileEx+  , Parser+  , parseFromText+  , Result+  , reservedNames+  , NAssoc(..)+  , NOpPrecedence(..)+  , NOpName(..)+  , NSpecialOp(..)+  , NOperatorDef(..)+  , nixExpr+  , nixExprAlgebra+  , nixSet+  , nixBinders+  , nixSelector+  , nixSym+  , nixPath+  , nixString+  , nixUri+  , nixSearchPath+  , nixFloat+  , nixInt+  , nixBool+  , nixNull+  , whiteSpace++  --  2022-01-26: NOTE: Try to hide it after OperatorInfo is removed+  , NOp(..)+  , appOpDef+  )+where++import           Nix.Prelude             hiding ( (<|>)+                                                , some+                                                , many+                                                )+import           Data.Foldable                  ( foldr1 )++import           Control.Monad                  ( msum )+import           Control.Monad.Combinators.Expr ( makeExprParser+                                                , Operator( Postfix+                                                          , InfixN+                                                          , InfixR+                                                          , Prefix+                                                          , InfixL+                                                          )+                                                )+import           Data.Char                      ( isAlpha+                                                , isDigit+                                                , isSpace+                                                )+import           Data.Data                      ( Data(..) )+import           Data.List.Extra                ( groupSort )+import           Data.Fix                       ( Fix(..) )+import qualified Data.HashSet                  as HashSet+import qualified Data.Text                     as Text+import           Nix.Expr.Types+import           Nix.Expr.Shorthands     hiding ( ($>) )+import           Nix.Expr.Types.Annotated+import           Nix.Expr.Strings               ( escapeCodes+                                                , stripIndent+                                                , mergePlain+                                                , removeEmptyPlains+                                                )+import           Nix.Render                     ( MonadFile() )+import           Prettyprinter                  ( Doc+                                                , pretty+                                                )+-- `parser-combinators` ships performance enhanced & MonadPlus-aware combinators.+-- For example `some` and `many` impoted here.+import           Text.Megaparsec         hiding ( (<|>)+                                                , State+                                                )+import           Text.Megaparsec.Char           ( space1+                                                , letterChar+                                                , char+                                                )+import qualified Text.Megaparsec.Char.Lexer    as Lexer+++type Parser = ParsecT Void Text (State SourcePos)++-- * Utils++-- | Different to @isAlphaNum@+isAlphanumeric :: Char -> Bool+isAlphanumeric x = isAlpha x || isDigit x+{-# inline isAlphanumeric #-}++-- | Alternative "<|>" with additional preservation of 'MonadPlus' constraint.+infixl 3 <|>+(<|>) :: MonadPlus m => m a -> m a -> m a+(<|>) = mplus++-- ** Annotated++annotateLocation1 :: Parser a -> Parser (AnnUnit SrcSpan a)+annotateLocation1 p =+  do+    begin <- getSourcePos+    res   <- p+    end   <- get -- The state set before the last whitespace++    pure $ AnnUnit (SrcSpan (toNSourcePos begin) (toNSourcePos end)) res++annotateLocation :: Parser (NExprF NExprLoc) -> Parser NExprLoc+annotateLocation = (annUnitToAnn <$>) . annotateLocation1++annotateNamedLocation :: String -> Parser (NExprF NExprLoc) -> Parser NExprLoc+annotateNamedLocation name = annotateLocation . label name+++-- ** Grammar++reservedNames :: HashSet VarName+reservedNames =+  HashSet.fromList+    ["let", "in", "if", "then", "else", "assert", "with", "rec", "inherit"]++reservedEnd :: Char -> Bool+reservedEnd x =+  isSpace x || (`elem` ("{([})];:.\"'," :: String)) x+{-# inline reservedEnd #-}++reserved :: Text -> Parser ()+reserved n =+  lexeme $ try $ chunk n *> lookAhead (void (satisfy reservedEnd) <|> eof)++exprAfterSymbol :: Char -> Parser NExprLoc+exprAfterSymbol p = symbol p *> nixExpr++exprAfterReservedWord :: Text -> Parser NExprLoc+exprAfterReservedWord word = reserved word *> nixExpr++-- | A literal copy of @megaparsec@ one but with addition of the @\r@ for Windows EOL case (@\r\n@).+-- Overall, parser should simply @\r\n -> \n@.+skipLineComment' :: Tokens Text -> Parser ()+skipLineComment' prefix =+  chunk prefix *> void (takeWhileP (pure "character") $ \x -> x /= '\n' && x /= '\r')++whiteSpace :: Parser ()+whiteSpace =+  do+    put =<< getSourcePos+    Lexer.space space1 lineCmnt blockCmnt+ where+  lineCmnt  = skipLineComment' "#"+  blockCmnt = Lexer.skipBlockComment "/*" "*/"++-- | Lexeme is a unit of the language.+-- Convention is that after lexeme an arbitrary amount of empty entities (space, comments, line breaks) are allowed.+-- This lexeme definition just skips over superflous @megaparsec: lexeme@ abstraction.+lexeme :: Parser a -> Parser a+lexeme p = p <* whiteSpace++symbol :: Char -> Parser Char+symbol = lexeme . char++symbols :: Text -> Parser Text+symbols = lexeme . chunk++-- We restrict the type of 'parens' and 'brackets' here because if they were to+-- take a 'Parser NExprLoc' argument they would parse additional text which+-- wouldn't be captured in the source location annotation.+--+-- Braces and angles in hnix don't enclose a single expression so this type+-- restriction would not be useful.+parens :: Parser (NExprF f) -> Parser (NExprF f)+parens   = on between symbol '(' ')'++braces :: Parser a -> Parser a+braces   = on between symbol '{' '}'++brackets :: Parser (NExprF f) -> Parser (NExprF f)+brackets = on between symbol '[' ']'++antiquotedIsHungryForTrailingSpaces :: Bool -> Parser (Antiquoted v NExprLoc)+antiquotedIsHungryForTrailingSpaces hungry = Antiquoted <$> (antiStart *> nixExpr <* antiEnd)+ where+  antiStart :: Parser Text+  antiStart = label "${" $ symbols "${"++  antiEnd :: Parser Char+  antiEnd = label "}" $+    bool+      id+      lexeme+      hungry+      (char '}')++antiquotedLexeme :: Parser (Antiquoted v NExprLoc)+antiquotedLexeme = antiquotedIsHungryForTrailingSpaces True++antiquoted :: Parser (Antiquoted v NExprLoc)+antiquoted = antiquotedIsHungryForTrailingSpaces False++---------------------------------------------------------------------------------++-- * Parser parts++-- ** Constrants++nixNull :: Parser NExprLoc+nixNull =+  annotateNamedLocation "null" $+    mkNullF <$ reserved "null"++nixBool :: Parser NExprLoc+nixBool =+  annotateNamedLocation "bool" $+    on (<|>) lmkBool (True, "true") (False, "false")+ where+  lmkBool (b, txt) = mkBoolF b <$ reserved txt++integer :: Parser Integer+integer = lexeme Lexer.decimal++nixInt :: Parser NExprLoc+nixInt =+  annotateNamedLocation "integer" $+    mkIntF <$> integer++float :: Parser Double+float = lexeme Lexer.float++nixFloat :: Parser NExprLoc+nixFloat =+  annotateNamedLocation "float" $+    try $+      mkFloatF . realToFrac <$> float++nixUri :: Parser NExprLoc+nixUri =+  lexeme $+    annotateLocation $+      try $+        do+          start    <- letterChar+          protocol <-+            takeWhileP mempty $+              \ x ->+                isAlphanumeric x+                || (`elem` ("+-." :: String)) x+          _       <- single ':'+          address <-+            takeWhile1P mempty $+                \ x ->+                  isAlphanumeric x+                  || (`elem` ("%/?:@&=+$,-_.!~*'" :: String)) x+          pure . NStr . DoubleQuoted . one . Plain $ start `Text.cons` protocol <> ":" <> address+++-- ** Strings++nixAntiquoted :: Parser a -> Parser (Antiquoted a NExprLoc)+nixAntiquoted p =+  label "anti-quotation" $+    antiquotedLexeme+    <|> Plain <$> p++escapeCode :: Parser Char+escapeCode =+  msum+    [ c <$ char e | (c, e) <- escapeCodes ]+  <|> anySingle++stringChar+  :: Parser ()+  -> Parser ()+  -> Parser (Antiquoted Text NExprLoc)+  -> Parser (Antiquoted Text NExprLoc)+stringChar end escStart esc =+  antiquoted+  <|> Plain . one <$> char '$'+  <|> esc+  <|> Plain . fromString <$> some plainChar+  where+  plainChar :: Parser Char+  plainChar =+    notFollowedBy (end <|> void (char '$') <|> escStart) *> anySingle++doubleQuoted :: Parser (NString NExprLoc)+doubleQuoted =+  label "double quoted string" $+    DoubleQuoted . removeEmptyPlains . mergePlain <$>+      inQuotationMarks (many $ stringChar quotationMark (void $ char '\\') doubleEscape)+  where+  inQuotationMarks :: Parser a -> Parser a+  inQuotationMarks expr = quotationMark *> expr <* quotationMark++  quotationMark :: Parser ()+  quotationMark = void $ char '"'++  doubleEscape :: Parser (Antiquoted Text r)+  doubleEscape = Plain . one <$> (char '\\' *> escapeCode)+++indented :: Parser (NString NExprLoc)+indented =+  label "indented string" $+    stripIndent <$>+      inIndentedQuotation (many $ join stringChar indentedQuotationMark indentedEscape)+ where+  -- | Read escaping inside of the "'' <expr> ''"+  indentedEscape :: Parser (Antiquoted Text r)+  indentedEscape =+    try $+      do+        indentedQuotationMark+        Plain <$> ("''" <$ char '\'' <|> "$" <$ char '$')+          <|>+            do+              c <- char '\\' *> escapeCode++              pure $+                bool+                  EscapedNewline+                  (Plain $ one c)+                  ('\n' /= c)++  -- | Enclosed into indented quatation "'' <expr> ''"+  inIndentedQuotation :: Parser a -> Parser a+  inIndentedQuotation expr = indentedQuotationMark *> expr <* indentedQuotationMark++  -- | Symbol "''"+  indentedQuotationMark :: Parser ()+  indentedQuotationMark = label "\"''\"" . void $ chunk "''"+++nixString' :: Parser (NString NExprLoc)+nixString' = label "string" $ lexeme $ doubleQuoted <|> indented++nixString :: Parser NExprLoc+nixString = annNStr <$> annotateLocation1 nixString'+++-- ** Names (variables aka symbols)++identifier :: Parser VarName+identifier =+  lexeme $+    try $+      do+        (coerce -> iD) <-+          liftA2 Text.cons+            (satisfy (\x -> isAlpha x || x == '_'))+            (takeWhileP mempty identLetter)+        guard $ not $ iD `HashSet.member` reservedNames+        pure iD+ where+  identLetter x = isAlphanumeric x || x == '_' || x == '\'' || x == '-'++nixSym :: Parser NExprLoc+nixSym = annotateLocation $ mkSymF <$> coerce identifier+++-- ** ( ) parens++-- | 'nixExpr' returns an expression annotated with a source position,+-- however this position doesn't include the parsed parentheses, so remove the+-- "inner" location annotateion and annotate again, including the parentheses.+nixParens :: Parser NExprLoc+nixParens =+  annotateNamedLocation "parens" $+    parens $ stripAnnF . unFix <$> nixExpr+++-- ** [ ] list++nixList :: Parser NExprLoc+nixList =+  annotateNamedLocation "list" $+    brackets $ NList <$> many nixTerm+++-- ** { } set++nixBinders :: Parser [Binding NExprLoc]+nixBinders = (inherit <|> namedVar) `endBy` symbol ';' where+  inherit =+    do+      -- We can't use 'reserved' here because it would consume the whitespace+      -- after the keyword, which is not exactly the semantics of C++ Nix.+      try $ chunk "inherit" *> lookAhead (void $ satisfy reservedEnd)+      p <- getSourcePos+      x <- whiteSpace *> optional scope+      label "inherited binding" $+        liftA2 (Inherit x)+          (many identifier)+          (pure (toNSourcePos p))+  namedVar =+    do+      p <- getSourcePos+      label "variable binding" $+        liftA3 NamedVar+          (annotated <$> nixSelector)+          (exprAfterSymbol '=')+          (pure (toNSourcePos p))+  scope = label "inherit scope" nixParens++nixSet :: Parser NExprLoc+nixSet =+  annotateNamedLocation "set" $+    isRec <*> braces nixBinders+ where+  isRec =+    label "recursive set" (reserved "rec" $> NSet Recursive)+    <|> pure (NSet mempty)++-- ** /x/y/z literal Path++pathChar :: Char -> Bool+pathChar x =+  isAlphanumeric x || (`elem` ("._-+~" :: String)) x++slash :: Parser Char+slash =+  label "slash " $+    try $+      char '/' <* notFollowedBy (satisfy $ \x -> x == '/' || x == '*' || isSpace x)++pathStr :: Parser Path+pathStr =+  lexeme $ coerce . toString <$>+    liftA2 (<>)+      (takeWhileP mempty pathChar)+      (Text.concat <$>+        some+          (liftA2 Text.cons+            slash+            (takeWhile1P mempty pathChar)+          )+      )++nixPath :: Parser NExprLoc+nixPath =+  annotateNamedLocation "path" $+    try $ mkPathF False <$> coerce pathStr+++-- ** <<x>> environment path++-- | A path surrounded by angle brackets, indicating that it should be+-- looked up in the NIX_PATH environment variable at evaluation.+nixSearchPath :: Parser NExprLoc+nixSearchPath =+  annotateNamedLocation "spath" $+    mkPathF True <$> try (lexeme $ char '<' *> many (satisfy pathChar <|> slash) <* char '>')+++-- ** Operators++--  2022-01-26: NOTE: Rename to 'literal'+newtype NOpName = NOpName Text+  deriving+    (Eq, Ord, Generic, Typeable, Data, Show, NFData)++instance IsString NOpName where+  fromString = coerce . fromString @Text++instance ToString NOpName where+  toString = toString @Text . coerce++operator :: NOpName -> Parser Text+operator (coerce -> op) =+  case op of+    c@"-" -> c `without` '>'+    c@"/" -> c `without` '/'+    c@"<" -> c `without` '='+    c@">" -> c `without` '='+    n   -> symbols n+ where+  without :: Text -> Char -> Parser Text+  without opChar noNextChar =+    lexeme . try $ chunk opChar <* notFollowedBy (char noNextChar)++opWithLoc :: (AnnUnit SrcSpan o -> a) -> o -> NOpName -> Parser a+opWithLoc f op name = f . (op <$) <$> annotateLocation1 (operator name)++--  2022-01-26: NOTE: Make presedence free and type safe by moving it into type level:+--  https://youtu.be/qaPdg0mZavM?t=1757+--  https://wiki.haskell.org/The_Monad.Reader/Issue5/Number_Param_Types+newtype NOpPrecedence = NOpPrecedence Int+  deriving (Eq, Ord, Generic, Bounded, Typeable, Data, Show, NFData)++instance Enum NOpPrecedence where+  toEnum = coerce+  fromEnum = coerce++instance Num NOpPrecedence where+  (+) = coerce ((+) @Int)+  (*) = coerce ((*) @Int)+  abs = coerce (abs @Int)+  signum = coerce (signum @Int)+  fromInteger = coerce (fromInteger @Int)+  negate = coerce (negate @Int)++--  2022-01-26: NOTE: This type belongs into 'Type.Expr' & be used in NExprF.+data NAppOp = NAppOp+  deriving (Eq, Ord, Generic, Typeable, Data, Show, NFData)++--  2022-01-26: NOTE: This type belongs into 'Type.Expr' & be used in NExprF.+data NSpecialOp+  = NHasAttrOp+  | NSelectOp+  | NTerm -- ^ For special handling of internal special cases.+  deriving (Eq, Ord, Generic, Typeable, Data, Show, NFData)++data NAssoc+  = NAssocLeft+  -- Nota bene: @parser-combinators@ named "associative property" as 'InfixN' stating it as "non-associative property".+  -- Binary operators having some associativity is a basis property in mathematical algebras in use (for example, in Category theory). Having no associativity in operators makes theory mostly impossible in use and so non-associativity is not encountered in notations, therefore under 'InfixN' @parser-combinators@ meant "associative".+  -- | Bidirectional associativity, or simply: associative property.+  | NAssoc+  | NAssocRight+  deriving (Eq, Ord, Generic, Typeable, Data, Show, NFData)++--  2022-01-31: NOTE: This type and related typeclasses & their design, probably need a refinement.+--+-- In the "Nix.Pretty", the code probably should be well-typed to the type of operations its processes.+-- Therefor splitting operation types into separate types there is probably needed.+--+-- After that:+--+-- > { NAssoc, NOpPrecedence, NOpName }+--+-- Can be formed into a type.+--+-- Also 'NAppDef' really has only 1 implementation, @{ NAssoc, NOpPrecedence, NOpName }@+-- were added there only to make type uniformal.+-- All impossible cases ideally should be unrepresentable.+-- | Single operator grammar entries.+data NOperatorDef+  = NAppDef     NAppOp     NAssoc NOpPrecedence NOpName+  | NUnaryDef   NUnaryOp   NAssoc NOpPrecedence NOpName+  | NBinaryDef  NBinaryOp  NAssoc NOpPrecedence NOpName+  | NSpecialDef NSpecialOp NAssoc NOpPrecedence NOpName+  --  2022-01-26: NOTE: Ord can be the order of evaluation of precedence (which 'Pretty' printing also accounts for).+  deriving (Eq, Ord, Generic, Typeable, Data, Show, NFData)++-- Supplied since its definition gets called/used frequently.+-- | Functional application operator definition, left associative, high precedence.+appOpDef :: NOperatorDef+appOpDef = NAppDef NAppOp NAssocLeft 1 " " -- This defined as "2" in Nix lang spec.++--  2022-01-26: NOTE: When total - make sure to hide & inline all these instances to get free solution.+-- | Class to get a private free construction to abstract away the gap between the Nix operation types+-- 'NUnaryOp', 'NBinaryOp', 'NSpecialOp'.+-- And in doing remove 'OperatorInfo' from existance.+class NOp a where+  {-# minimal getOpDef, getOpAssoc, getOpPrecedence, getOpName #-}++  getOpDef :: a -> NOperatorDef+  getOpAssoc :: a -> NAssoc+  getOpPrecedence :: a -> NOpPrecedence+  getOpName :: a -> NOpName++instance NOp NAppOp where+  getOpDef NAppOp = appOpDef+  getOpAssoc _op = fun appOpDef+   where+    fun (NAppDef _op assoc _prec _name) = assoc+    fun _ = error "Impossible happened, funapp operation should been matched."+  getOpPrecedence _op = fun appOpDef+   where+    fun (NAppDef _op _assoc prec _name) = prec+    fun _ = error "Impossible happened, funapp operation should been matched."+  getOpName _ = fun appOpDef+   where+    fun (NAppDef _op _assoc _prec name) = name+    fun _ = error "Impossible happened, funapp operation should been matched."++instance NOp NUnaryOp where+  getOpDef =+    \case+      NNeg -> NUnaryDef NNeg NAssocRight 3 "-"+      NNot -> NUnaryDef NNot NAssocRight 8 "!"+  getOpAssoc = fun . getOpDef+   where+    fun (NUnaryDef _op assoc _prec _name) = assoc+    fun _ = error "Impossible happened, unary operation should been matched."+  getOpPrecedence = fun . getOpDef+   where+    fun (NUnaryDef _op _assoc prec _name) = prec+    fun _ = error "Impossible happened, unary operation should been matched."+  getOpName = fun . getOpDef+   where+    fun (NUnaryDef _op _assoc _prec name) = name+    fun _ = error "Impossible happened, unary operation should been matched."++instance NOp NBinaryOp where+  getOpDef =+    \case+      NConcat -> NBinaryDef NConcat NAssocRight  5 "++"+      NMult   -> NBinaryDef NMult   NAssocLeft   6 "*"+      NDiv    -> NBinaryDef NDiv    NAssocLeft   6 "/"+      NPlus   -> NBinaryDef NPlus   NAssocLeft   7 "+"+      NMinus  -> NBinaryDef NMinus  NAssocLeft   7 "-"+      NUpdate -> NBinaryDef NUpdate NAssocRight  9 "//"+      NLt     -> NBinaryDef NLt     NAssocLeft  10 "<"+      NLte    -> NBinaryDef NLte    NAssocLeft  10 "<="+      NGt     -> NBinaryDef NGt     NAssocLeft  10 ">"+      NGte    -> NBinaryDef NGte    NAssocLeft  10 ">="+      NEq     -> NBinaryDef NEq     NAssoc      11 "=="+      NNEq    -> NBinaryDef NNEq    NAssoc      11 "!="+      NAnd    -> NBinaryDef NAnd    NAssocLeft  12 "&&"+      NOr     -> NBinaryDef NOr     NAssocLeft  13 "||"+      NImpl   -> NBinaryDef NImpl   NAssocRight 14 "->"+  getOpAssoc = fun . getOpDef+   where+    fun (NBinaryDef _op assoc _prec _name) = assoc+    fun _ = error "Impossible happened, binary operation should been matched."+  getOpPrecedence = fun . getOpDef+   where+    fun (NBinaryDef _op _assoc prec _name) = prec+    fun _ = error "Impossible happened, binary operation should been matched."+  getOpName = fun . getOpDef+   where+    fun (NBinaryDef _op _assoc _prec name) = name+    fun _ = error "Impossible happened, binary operation should been matched."++instance NOp NSpecialOp where+  getOpDef =+    \case+      NSelectOp  -> NSpecialDef NSelectOp  NAssocLeft 1 "."+      NHasAttrOp -> NSpecialDef NHasAttrOp NAssocLeft 4 "?"+      NTerm      -> NSpecialDef NTerm      NAssocLeft 1 "???"+  getOpAssoc = fun . getOpDef+   where+    fun (NSpecialDef _op assoc _prec _name) = assoc+    fun _ = error "Impossible happened, special operation should been matched."+  getOpPrecedence = fun . getOpDef+   where+    fun (NSpecialDef _op _assoc prec _name) = prec+    fun _ = error "Impossible happened, special operation should been matched."+  getOpName = fun . getOpDef+   where+    fun (NSpecialDef _op _assoc _prec name) = name+    fun _ = error "Impossible happened, special operation should been matched."++instance NOp NOperatorDef where+  getOpDef op = op+  getOpAssoc = \case+    (NAppDef     _op assoc _prec _name) -> assoc+    (NUnaryDef   _op assoc _prec _name) -> assoc+    (NBinaryDef  _op assoc _prec _name) -> assoc+    (NSpecialDef _op assoc _prec _name) -> assoc+  getOpPrecedence = fun . getOpDef+   where+    fun (NAppDef     _op _assoc prec _name) = prec+    fun (NUnaryDef   _op _assoc prec _name) = prec+    fun (NBinaryDef  _op _assoc prec _name) = prec+    fun (NSpecialDef _op _assoc prec _name) = prec+  getOpName = fun . getOpDef+   where+    fun (NAppDef     _op _assoc _prec name) = name+    fun (NUnaryDef   _op _assoc _prec name) = name+    fun (NBinaryDef  _op _assoc _prec name) = name+    fun (NSpecialDef _op _assoc _prec name) = name++prefix :: NUnaryOp -> Operator Parser NExprLoc+prefix op =+  Prefix $ manyUnaryOp $ opWithLoc annNUnary op $ getOpName op+-- postfix name op = (NUnaryDef name op,+--                    Postfix (opWithLoc annNUnary op name))++manyUnaryOp :: MonadPlus f => f (a -> a) -> f (a -> a)+manyUnaryOp f = foldr1 (.) <$> some f++binary+  :: NBinaryOp+  -> Operator Parser NExprLoc+binary op =+  mapAssocToInfix (getOpAssoc op) $ opWithLoc annNBinary op (getOpName op)++mapAssocToInfix :: NAssoc -> m (a -> a -> a) -> Operator m a+mapAssocToInfix NAssocLeft  = InfixL+mapAssocToInfix NAssoc      = InfixN+mapAssocToInfix NAssocRight = InfixR++-- ** x: y lambda function++-- | Gets all of the arguments for a function.+argExpr :: Parser (Params NExprLoc)+argExpr =+  msum+    [ atLeft+    , onlyname+    , atRight+    ]+  <* symbol ':'+ where+  -- An argument not in curly braces. There's some potential ambiguity+  -- in the case of, for example `x:y`. Is it a lambda function `x: y`, or+  -- a URI `x:y`? Nix syntax says it's the latter. So we need to fail if+  -- there's a valid URI parse here.+  onlyname =+    msum+      [ nixUri *> unexpected (Label $ fromList "valid uri" )+      , Param <$> identifier+      ]++  -- Parameters named by an identifier on the left (`args @ {x, y}`)+  atLeft =+    try $+      do+        name             <- identifier <* symbol '@'+        (variadic, pset) <- params+        pure $ ParamSet (pure name) variadic pset++  -- Parameters named by an identifier on the right, or none (`{x, y} @ args`)+  atRight =+    do+      (variadic, pset) <- params+      name             <- optional $ symbol '@' *> identifier+      pure $ ParamSet name variadic pset++  -- Return the parameters set.+  params = braces getParams++  -- Collects the parameters within curly braces. Returns the parameters and+  -- an flag indication if the parameters are variadic.+  getParams :: Parser (Variadic, [(VarName, Maybe NExprLoc)])+  getParams = go mempty+   where+    -- Attempt to parse `...`. If this succeeds, stop and return True.+    -- Otherwise, attempt to parse an argument, optionally with a+    -- default. If this fails, then return what has been accumulated+    -- so far.+    go :: [(VarName, Maybe NExprLoc)] -> Parser (Variadic, [(VarName, Maybe NExprLoc)])+    go acc = ((Variadic, acc) <$ symbols "...") <|> getMore+     where+      getMore :: Parser (Variadic, [(VarName, Maybe NExprLoc)])+      getMore =+        -- Could be nothing, in which just return what we have so far.+        option (mempty, acc) $+          do+            -- Get an argument name and an optional default.+            pair <-+              liftA2 (,)+                identifier+                (optional $ exprAfterSymbol '?')++            let args = acc <> one pair++            -- Either return this, or attempt to get a comma and restart.+            option (mempty, args) $ symbol ',' *> go args++nixLambda :: Parser NExprLoc+nixLambda =+  liftA2 annNAbs+    (annotateLocation1 $ try argExpr)+    nixExpr+++-- ** let expression++nixLet :: Parser NExprLoc+nixLet =+  annotateNamedLocation "let block" $+    reserved "let" *> (letBody <|> letBinders)+ where+  -- | Expressions `let {..., body = ...}' are just desugared+  -- into `(rec {..., body = ...}).body'.+  letBody    = (\ expr -> NSelect Nothing expr (one $ StaticKey "body")) <$> attrset+   where+    attrset       = annotateLocation $ NSet Recursive <$> braces nixBinders+  -- | Regular `let`+  letBinders =+    liftA2 NLet+      nixBinders+      (exprAfterReservedWord "in")++-- ** if then else++nixIf :: Parser NExprLoc+nixIf =+  annotateNamedLocation "if" $+    liftA3 NIf+      (reserved "if"   *> nixExpr)+      (exprAfterReservedWord "then")+      (exprAfterReservedWord "else")++-- ** with++nixWith :: Parser NExprLoc+nixWith =+  annotateNamedLocation "with" $+    liftA2 NWith+      (exprAfterReservedWord "with")+      (exprAfterSymbol       ';'   )+++-- ** assert++nixAssert :: Parser NExprLoc+nixAssert =+  annotateNamedLocation "assert" $+    liftA2 NAssert+      (exprAfterReservedWord "assert")+      (exprAfterSymbol       ';'     )++-- ** . - reference (selector) into attr++selectorDot :: Parser ()+selectorDot = label "." $ try (symbol '.' *> notFollowedBy nixPath)++keyName :: Parser (NKeyName NExprLoc)+keyName = dynamicKey <|> staticKey+ where+  staticKey  = StaticKey <$> identifier+  dynamicKey = DynamicKey <$> nixAntiquoted nixString'++nixSelector :: Parser (AnnUnit SrcSpan (NAttrPath NExprLoc))+nixSelector =+  annotateLocation1 $ fromList <$> keyName `sepBy1` selectorDot++nixSelect :: Parser NExprLoc -> Parser NExprLoc+nixSelect term =+  do+    res <-+      liftA2 builder+        term+        (optional $+          liftA2 (flip (,))+            (selectorDot *> nixSelector)+            (optional $ reserved "or" *> nixTerm)+        )+    continues <- optional $ lookAhead selectorDot++    maybe+      id+      (const nixSelect)+      continues+      (pure res)+ where+  builder+    :: NExprLoc+    -> Maybe+      ( Maybe NExprLoc+      , AnnUnit SrcSpan (NAttrPath NExprLoc)+      )+    -> NExprLoc+  builder t =+    maybe+      t+      (uncurry (`annNSelect` t))+++-- ** _ - syntax hole++nixSynHole :: Parser NExprLoc+nixSynHole =+  annotateLocation $ mkSynHoleF <$> coerce (char '^' *> identifier)++-- List of Nix operation parsers with their precedence.+opParsers :: [(NOpPrecedence, Operator Parser NExprLoc)]+opParsers =+  -- This is not parsed here, even though technically it's part of the+  -- expression table. The problem is that in some cases, such as list+  -- membership, it's also a term. And since terms are effectively the+  -- highest precedence entities parsed by the expression parser, it ends up+  -- working out that we parse them as a kind of "meta-term".++  -- {-  1 -}+  -- [ ( NSpecialDef "." NSelectOp NAssocLeft+  --   , Postfix $+  --       do+  --         sel <- seldot *> selector+  --         mor <- optional (reserved "or" *> term)+  --         pure $ \x -> annNSelect x sel mor)+  -- ]++  -- NApp is left associative+  -- 2018-05-07: jwiegley: Thanks to Brent Yorgey for showing me this trick!+  specialBuilder NAppOp (InfixL $ annNApp <$ symbols mempty) <>+  specialBuilder NHasAttrOp (Postfix $ symbol '?' *> (flip annNHasAttr <$> nixSelector)) <>+  builder prefix <>+  builder binary+ where+  specialBuilder :: NOp t => t -> b -> [(NOpPrecedence, b)]+  specialBuilder op parser = one (entry op (const parser))++  builder :: (Enum t, Bounded t, NOp t) => (t -> b) -> [(NOpPrecedence, b)]+  builder tp = fmap (`entry` tp) universe++  entry :: NOp t => t -> (t -> b) -> (NOpPrecedence, b)+  entry op parser = (getOpPrecedence op, parser op)+++-- ** Expr & its constituents (Language term, expr algebra)++nixTerm :: Parser NExprLoc+nixTerm =+  do+    c <- try . lookAhead . satisfy $+      \x -> (`elem` ("({[</\"'^" :: String)) x || pathChar x+    case c of+      '('  -> nixSelect nixParens+      '{'  -> nixSelect nixSet+      '['  -> nixList+      '<'  -> nixSearchPath+      '/'  -> nixPath+      '"'  -> nixString+      '\'' -> nixString+      '^'  -> nixSynHole+      _ ->+        msum+          $  [ nixSelect nixSet | c == 'r' ]+          <> [ nixPath | pathChar c ]+          <> if isDigit c+              then [ nixFloat, nixInt ]+              else+                [ nixUri | isAlpha c ]+                <> [ nixBool | c == 't' || c == 'f' ]+                <> [ nixNull | c == 'n' ]+                <> one (nixSelect nixSym)++-- | Bundles parsers into @[[]]@ based on precedence (form is required for `megaparsec`).+nixOperators :: [[ Operator Parser NExprLoc ]]+nixOperators =+  snd <$>+    groupSort opParsers++-- | Nix expression algebra parser.+-- "Expression algebra" is to explain @megaparsec@ use of the term "Expression" (parser for language algebraic coperators without any statements (without @let@ etc.)), which is essentially an algebra inside the language.+nixExprAlgebra :: Parser NExprLoc+nixExprAlgebra =+  makeExprParser+    nixTerm+    nixOperators++nixExpr :: Parser NExprLoc+nixExpr = keywords <|> nixLambda <|> nixExprAlgebra+ where+  keywords = nixLet <|> nixIf <|> nixAssert <|> nixWith+++-- * Parse++type Result a = Either (Doc Void) a+++parseWith+  :: Parser a+  -> Path+  -> Text+  -> Either (Doc Void) a+parseWith parser file input =+  either+    (Left . pretty . errorBundlePretty)+    pure+    $ (`evalState` initialPos (coerce file)) $ (`runParserT` coerce file) parser input+++parseFromFileEx :: MonadFile m => Parser a -> Path -> m (Result a)+parseFromFileEx parser file = parseWith parser file <$> readFile file++parseFromText :: Parser a -> Text -> Result a+parseFromText = (`parseWith` "<string>")++fullContent :: Parser NExprLoc+fullContent = whiteSpace *> nixExpr <* eof++parseNixFile' :: MonadFile m => (Parser NExprLoc -> Parser a) -> Path -> m (Result a)+parseNixFile' f =+  parseFromFileEx $ f fullContent++parseNixFile :: MonadFile m => Path -> m (Result NExpr)+parseNixFile =+  parseNixFile' (stripAnnotation <$>)++parseNixFileLoc :: MonadFile m => Path -> m (Result NExprLoc)+parseNixFileLoc =+  parseNixFile' id++parseNixText' :: (Parser NExprLoc -> Parser a) -> Text -> Result a+parseNixText' f =+  parseFromText $ f fullContent++parseNixText :: Text -> Result NExpr+parseNixText =+  parseNixText' (stripAnnotation <$>)++parseNixTextLoc :: Text -> Result NExprLoc+parseNixTextLoc =+  parseNixText' id++parseExpr :: MonadFail m => Text -> m NExpr+parseExpr =+  either+    (fail . show)+    pure+    . parseNixText
+ src/Nix/Prelude.hs view
@@ -0,0 +1,20 @@+-- | This is a @Prelude@, but, please, do not put things in here,+-- put them into "Nix.Utils". This module is a pass-through-multiplexer,+-- between our custom code ("Nix.Utils") that shadows over the outside prelude that is in use ("Relude")+-- "Prelude" module has a problem of being imported & used by other projects.+-- "Nix.Utils" as a module with a regular name does not have that problem.+module Nix.Prelude+    ( module Nix.Utils+    , module Relude+    ) where++import           Nix.Utils+import           Relude                  hiding ( pass+                                                , force+                                                , readFile+                                                , whenJust+                                                , whenNothing+                                                , trace+                                                , traceM+                                                )+
src/Nix/Pretty.hs view
@@ -1,305 +1,455 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE ViewPatterns #-}+{-# language CPP #-}+{-# language AllowAmbiguousTypes #-} -{-# OPTIONS_GHC -fno-warn-name-shadowing #-}-{-# OPTIONS_GHC -Wno-orphans #-}+{-# options_ghc -fno-warn-name-shadowing #-}  module Nix.Pretty where -import           Control.Monad-import           Data.Fix-import           Data.HashMap.Lazy (toList)-import qualified Data.HashMap.Lazy as M-import qualified Data.HashSet as HashSet-import           Data.List (isPrefixOf, sort)-import           Data.List.NonEmpty (NonEmpty(..))-import qualified Data.List.NonEmpty as NE-import           Data.Maybe (isJust, fromMaybe)-import           Data.Text (pack, unpack, replace, strip)-import qualified Data.Text as Text+import           Nix.Prelude             hiding ( toList, group )+import           Control.Monad.Free             ( Free(Free) )+import           Data.Fix                       ( Fix(..)+                                                , foldFix )+import           Data.HashMap.Lazy              ( toList )+import qualified Data.HashMap.Lazy             as M+import qualified Data.HashSet                  as HashSet+import qualified Data.List.NonEmpty            as NE+import           Data.Text                      ( replace+                                                , strip+                                                )+import qualified Data.Text                     as Text+import           Prettyprinter           hiding ( list ) import           Nix.Atoms-import           Nix.Expr+import           Nix.Cited+import           Nix.Expr.Types+import           Nix.Expr.Types.Annotated+import           Nix.Expr.Strings+import           Nix.Normal import           Nix.Parser-import           Nix.Strings+import           Nix.String import           Nix.Thunk-#if ENABLE_TRACING-import           Nix.Utils-#else-import           Nix.Utils hiding ((<$>))-#endif import           Nix.Value-import           Prelude hiding ((<$>))-import           Text.PrettyPrint.ANSI.Leijen  -- | This type represents a pretty printed nix expression -- together with some information about the expression.-data NixDoc = NixDoc-  { -- | The rendered expression, without any parentheses.-    withoutParens    :: Doc+data NixDoc ann = NixDoc+  { -- | Rendered expression. Without surrounding parenthesis.+    getDoc :: Doc ann      -- | The root operator is the operator at the root of     -- the expression tree. For example, in '(a * b) + c', '+' would be the root     -- operator. It is needed to determine if we need to wrap the expression in     -- parentheses.-  , rootOp :: OperatorInfo+  , rootOp :: NOperatorDef   , wasPath :: Bool -- This is needed so that when a path is used in a selector path-                    -- we can add brackets appropiately+                    -- we can add brackets appropriately   } -mkNixDoc :: Doc -> OperatorInfo -> NixDoc-mkNixDoc d o = NixDoc { withoutParens = d, rootOp = o, wasPath = False }+-- | Represent Nix antiquotes.+--+-- >+-- > ${ expr }+-- >+antiquote :: NixDoc ann -> Doc ann+antiquote x = "${" <> getDoc x <> "}" +mkNixDoc :: NOperatorDef -> Doc ann -> NixDoc ann+mkNixDoc o d = NixDoc { getDoc = d, rootOp = o, wasPath = False }+ -- | A simple expression is never wrapped in parentheses. The expression --   behaves as if its root operator had a precedence higher than all --   other operators (including function application).-simpleExpr :: Doc -> NixDoc-simpleExpr d = mkNixDoc d (OperatorInfo minBound NAssocNone "simple expr")+simpleExpr :: Doc ann -> NixDoc ann+simpleExpr =+  mkNixDoc $ NSpecialDef NTerm NAssoc minBound "simple expr" -pathExpr :: Doc -> NixDoc+pathExpr :: Doc ann -> NixDoc ann pathExpr d = (simpleExpr d) { wasPath = True }  -- | An expression that behaves as if its root operator had a precedence lower --   than all other operators. That ensures that the expression is wrapped in---   parantheses in almost always, but it's still rendered without parentheses+--   parentheses in almost always, but it's still rendered without parentheses --   in cases where parentheses are never required (such as in the LHS of a --   binding).-leastPrecedence :: Doc -> NixDoc+leastPrecedence :: Doc ann -> NixDoc ann leastPrecedence =-    flip mkNixDoc $ OperatorInfo maxBound NAssocNone "least precedence"+  mkNixDoc $ NSpecialDef NTerm NAssoc maxBound "least precedence" -appOp :: OperatorInfo-appOp = getBinaryOperator NApp -appOpNonAssoc :: OperatorInfo-appOpNonAssoc = (getBinaryOperator NApp) { associativity = NAssocNone }+data WrapMode+  = ProcessAllWrap+  | PrecedenceWrap+ deriving Eq -selectOp :: OperatorInfo-selectOp = getSpecialOperator NSelectOp+needsParens+  :: WrapMode+  -> NOperatorDef+  -> NOperatorDef+  -> Bool+needsParens mode host sub =+  getOpPrecedence host > getOpPrecedence sub+  || bool+    False+    ( NAssoc /=  getOpAssoc      host+      && on (==) getOpAssoc      host sub+      && on (==) getOpPrecedence host sub+    )+    (ProcessAllWrap == mode) -hasAttrOp :: OperatorInfo-hasAttrOp = getSpecialOperator NHasAttrOp+maybeWrapDoc :: WrapMode -> NOperatorDef -> NixDoc ann -> Doc ann+maybeWrapDoc mode host sub =+  bool+    parens+    id+    (needsParens mode host (rootOp sub))+    (getDoc sub) -wrapParens :: OperatorInfo -> NixDoc -> Doc-wrapParens op sub-  | precedence (rootOp sub) < precedence op = withoutParens sub-  | precedence (rootOp sub) == precedence op-    && associativity (rootOp sub) == associativity op-    && associativity op /= NAssocNone = withoutParens sub-  | otherwise = parens $ withoutParens sub+-- | Determine if to return doc wraped into parens,+-- according the given operator.+wrap :: NOperatorDef -> NixDoc ann -> Doc ann+wrap = maybeWrapDoc ProcessAllWrap +precedenceWrap :: NOperatorDef -> NixDoc ann -> Doc ann+precedenceWrap = maybeWrapDoc PrecedenceWrap+ -- Used in the selector case to print a path in a selector as -- "${./abc}"-wrapPath :: OperatorInfo -> NixDoc -> Doc+wrapPath :: NOperatorDef -> NixDoc ann -> Doc ann wrapPath op sub =-  if wasPath sub then dquotes (text "$" <> braces (withoutParens sub))-                else wrapParens op sub+  bool+    (wrap op sub)+    (dquotes $ antiquote sub)+    (wasPath sub) -prettyString :: NString NixDoc -> Doc-prettyString (DoubleQuoted parts) = dquotes . hcat . map prettyPart $ parts-  where prettyPart (Plain t)      = text . concatMap escape . unpack $ t-        prettyPart EscapedNewline = text "''\\n"-        prettyPart (Antiquoted r) = text "$" <> braces (withoutParens r)-        escape '"' = "\\\""-        escape x = maybe [x] (('\\':) . (:[])) $ toEscapeCode x-prettyString (Indented _ parts)-  = group $ nest 2 (squote <> squote <$$> content) <$$> squote <> squote+-- | Handle Output representation of the string escape codes.+prettyString :: NString (NixDoc ann) -> Doc ann+prettyString (DoubleQuoted parts) =+  dquotes $ foldMap prettyPart parts  where-  content = vsep . map prettyLine . stripLastIfEmpty . splitLines $ parts-  stripLastIfEmpty = reverse . f . reverse where-    f ([Plain t] : xs) | Text.null (strip t) = xs-    f xs = xs-  prettyLine = hcat . map prettyPart-  prettyPart (Plain t) = text . unpack . replace "${" "''${" . replace "''" "'''" $ t-  prettyPart EscapedNewline = text "\\n"-  prettyPart (Antiquoted r) = text "$" <> braces (withoutParens r)+  prettyPart (Plain t)      = pretty $ escapeString t+  prettyPart EscapedNewline = "''\\n"+  prettyPart (Antiquoted r) = antiquote r+prettyString (Indented _ parts) =+  group $ nest 2 $ vcat ["''", content, "''"]+ where+  content = vsep . fmap prettyLine . stripLastIfEmpty . splitLines $ parts+  stripLastIfEmpty :: [[Antiquoted Text r]] -> [[Antiquoted Text r]]+  stripLastIfEmpty =+    filter flt+   where+    flt :: [Antiquoted Text r] -> Bool+    flt [Plain t] | Text.null (strip t) = False+    flt _ = True -prettyParams :: Params NixDoc -> Doc-prettyParams (Param n) = text $ unpack n-prettyParams (ParamSet s v mname) = prettyParamSet s v <> case mname of-  Nothing -> empty-  Just name | Text.null name -> empty-            | otherwise -> text "@" <> text (unpack name)+  prettyLine :: [Antiquoted Text (NixDoc ann)] -> Doc ann+  prettyLine =+    hcat . fmap prettyPart+   where+    prettyPart :: Antiquoted Text (NixDoc ann) -> Doc ann+    prettyPart (Plain t) =+      pretty . replace "${" "''${" . replace "''" "'''" $ t+    prettyPart EscapedNewline = "\\n"+    prettyPart (Antiquoted r) = antiquote r -prettyParamSet :: ParamSet NixDoc -> Bool -> Doc-prettyParamSet args var =-    encloseSep (lbrace <> space) (align (space <> rbrace)) sep (map prettySetArg args ++ prettyVariadic)-  where-    prettySetArg (n, maybeDef) = case maybeDef of-      Nothing -> text (unpack n)-      Just v -> text (unpack n) <+> text "?" <+> withoutParens v-    prettyVariadic = [text "..." | var]-    sep = align (comma <> space)+prettyVarName :: VarName -> Doc ann+prettyVarName = pretty @Text . coerce -prettyBind :: Binding NixDoc -> Doc+prettyParams :: Params (NixDoc ann) -> Doc ann+prettyParams (Param n           ) = prettyVarName n+prettyParams (ParamSet mname variadic pset) =+  prettyParamSet variadic pset <>+    toDoc `whenJust` mname+ where+  toDoc :: VarName -> Doc ann+  toDoc (coerce -> name) =+    ("@" <> pretty name) `whenFalse` Text.null name++prettyParamSet :: forall ann . Variadic -> ParamSet (NixDoc ann) -> Doc ann+prettyParamSet variadic args =+  encloseSep+    "{ "+    (align " }")+    (align ", ")+    (fmap prettySetArg args <> one "..." `whenTrue` (variadic == Variadic))+ where+  prettySetArg :: (VarName, Maybe (NixDoc ann)) -> Doc ann+  prettySetArg (n, maybeDef) =+    (prettyVarName n <>) $ ((" ? " <>) . getDoc) `whenJust` maybeDef++prettyBind :: Binding (NixDoc ann) -> Doc ann prettyBind (NamedVar n v _p) =-    prettySelector n <+> equals <+> withoutParens v <> semi-prettyBind (Inherit s ns _p)-  = text "inherit" <+> scope <> align (fillSep (map prettyKeyName ns)) <> semi- where scope = maybe empty ((<> space) . parens . withoutParens) s+  prettySelector n <> " = " <> getDoc v <> ";"+prettyBind (Inherit s ns _p) =+  "inherit " <> scope <> align (fillSep $ prettyVarName <$> ns) <> ";"+ where+  scope =+    ((<> " ") . parens . getDoc) `whenJust` s -prettyKeyName :: NKeyName NixDoc -> Doc-prettyKeyName (StaticKey "") = dquotes $ text ""-prettyKeyName (StaticKey key)-  | HashSet.member key reservedNames = dquotes $ text $ unpack key-prettyKeyName (StaticKey key) = text . unpack $ key+prettyKeyName :: NKeyName (NixDoc ann) -> Doc ann+prettyKeyName (StaticKey key) =+  bool+    "\"\""+    (bool+      id+      dquotes+      (HashSet.member key reservedNames)+      (prettyVarName key)+    )+    (not $ Text.null $ coerce key) prettyKeyName (DynamicKey key) =-    runAntiquoted (DoubleQuoted [Plain "\n"])-        prettyString ((text "$" <>) . braces . withoutParens) key+  runAntiquoted+    (DoubleQuoted $ one $ Plain "\n")+    prettyString+    antiquote+    key -prettySelector :: NAttrPath NixDoc -> Doc-prettySelector = hcat . punctuate dot . map prettyKeyName . NE.toList+prettySelector :: NAttrPath (NixDoc ann) -> Doc ann+prettySelector = hcat . punctuate "." . fmap prettyKeyName . NE.toList -prettyAtom :: NAtom -> NixDoc-prettyAtom atom = simpleExpr $ text $ unpack $ atomText atom+prettyAtom :: NAtom -> NixDoc ann+prettyAtom = simpleExpr . pretty . atomText -prettyNix :: NExpr -> Doc-prettyNix = withoutParens . cata exprFNixDoc+prettyNix :: NExpr -> Doc ann+prettyNix = getDoc . foldFix exprFNixDoc -prettyOriginExpr :: NExprLocF (Maybe (NValue m)) -> Doc-prettyOriginExpr = withoutParens . go-  where-    go = exprFNixDoc . annotated . getCompose . fmap render+prettyOriginExpr+  :: forall t f m ann+   . HasCitations1 m (NValue t f m) f+  => NExprLocF (Maybe (NValue t f m))+  -> Doc ann+prettyOriginExpr = getDoc . go+ where+  go :: NExprLocF (Maybe (NValue t f m)) -> NixDoc ann+  go = exprFNixDoc . stripAnnF . fmap render+   where+    render :: Maybe (NValue t f m) -> NixDoc ann+    render Nothing = simpleExpr "_"+    render (Just (Free (reverse . citations @m -> p:_))) = go (getOriginExpr p)+    render _       = simpleExpr "?"+      -- render (Just (NValue (citations -> ps))) =+          -- simpleExpr $ foldr ((\x y -> vsep [x, y]) . parens . indent 2 . getDoc+          --                           . go . originExpr)+          --     mempty (reverse ps) -    render Nothing = simpleExpr $ text "_"-    render (Just (NValue (reverse -> p:_) _)) = go (_originExpr p)-    render (Just (NValue _ _)) = simpleExpr $ text "?"-        -- simpleExpr $ foldr ((<$>) . parens . indent 2 . withoutParens-        --                           . go . originExpr)-        --     mempty (reverse ps)+-- | Takes original expression from inside provenance information.+-- Prettifies that expression.+prettyExtractFromProvenance+  :: forall t f m ann+   . HasCitations1 m (NValue t f m) f+  => [Provenance m (NValue t f m)] -> Doc ann+prettyExtractFromProvenance =+  sep .+    fmap (prettyOriginExpr . getOriginExpr) -exprFNixDoc :: NExprF NixDoc -> NixDoc+exprFNixDoc :: forall ann . NExprF (NixDoc ann) -> NixDoc ann exprFNixDoc = \case-    NConstant atom -> prettyAtom atom-    NStr str -> simpleExpr $ prettyString str-    NList [] -> simpleExpr $ lbracket <> rbracket-    NList xs -> simpleExpr $ group $-        nest 2 (vsep $ lbracket : map (wrapParens appOpNonAssoc) xs) <$> rbracket-    NSet [] -> simpleExpr $ lbrace <> rbrace-    NSet xs -> simpleExpr $ group $-        nest 2 (vsep $ lbrace : map prettyBind xs) <$> rbrace-    NRecSet [] -> simpleExpr $ recPrefix <> lbrace <> rbrace-    NRecSet xs -> simpleExpr $ group $-        nest 2 (vsep $ recPrefix <> lbrace : map prettyBind xs) <$> rbrace-    NAbs args body -> leastPrecedence $-        nest 2 ((prettyParams args <> colon) <$> withoutParens body)-    NBinary NApp fun arg ->-        mkNixDoc (wrapParens appOp fun <+> wrapParens appOpNonAssoc arg) appOp-    NBinary op r1 r2 -> flip mkNixDoc opInfo $ hsep-        [ wrapParens (f NAssocLeft) r1-        , text $ unpack $ operatorName opInfo-        , wrapParens (f NAssocRight) r2+  NConstant atom -> prettyAtom atom+  NStr      str  -> simpleExpr $ prettyString str+  NList xs ->+    prettyContainer "[" (precedenceWrap appOpDef) "]" xs+  NSet NonRecursive xs ->+    prettyContainer "{" prettyBind "}" xs+  NSet Recursive xs ->+    prettyContainer "rec {" prettyBind "}" xs+  NAbs args body ->+    leastPrecedence $+      nest 2 $+        vsep+          [ prettyParams args <> ":"+          , getDoc body+          ]+  NApp fun arg ->+    mkNixDoc appOpDef (wrap appOpDef fun <> " " <> precedenceWrap appOpDef arg)+  NBinary op r1 r2 ->+    mkNixDoc+      opDef $+      hsep+        [ pickWrapMode NAssocLeft r1+        , pretty @Text $ coerce @NOpName $ getOpName op+        , pickWrapMode NAssocRight r2         ]-      where-        opInfo = getBinaryOperator op-        f x | associativity opInfo /= x = opInfo { associativity = NAssocNone }-            | otherwise = opInfo-    NUnary op r1 ->-        mkNixDoc (text (unpack (operatorName opInfo)) <> wrapParens opInfo r1) opInfo-      where opInfo = getUnaryOperator op-    NSelect r attr o ->-      (if isJust o then leastPrecedence else flip mkNixDoc selectOp) $-          wrapPath selectOp r <> dot <> prettySelector attr <> ordoc-      where ordoc = maybe empty (((space <> text "or") <+>) . wrapParens selectOp) o-    NHasAttr r attr ->-        mkNixDoc (wrapParens hasAttrOp r <+> text "?" <+> prettySelector attr) hasAttrOp-    NEnvPath p -> simpleExpr $ text ("<" ++ p ++ ">")-    NLiteralPath p -> pathExpr $ text $ case p of-        "./" -> "./."-        "../" -> "../."-        ".." -> "../."-        txt | "/" `isPrefixOf` txt -> txt-            | "~/" `isPrefixOf` txt -> txt-            | "./" `isPrefixOf` txt -> txt-            | "../" `isPrefixOf` txt -> txt-            | otherwise -> "./" ++ txt-    NSym name -> simpleExpr $ text (unpack name)-    NLet binds body -> leastPrecedence $ group $ text "let" <$> indent 2 (-        vsep (map prettyBind binds)) <$> text "in" <+> withoutParens body-    NIf cond trueBody falseBody -> leastPrecedence $-        group $ nest 2 $ (text "if" <+> withoutParens cond) <$>-          (  align (text "then" <+> withoutParens trueBody)-         <$> align (text "else" <+> withoutParens falseBody)-          )-    NWith scope body -> leastPrecedence $-        text "with"  <+> withoutParens scope <> semi <$> align (withoutParens body)-    NAssert cond body -> leastPrecedence $-        text "assert" <+> withoutParens cond <> semi <$> align (withoutParens body)-  where-    recPrefix = text "rec" <> space+   where+    opDef = getOpDef op -prettyNValueNF :: Functor m => NValueNF m -> Doc-prettyNValueNF = prettyNix . valueToExpr-  where valueToExpr :: Functor m => NValueNF m -> NExpr-        valueToExpr = transport go+    pickWrapMode :: NAssoc -> NixDoc ann -> Doc ann+    pickWrapMode x =+      bool+        wrap+        precedenceWrap+        (getOpAssoc opDef /= x)+        opDef+  NUnary op r1 ->+    mkNixDoc+      opDef $+      pretty @Text (coerce $ getOpName op) <> wrap opDef r1+   where+    opDef = getOpDef op+  NSelect o r' attr ->+    maybe+      (mkNixDoc selectOp)+      (const leastPrecedence)+      o+      $ wrapPath selectOp (mkNixDoc selectOp (wrap appOpDef r')) <> "." <> prettySelector attr <>+        ((" or " <>) . precedenceWrap appOpDef) `whenJust` o+   where+    selectOp :: NOperatorDef+    selectOp = getOpDef NSelectOp -        go (NVConstantF a) = NConstant a-        go (NVStrF t _) = NStr (DoubleQuoted [Plain t])-        go (NVListF l) = NList l-        go (NVSetF s p) = NSet-            [ NamedVar (StaticKey k :| []) v (fromMaybe nullPos (M.lookup k p))-            | (k, v) <- toList s ]-        go (NVClosureF _ _) = NSym . pack $ "<closure>"-        go (NVPathF p) = NLiteralPath p-        go (NVBuiltinF name _) = NSym $ Text.pack $ "builtins." ++ name+  NHasAttr r attr ->+    mkNixDoc hasAttrOp (wrap hasAttrOp r <> " ? " <> prettySelector attr)+   where+    hasAttrOp :: NOperatorDef+    hasAttrOp = getOpDef NHasAttrOp -printNix :: Functor m => NValueNF m -> String-printNix = cata phi-  where phi :: NValueF m String -> String-        phi (NVConstantF a) = unpack $ atomText a-        phi (NVStrF t _) = show t-        phi (NVListF l) = "[ " ++ unwords l ++ " ]"-        phi (NVSetF s _) =-            "{ " ++ concat [ unpack k ++ " = " ++ v ++ "; "-                           | (k, v) <- sort $ toList s ] ++ "}"-        phi NVClosureF {} = "<<lambda>>"-        phi (NVPathF fp) = fp-        phi (NVBuiltinF name _) = "<<builtin " ++ name ++ ">>"+  NEnvPath     p -> simpleExpr $ pretty @String $ "<" <> coerce p <> ">"+  NLiteralPath p ->+    pathExpr $+      pretty @FilePath $ coerce $+        case p of+          "./"  -> "./."+          "../" -> "../."+          ".."  -> "../."+          path  ->+            bool+              ("./" <> path)+              path+              (any (`isPrefixOf` coerce path) ["/", "~/", "./", "../"])+  NSym name -> simpleExpr $ prettyVarName name+  NLet binds body ->+    leastPrecedence $+      group $+        vsep+          [ "let"+          , indent 2 (vsep $ fmap prettyBind binds)+          , "in " <> getDoc body+          ]+  NIf cond trueBody falseBody ->+    leastPrecedence $+      group $+        nest 2 ifThenElse+   where+    ifThenElse :: Doc ann+    ifThenElse =+      sep+        [         "if "   <> getDoc cond+        , align $ "then " <> getDoc trueBody+        , align $ "else " <> getDoc falseBody+        ]+  NWith scope body ->+    prettyAddScope "with " scope body+  NAssert cond body ->+    prettyAddScope "assert " cond body+  NSynHole name -> simpleExpr $ pretty @Text ("^" <> coerce name)+ where+  prettyContainer h f t c =+    handlePresence+      (simpleExpr (h <> t))+      (const $ simpleExpr $ group $ nest 2 (h <> line <> vsep (f <$> c)) <> line <> t)+      c -removeEffects :: Functor m => NValueF m (NThunk m) -> NValueNF m-removeEffects = Fix . fmap dethunk-  where-    dethunk (NThunk _ (Value v)) = removeEffects (_baseValue v)-    dethunk (NThunk _ _) = Fix $ NVStrF "<thunk>" mempty+  prettyAddScope h c b =+    leastPrecedence $+      vsep+        [h <> getDoc c <> ";", align $ getDoc b] -removeEffectsM :: MonadVar m => NValueF m (NThunk m) -> m (NValueNF m)-removeEffectsM = fmap Fix . traverse dethunk -prettyNValueF :: MonadVar m => NValueF m (NThunk m) -> m Doc-prettyNValueF = fmap prettyNValueNF . removeEffectsM+valueToExpr :: forall t f m . MonadDataContext f m => NValue t f m -> NExpr+valueToExpr = iterNValueByDiscardWith thk (Fix . phi)+ where+  thk = Fix . NSym $ "<expr>" -prettyNValue :: MonadVar m => NValue m -> m Doc-prettyNValue (NValue _ v) = prettyNValueF v+  phi :: NValue' t f m NExpr -> NExprF NExpr+  phi (NVConstant' a     ) = NConstant a+  phi (NVStr'      ns    ) = NStr $ DoubleQuoted $ one $ Plain $ ignoreContext ns+  phi (NVList'     l     ) = NList l+  phi (NVSet'      p    s) = NSet mempty+    [ NamedVar (one $ StaticKey k) v (fromMaybe nullPos $ (`M.lookup` p) k)+    | (k, v) <- toList s+    ]+  phi (NVClosure'  _    _) = NSym "<closure>"+  phi (NVPath'     p     ) = NLiteralPath p+  phi (NVBuiltin'  name _) = NSym $ coerce ((mappend @Text) "builtins.") name -prettyNValueProv :: MonadVar m => NValue m -> m Doc-prettyNValueProv = \case-    NValue [] v -> prettyNValueF v-    NValue ps v -> do-        v' <- prettyNValueF v-        pure $ v' </> indent 2 (parens (mconcat-            (text "from: " : map (prettyOriginExpr . _originExpr) ps)))+prettyNValue+  :: forall t f m ann . MonadDataContext f m => NValue t f m -> Doc ann+prettyNValue = prettyNix . valueToExpr -prettyNThunk :: MonadVar m => NThunk m -> m Doc-prettyNThunk = \case-    t@(NThunk ps _) -> do-        v' <- fmap prettyNValueNF (dethunk t)-        pure $ v' </> indent 2 (parens (mconcat-            (text "thunk from: " : map (prettyOriginExpr . _originExpr) ps)))+-- | During the output, which can print only representation of value,+-- lazy thunks need to looked into & so - be evaluated (*sic)+-- This type is a simple manual witness "is the thunk gets shown".+data ValueOrigin = WasThunk | Value+ deriving Eq -dethunk :: MonadVar m => NThunk m -> m (NValueNF m)-dethunk = \case-    NThunk _ (Value v) -> removeEffectsM (_baseValue v)-    NThunk _ (Thunk _ active ref) -> do-        nowActive <- atomicModifyVar active (True,)-        if nowActive-            then pure $ Fix $ NVStrF "<thunk>" mempty-            else do-                eres <- readVar ref-                case eres of-                    Computed v -> removeEffectsM (_baseValue v)-                    _ -> pure $ Fix $ NVStrF "<thunk>" mempty+prettyProv+  :: forall t f m ann+   . ( HasCitations m (NValue t f m) t+     , HasCitations1 m (NValue t f m) f+     , MonadThunk t m (NValue t f m)+     , MonadDataContext f m+     )+  => ValueOrigin  -- ^ Was thunk?+  -> NValue t f m+  -> Doc ann+prettyProv wasThunk v =+  handlePresence+    id+    (\ ps pv ->+      fillSep+        [ pv+        , indent 2 $+          "(" <> ("thunk " `whenTrue` (wasThunk == WasThunk) <> "from: " <> prettyExtractFromProvenance ps) <> ")"+        ]+    )+    (citations @m @(NValue t f m) v)+    (prettyNValue v)++prettyNValueProv+  :: forall t f m ann+   . ( HasCitations m (NValue t f m) t+     , HasCitations1 m (NValue t f m) f+     , MonadThunk t m (NValue t f m)+     , MonadDataContext f m+     )+  => NValue t f m+  -> Doc ann+prettyNValueProv =+  prettyProv Value++prettyNThunk+  :: forall t f m ann+   . ( HasCitations m (NValue t f m) t+     , HasCitations1 m (NValue t f m) f+     , MonadThunk t m (NValue t f m)+     , MonadDataContext f m+     )+  => t+  -> m (Doc ann)+prettyNThunk t =+  prettyProv WasThunk <$> dethunk t++-- | This function is used only by the testing code.+printNix :: forall t f m . MonadDataContext f m => NValue t f m -> Text+printNix =+  iterNValueByDiscardWith thunkStubText phi+ where+  phi :: NValue' t f m Text -> Text+  phi (NVConstant' a ) = atomText a+  phi (NVStr'      ns) = "\"" <> escapeString (ignoreContext ns) <> "\""+  phi (NVList'     l ) = "[ " <> unwords l <> " ]"+  phi (NVSet' _ s) =+    "{ " <>+      fold+        [ check k <> " = " <> v <> "; "+        | (coerce -> k, v) <- sort $ toList s+        ] <> "}"+   where+    check :: Text -> Text+    check v =+      fromMaybe+        v+        (tryRead @Int <|> tryRead @Float)+     where+      tryRead :: forall a . (Read a, Show a) => Maybe Text+      tryRead = fmap ((\ s -> "\"" <> s <> "\"") . show) $ readMaybe @a $ toString v+  phi NVClosure'{}        = "<<lambda>>"+  phi (NVPath' fp       ) = fromString $ coerce fp+  phi (NVBuiltin' name _) = "<<builtin " <> coerce name <> ">>"
src/Nix/Reduce.hs view
@@ -1,27 +1,13 @@-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE ApplicativeDo #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DeriveFoldable #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE DeriveTraversable #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE MultiWayIf #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE PartialTypeSignatures #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE ViewPatterns #-}+{-# language CPP #-}+{-# language AllowAmbiguousTypes #-}+{-# language ConstraintKinds #-}+{-# language GeneralizedNewtypeDeriving #-}+{-# language PartialTypeSignatures #-}+{-# language TypeFamilies #-} -{-# OPTIONS_GHC -fno-warn-name-shadowing #-}-{-# OPTIONS_GHC -Wno-orphans #-}+{-# options_ghc -fno-warn-name-shadowing #-} + -- | This module provides a "reducing" expression evaluator, which reduces --   away pure, non self-referential aspects of an expression tree, yielding a --   new expression tree. It does not yet attempt to reduce everything@@ -29,381 +15,474 @@ --   original. It should be seen as an opportunistic simplifier, but which --   gives up easily if faced with any potential for ambiguity in the result. -module Nix.Reduce (reduceExpr, reducingEvalExpr) where+module Nix.Reduce+  ( reduceExpr+  , reducingEvalExpr+  ) where -import           Control.Applicative-import           Control.Arrow (second)-import           Control.Monad-import           Control.Monad.Catch-import           Control.Monad.Fix-import           Control.Monad.IO.Class-import           Control.Monad.Reader-import           Control.Monad.State.Strict-import           Control.Monad.Trans.Reader (ReaderT(..))-import           Control.Monad.Trans.State.Strict (StateT(..))-import           Data.Fix--- import           Data.Foldable-import           Data.HashMap.Lazy (HashMap)-import qualified Data.HashMap.Lazy as M--- import           Data.HashSet (HashSet)--- import qualified Data.HashSet as S-import           Data.IORef-import           Data.List.NonEmpty (NonEmpty(..))-import qualified Data.List.NonEmpty as NE-import           Data.Maybe (fromMaybe, mapMaybe, catMaybes)-import           Data.Text (Text)+import           Nix.Prelude+import           Control.Monad.Catch            ( MonadCatch(catch) )+#if !MIN_VERSION_base(4,12,0)+import           Prelude                 hiding ( fail )+import           Control.Monad.Fail+#endif+import           Control.Monad.Fix              ( MonadFix )+import           Data.Fix                       ( Fix(..)+                                                , foldFix+                                                , foldFixM+                                                )+import qualified Data.HashMap.Internal         as HM+                                                ( lookup+                                                , insert+                                                , singleton+                                                , fromList+                                                )+import qualified Data.List.NonEmpty            as NE+import qualified Text.Show import           Nix.Atoms-import           Nix.Exec-import           Nix.Expr+import           Nix.Effects.Basic              ( pathToDefaultNixFile )+import           Nix.Expr.Types+import           Nix.Expr.Types.Annotated import           Nix.Frames-import           Nix.Options (Options, reduceSets, reduceLists)+import           Nix.Options                    ( Options+                                                , isReduceSets+                                                , isReduceLists+                                                , askOptions+                                                ) import           Nix.Parser import           Nix.Scope-import           Nix.Utils import           System.Directory-import           System.FilePath  newtype Reducer m a = Reducer-    { runReducer :: ReaderT (Maybe FilePath, Scopes (Reducer m) NExprLoc)-                           (StateT (HashMap FilePath NExprLoc) m) a }-    deriving (Functor, Applicative, Alternative, Monad, MonadPlus,-              MonadFix, MonadIO,-              MonadReader (Maybe FilePath, Scopes (Reducer m) NExprLoc),-              MonadState (HashMap FilePath NExprLoc))+    { runReducer ::+        ReaderT+          ( Maybe Path+          , Scopes (Reducer m) NExprLoc+          )+          ( StateT+              ( HashMap Path NExprLoc+              , HashMap Text Text+              )+            m+          )+          a+    }+  deriving+    ( Functor, Applicative, Alternative+    , Monad, MonadPlus, MonadFix, MonadIO, MonadFail+    , MonadReader (Maybe Path, Scopes (Reducer m) NExprLoc)+    , MonadState (HashMap Path NExprLoc, HashMap Text Text)+    )  staticImport-    :: forall e m.-      (MonadIO m, Scoped e NExprLoc m,-       MonadReader (Maybe FilePath, Scopes m NExprLoc) m,-       MonadState (HashMap FilePath NExprLoc) m)-    => SrcSpan -> FilePath -> m NExprLoc-staticImport pann path = do+  :: forall m+   . ( MonadIO m+     , Scoped NExprLoc m+     , MonadFail m+     , MonadReader (Maybe Path, Scopes m NExprLoc) m+     , MonadState (HashMap Path NExprLoc, HashMap Text Text) m+     )+  => SrcSpan+  -> Path+  -> m NExprLoc+staticImport pann path =+  do     mfile <- asks fst-    path  <- liftIO $ pathToDefaultNixFile path-    path' <- liftIO $ pathToDefaultNixFile =<< canonicalizePath-        (maybe path (\p -> takeDirectory p </> path) mfile)+    path'  <- liftIO $ pathToDefaultNixFile path+    path'' <- liftIO $ pathToDefaultNixFile =<< coerce canonicalizePath+      (maybe id ((</>) . takeDirectory) mfile path') -    imports <- get-    case M.lookup path' imports of-        Just expr -> pure expr-        Nothing -> go path'-  where-    go path = do-        liftIO $ putStrLn $ "Importing file " ++ path+    let+      importIt :: m NExprLoc+      importIt = do+        liftIO $ putStrLn $ "Importing file " <> coerce path'' -        eres <- liftIO $ parseNixFileLoc path-        case eres of-            Failure err  -> error $ "Parse failed: " ++ show err-            Success x -> do-                let pos  = SourcePos "Reduce.hs" (mkPos 1) (mkPos 1)-                    span = SrcSpan pos pos-                    cur  = NamedVar (StaticKey "__cur_file" :| [])-                        (Fix (NLiteralPath_ pann path)) pos-                    x'   = Fix (NLet_ span [cur] x)-                modify (M.insert path x')-                local (const (Just path, emptyScopes @m @NExprLoc)) $ do-                    x'' <- cata reduce x'-                    modify (M.insert path x'')-                    return x''+        eres <- liftIO $ parseNixFileLoc path''+        either+          (\ err -> fail $ "Parse failed: " <> show err)+          (\ x -> do+            let+              pos  = join (NSourcePos "Reduce.hs") $ (coerce . mkPos) 1+              span = join SrcSpan pos+              cur  =+                NamedVar+                  (one $ StaticKey "__cur_file")+                  (NLiteralPathAnn pann path'')+                  pos+              x' = NLetAnn span (one cur) x+            modify $ first $ HM.insert path'' x'+            local+              (const (pure path'', mempty)) $+              do+                x'' <- foldFix reduce x'+                modify $ first $ HM.insert path'' x''+                pure x''+          )+          eres +    imports <- gets fst+    maybe+      importIt+      pure+      (HM.lookup path'' imports)+ -- gatherNames :: NExprLoc -> HashSet VarName--- gatherNames = cata $ \case---     NSym_ _ var -> S.singleton var---     Compose (Ann _ x) -> fold x+-- gatherNames = foldFix $ \case+--     NSymAnnF _ var -> S.singleton var+--     AnnF _ x -> fold x -reduceExpr :: MonadIO m => Maybe FilePath -> NExprLoc -> m NExprLoc-reduceExpr mpath expr-    = (`evalStateT` M.empty)-    . (`runReaderT` (mpath, emptyScopes))+reduceExpr+  :: (MonadIO m, MonadFail m) => Maybe Path -> NExprLoc -> m NExprLoc+reduceExpr mpath expr =+  (`evalStateT` mempty)+    . (`runReaderT` (mpath, mempty))     . runReducer-    $ cata reduce expr+    $ foldFix reduce expr -reduce :: forall e m.-           (MonadIO m, Scoped e NExprLoc m,-            MonadReader (Maybe FilePath, Scopes m NExprLoc) m,-            MonadState (HashMap FilePath NExprLoc) m)-       => NExprLocF (m NExprLoc) -> m NExprLoc+reduce+  :: forall m+   . ( MonadIO m+     , Scoped NExprLoc m+     , MonadFail m+     , MonadReader (Maybe Path, Scopes m NExprLoc) m+     , MonadState (HashMap Path NExprLoc, HashMap Text Text) m+     )+  => NExprLocF (m NExprLoc)+  -> m NExprLoc  -- | Reduce the variable to its value if defined. --   Leave it as it is otherwise.-reduce (NSym_ ann var) = lookupVar var <&> \case-    Nothing -> Fix (NSym_ ann var)-    Just v  -> v+reduce (NSymAnnF ann var) =+  fromMaybe (NSymAnn ann var) <$> lookupVar var  -- | Reduce binary and integer negation.-reduce (NUnary_ uann op arg) = arg >>= \x -> case (op, x) of-    (NNeg, Fix (NConstant_ cann (NInt n))) ->-        return $ Fix $ NConstant_ cann (NInt (negate n))-    (NNot, Fix (NConstant_ cann (NBool b))) ->-        return $ Fix $ NConstant_ cann (NBool (not b))-    _ -> return $ Fix $ NUnary_ uann op x+reduce (NUnaryAnnF uann op arg) =+  do+    x <- arg+    pure $+      case (op, x) of+        (NNeg, NConstantAnn cann (NInt  n)) -> NConstantAnn cann $ NInt $ negate n+        (NNot, NConstantAnn cann (NBool b)) -> NConstantAnn cann $ NBool $ not b+        _                                   -> NUnaryAnn    uann op x  -- | Reduce function applications. -- --     * Reduce an import to the actual imported expression. -- --     * Reduce a lambda function by adding its name to the local---       scope and recursively reducing its body. -reduce (NBinary_ bann NApp fun arg) = fun >>= \case-    f@(Fix (NSym_ _ "import")) -> arg >>= \case-        -- Fix (NEnvPath_     pann origPath) -> staticImport pann origPath-        Fix (NLiteralPath_ pann origPath) -> staticImport pann origPath-        v -> return $ Fix $ NBinary_ bann NApp f v+--       scope and recursively reducing its body.+reduce (NAppAnnF bann fun arg) =+  (\case+    f@(NSymAnn _ "import") ->+      (\case+          -- NEnvPathAnn     pann origPath -> staticImport pann origPath+        NLiteralPathAnn pann origPath -> staticImport pann origPath+        v -> pure $ NAppAnn bann f v+      ) =<< arg -    Fix (NAbs_ _ (Param name) body) -> do+    NAbsAnn _ (Param name) body ->+      do         x <- arg-        pushScope (M.singleton name x) (cata reduce body)+        pushScope+          (coerce $ HM.singleton name x)+          (foldFix reduce body) -    f -> Fix . NBinary_ bann NApp f <$> arg+    f -> NAppAnn bann f <$> arg+  ) =<< fun  -- | Reduce an integer addition to its result.-reduce (NBinary_ bann op larg rarg) = do+reduce (NBinaryAnnF bann op larg rarg) =+  do     lval <- larg     rval <- rarg-    case (op, lval, rval) of-        (NPlus, Fix (NConstant_ ann (NInt x)), Fix (NConstant_ _ (NInt y))) ->-            return $ Fix (NConstant_ ann (NInt (x + y)))-        _ -> pure $ Fix $ NBinary_ bann op lval rval+    pure $+      case (op, lval, rval) of+        (NPlus, NConstantAnn ann (NInt x), NConstantAnn _ (NInt y)) -> NConstantAnn ann  $ NInt $ x + y+        _                                                           -> NBinaryAnn   bann op lval rval --- | Reduce a select on a Set by substituing the set to the selected value.+-- | Reduce a select on a Set by substituting the set to the selected value. -- -- Before applying this reduction, we need to ensure that: -- --   1. The selected expr is indeed a set. --   2. The selection AttrPath is a list of StaticKeys. --   3. The selected AttrPath exists in the set.-reduce base@(NSelect_ _ _ attrs _)-    | sAttrPath $ NE.toList attrs = do-      (NSelect_ _ aset attrs _) <- sequence base-      inspectSet (unFix aset) attrs-    | otherwise = sId-  where-    sId = Fix <$> sequence base-    -- The selection AttrPath is composed of StaticKeys.-    sAttrPath (StaticKey _:xs) = sAttrPath xs-    sAttrPath []               = True-    sAttrPath _                = False-    -- Find appropriate bind in set's binds.-    findBind [] _                = Nothing-    findBind (x:xs) attrs@(a:|_) = case x of-        n@(NamedVar (a':|_) _ _) | a' == a -> Just n-        _                                  -> findBind xs attrs-    -- Follow the attrpath recursively in sets.-    inspectSet (NSet_ _ binds) attrs = case findBind binds attrs of-       Just (NamedVar _ e _) -> case NE.uncons attrs of -               (_,Just attrs) -> inspectSet (unFix e) attrs-               _              -> pure e-       _ -> sId-    inspectSet _ _ = sId+reduce base@(NSelectAnnF _ _ _ attrs)+  | sAttrPath $ NE.toList attrs = do+    (NSelectAnnF _ _ aset attrs) <- sequenceA base+    inspectSet (unFix aset) attrs+  | otherwise = sId+ where+  sId = reduceLayer base+  -- The selection AttrPath is composed of StaticKeys.+  sAttrPath (StaticKey _ : xs) = sAttrPath xs+  sAttrPath []                 = True+  sAttrPath _                  = False+  -- Find appropriate bind in set's binds.+  findBind []   _              = Nothing+  findBind (x : xs) attrs@(a :| _) = case x of+    n@(NamedVar (a' :| _) _ _) | a' == a -> pure n+    _ -> findBind xs attrs+  -- Follow the attrpath recursively in sets.+  inspectSet (NSetAnnF _ NonRecursive binds) attrs = case findBind binds attrs of+    Just (NamedVar _ e _) -> case NE.uncons attrs of+      (_, Just attrs) -> inspectSet (unFix e) attrs+      _               -> pure e+    _ -> sId+  inspectSet _ _ = sId  -- reduce (NHasAttr aset attr) =  -- | Reduce a set by inlining its binds outside of the set --   if none of the binds inherit the super set.-reduce e@(NSet_ ann binds) = do-    let usesInherit = flip any binds $ \case-            Inherit {} -> True-            _ -> False-    if usesInherit-        then clearScopes @NExprLoc $-            Fix . NSet_ ann <$> traverse sequence binds-        else Fix <$> sequence e+reduce e@(NSetAnnF ann r binds) =+  bool+    -- Encountering a 'rec set' construction eliminates any hope of inlining+    -- definitions.+    mExprLoc+    (bool+      (reduceLayer e)+      mExprLoc+      usesInherit+    )+    (r == NonRecursive)+ where+  mExprLoc :: m NExprLoc+  mExprLoc =+    clearScopes @NExprLoc $ NSetAnn ann r <$> traverse sequenceA binds --- Encountering a 'rec set' construction eliminates any hope of inlining--- definitions.-reduce (NRecSet_ ann binds) =-    clearScopes @NExprLoc $ Fix . NRecSet_ ann <$> traverse sequence binds+  usesInherit =+    any+      (\case+        Inherit{} -> True+        _         -> False+      )+      binds  -- Encountering a 'with' construction eliminates any hope of inlining -- definitions.-reduce (NWith_ ann scope body) =-    clearScopes @NExprLoc $ fmap Fix $ NWith_ ann <$> scope <*> body+reduce (NWithAnnF ann scope body) =+  clearScopes @NExprLoc $ liftA2 (NWithAnn ann) scope body  -- | Reduce a let binds section by pushing lambdas, --   constants and strings to the body scope.-reduce (NLet_ ann binds body) = do-    s <- fmap (M.fromList . catMaybes) $ forM binds $ \case-        NamedVar (StaticKey name :| []) def _pos -> def >>= \case-            d@(Fix NAbs_ {})      -> pure $ Just (name, d)-            d@(Fix NConstant_ {}) -> pure $ Just (name, d)-            d@(Fix NStr_ {})      -> pure $ Just (name, d)+reduce (NLetAnnF ann binds body) =+  do+    binds' <- traverse sequenceA binds+    body'  <-+      (`pushScope` body) . coerce . HM.fromList . catMaybes =<<+        traverse+          (\case+            NamedVar (StaticKey name :| []) def _pos ->+              let+                defcase =+                  \case+                    d@NAbsAnn     {} -> pure (name, d)+                    d@NConstantAnn{} -> pure (name, d)+                    d@NStrAnn     {} -> pure (name, d)+                    _                -> Nothing+              in+              defcase <$> def+             _ -> pure Nothing-        _ -> pure Nothing-    body' <- pushScope s body-    binds' <- traverse sequence binds+          )+          binds+     -- let names = gatherNames body'-    -- binds' <- traverse sequence binds <&> \b -> flip filter b $ \case+    -- binds' <- traverse sequenceA binds <&> \b -> flip filter b $ \case     --     NamedVar (StaticKey name _ :| []) _ ->     --         name `S.member` names     --     _ -> True-    pure $ Fix $ NLet_ ann binds' body'-  -- where-  --   go m [] = pure m-  --   go m (x:xs) = case x of-  --       NamedVar (StaticKey name _ :| []) def -> do-  --           v <- pushScope m def-  --           go (M.insert name v m) xs-  --       _ -> go m xs+    pure $ NLetAnn ann binds' body'+    -- where+    --   go m [] = pure m+    --   go m (x:xs) = case x of+    --       NamedVar (StaticKey name _ :| []) def -> do+    --           v <- pushScope m def+    --           go (M.insert name v m) xs+    --       _ -> go m xs  -- | Reduce an if to the relevant path if --   the condition is a boolean constant.-reduce e@(NIf_ _ b t f) = b >>= \case-    Fix (NConstant_ _ (NBool b')) -> if b' then t else f-    _ -> Fix <$> sequence e+reduce e@(NIfAnnF _ b t f) =+  (\case+    NConstantAnn _ (NBool b') -> bool f t b'+    _                         -> reduceLayer e+  ) =<< b  -- | Reduce an assert atom to its encapsulated --   symbol if the assertion is a boolean constant.-reduce e@(NAssert_ _ b body) = b >>= \case-    Fix (NConstant_ _ (NBool b')) | b' -> body-    _ -> Fix <$> sequence e+reduce e@(NAssertAnnF _ b body) =+  (\case+    NConstantAnn _ (NBool True) -> body+    _ -> reduceLayer e+  ) =<< b -reduce (NAbs_ ann params body) = do-    params' <- sequence params-    -- Make sure that variable definitions in scope do not override function-    -- arguments.-    let args = case params' of-            Param name -> M.singleton name (Fix (NSym_ ann name))-            ParamSet pset _ _ ->-                M.fromList $ map (\(k, _) -> (k, Fix (NSym_ ann k))) pset-    Fix . NAbs_ ann params' <$> pushScope args body+reduce (NAbsAnnF ann params body) = do+  params' <- sequenceA params+  -- Make sure that variable definitions in scope do not override function+  -- arguments.+  let+    scope = coerce $+      case params' of+        Param    name     -> one (name, NSymAnn ann name)+        ParamSet _ _ pset ->+          HM.fromList $ (\(k, _) -> (k, NSymAnn ann k)) <$> pset+  NAbsAnn ann params' <$> pushScope scope body -reduce v = Fix <$> sequence v+reduce v = reduceLayer v +reduceLayer :: (Traversable f1, Applicative f2) => f1 (f2 (Fix f1)) -> f2 (Fix f1)+reduceLayer v = Fix <$> sequenceA v+ -- newtype FlaggedF f r = FlaggedF { flagged :: (IORef Bool, f r) } newtype FlaggedF f r = FlaggedF (IORef Bool, f r)-    deriving (Functor, Foldable, Traversable)+  deriving (Functor, Foldable, Traversable)  instance Show (f r) => Show (FlaggedF f r) where-    show (FlaggedF (_, x)) = show x+  show (FlaggedF (_, x)) = show x  type Flagged f = Fix (FlaggedF f) -flagExprLoc :: (MonadIO n, Traversable f)-            => Fix f -> n (Flagged f)-flagExprLoc = cataM $ \x -> do-    flag <- liftIO $ newIORef False-    pure $ Fix $ FlaggedF (flag, x)+flagExprLoc :: (MonadIO n, Traversable f) => Fix f -> n (Flagged f)+flagExprLoc = foldFixM $ \x -> do+  flag <- liftIO $ newIORef False+  pure $ coerce (flag, x)  -- stripFlags :: Functor f => Flagged f -> Fix f--- stripFlags = cata $ Fix . snd . flagged+-- stripFlags = foldFix $ Fix . snd . flagged  pruneTree :: MonadIO n => Options -> Flagged NExprLocF -> n (Maybe NExprLoc)-pruneTree opts = cataM $ \(FlaggedF (b, Compose x)) -> do-    used <- liftIO $ readIORef b-    pure $ if used-           then Fix . Compose <$> traverse prune x-           else Nothing-  where-    prune :: NExprF (Maybe NExprLoc) -> Maybe (NExprF NExprLoc)-    prune = \case-        NStr str                  -> Just $ NStr (pruneString str)-        NHasAttr (Just aset) attr -> Just $ NHasAttr aset (NE.map pruneKeyName attr)-        NAbs params (Just body)   -> Just $ NAbs (pruneParams params) body--        NList l       | reduceLists opts -> Just $ NList   (catMaybes l)-                      | otherwise        -> Just $ NList   (map (fromMaybe nNull) l)-        NSet binds    | reduceSets opts  -> Just $ NSet    (mapMaybe sequence binds)-                      | otherwise        -> Just $ NSet    (map (fmap (fromMaybe nNull)) binds)-        NRecSet binds | reduceSets opts  -> Just $ NRecSet (mapMaybe sequence binds)-                      | otherwise        -> Just $ NRecSet (map (fmap (fromMaybe nNull)) binds)+pruneTree opts =+  foldFixM $+    \(FlaggedF (b, Compose x)) ->+      bool+        Nothing+        (annUnitToAnn <$> traverse prune x)+        <$> liftIO (readIORef b)+ where+  prune :: NExprF (Maybe NExprLoc) -> Maybe (NExprF NExprLoc)+  prune = \case+    NStr str -> pure $ NStr $ pruneString str+    NHasAttr (Just aset) attr ->+      pure $ NHasAttr aset $ pruneKeyName <$> attr+    NAbs params (Just body) -> pure $ NAbs (pruneParams params) body -        NLet binds (Just body@(Fix (Compose (Ann _ x)))) ->-            Just $ case mapMaybe pruneBinding binds of-                [] -> x-                xs -> NLet xs body+    NList l -> pure $ NList $+      bool+        (fromMaybe annNNull <$>)+        catMaybes+        (isReduceLists opts)  -- Reduce list members that aren't used; breaks if elemAt is used+        l+    NSet recur binds -> pure $ NSet recur $+      bool+        (fromMaybe annNNull <<$>>)+        (mapMaybe sequenceA)+        (isReduceSets opts)  -- Reduce set members that aren't used; breaks if hasAttr is used+        binds -        NSelect (Just aset) attr alt ->-            Just $ NSelect aset (NE.map pruneKeyName attr) (join alt)+    NLet binds (Just body@(Ann _ x)) ->+      pure $+        handlePresence+          x+          (`NLet` body)+          (mapMaybe pruneBinding binds) -        -- These are the only short-circuiting binary operators-        NBinary NAnd (Just (Fix (Compose (Ann _ larg)))) _ -> Just larg-        NBinary NOr  (Just (Fix (Compose (Ann _ larg)))) _ -> Just larg+    NSelect alt (Just aset) attr ->+      pure $ NSelect (join alt) aset $ pruneKeyName <$> attr -        -- If the function was never called, it means its argument was in a-        -- thunk that was forced elsewhere.-        NBinary NApp Nothing (Just _) -> Nothing+    -- If the function was never called, it means its argument was in a+    -- thunk that was forced elsewhere.+    NApp Nothing (Just _) -> Nothing -        -- The idea behind emitted a binary operator where one side may be-        -- invalid is that we're trying to emit what will reproduce whatever-        -- error the user encountered, which means providing all aspects of-        -- the evaluation path they ultimately followed.-        NBinary op Nothing (Just rarg) -> Just $ NBinary op nNull rarg-        NBinary op (Just larg) Nothing -> Just $ NBinary op larg nNull+    -- These are the only short-circuiting binary operators+    NBinary NAnd (Just (Ann _ larg)) _ -> pure larg+    NBinary NOr  (Just (Ann _ larg)) _ -> pure larg -        -- If the scope of a with was never referenced, it's not needed-        NWith Nothing (Just (Fix (Compose (Ann _ body)))) -> Just body+    -- The idea behind emitted a binary operator where one side may be+    -- invalid is that we're trying to emit what will reproduce whatever+    -- fail the user encountered, which means providing all aspects of+    -- the evaluation path they ultimately followed.+    NBinary op Nothing (Just rarg) -> pure $ NBinary op annNNull rarg+    NBinary op (Just larg) Nothing -> pure $ NBinary op larg annNNull -        NAssert Nothing _ ->-            error "How can an assert be used, but its condition not?"+    -- If the scope of a with was never referenced, it's not needed+    NWith Nothing (Just (Ann _ body)) -> pure body -        NAssert _ (Just (Fix (Compose (Ann _ body)))) -> Just body-        NAssert (Just cond) _ -> Just $ NAssert cond nNull+    NAssert Nothing _              -> fail "How can an assert be used, but its condition not?"+    NAssert _ (Just (Ann _ body)) -> pure body+    NAssert (Just cond) _          -> pure $ NAssert cond annNNull -        NIf Nothing _ _ ->-            error "How can an if be used, but its condition not?"+    NIf Nothing _ _ -> fail "How can an if be used, but its condition not?" -        NIf _ Nothing (Just (Fix (Compose (Ann _ f)))) -> Just f-        NIf _ (Just (Fix (Compose (Ann _ t)))) Nothing -> Just t+    NIf _ Nothing (Just (Ann _ f)) -> pure f+    NIf _ (Just (Ann _ t)) Nothing -> pure t -        x -> sequence x+    x                     -> sequenceA x -    pruneString :: NString (Maybe NExprLoc) -> NString NExprLoc-    pruneString (DoubleQuoted xs) =-        DoubleQuoted (mapMaybe pruneAntiquotedText xs)-    pruneString (Indented n xs)   =-        Indented n (mapMaybe pruneAntiquotedText xs)+  pruneString :: NString (Maybe NExprLoc) -> NString NExprLoc+  pruneString (DoubleQuoted xs) = DoubleQuoted $ mapMaybe pruneAntiquotedText xs+  pruneString (Indented n   xs) = Indented n   $ mapMaybe pruneAntiquotedText xs -    pruneAntiquotedText-        :: Antiquoted Text (Maybe NExprLoc)-        -> Maybe (Antiquoted Text NExprLoc)-    pruneAntiquotedText (Plain v)             = Just (Plain v)-    pruneAntiquotedText EscapedNewline        = Just EscapedNewline-    pruneAntiquotedText (Antiquoted Nothing)  = Nothing-    pruneAntiquotedText (Antiquoted (Just k)) = Just (Antiquoted k)+  pruneAntiquotedText+    :: Antiquoted Text (Maybe NExprLoc) -> Maybe (Antiquoted Text NExprLoc)+  pruneAntiquotedText (Plain v)             = pure $ Plain v+  pruneAntiquotedText EscapedNewline        = pure EscapedNewline+  pruneAntiquotedText (Antiquoted (Just k)) = pure $ Antiquoted k+  pruneAntiquotedText (Antiquoted Nothing ) = Nothing -    pruneAntiquoted-        :: Antiquoted (NString (Maybe NExprLoc)) (Maybe NExprLoc)-        -> Maybe (Antiquoted (NString NExprLoc) NExprLoc)-    pruneAntiquoted (Plain v)             = Just (Plain (pruneString v))-    pruneAntiquoted EscapedNewline        = Just EscapedNewline-    pruneAntiquoted (Antiquoted Nothing)  = Nothing-    pruneAntiquoted (Antiquoted (Just k)) = Just (Antiquoted k)+  pruneAntiquoted+    :: Antiquoted (NString (Maybe NExprLoc)) (Maybe NExprLoc)+    -> Maybe (Antiquoted (NString NExprLoc) NExprLoc)+  pruneAntiquoted (Plain v)             = pure $ Plain $ pruneString v+  pruneAntiquoted EscapedNewline        = pure EscapedNewline+  pruneAntiquoted (Antiquoted (Just k)) = pure $ Antiquoted k+  pruneAntiquoted (Antiquoted Nothing ) = Nothing -    pruneKeyName :: NKeyName (Maybe NExprLoc) -> NKeyName NExprLoc-    pruneKeyName (StaticKey n) = StaticKey n-    pruneKeyName (DynamicKey k)-        | Just k' <- pruneAntiquoted k = DynamicKey k'-        | otherwise = StaticKey "<unused?>"+  pruneKeyName :: NKeyName (Maybe NExprLoc) -> NKeyName NExprLoc+  pruneKeyName (StaticKey n) = StaticKey n+  pruneKeyName (DynamicKey k) | Just k' <- pruneAntiquoted k = DynamicKey k'+                              | otherwise = StaticKey "<unused?>" -    pruneParams :: Params (Maybe NExprLoc) -> Params NExprLoc-    pruneParams (Param n) = Param n-    pruneParams (ParamSet xs b n)-        | reduceSets opts =-              ParamSet (map (second (maybe (Just nNull) Just-                                     . fmap (fromMaybe nNull))) xs) b n-        | otherwise =-              ParamSet (map (second (fmap (fromMaybe nNull))) xs) b n+  pruneParams :: Params (Maybe NExprLoc) -> Params NExprLoc+  pruneParams (Param n) = Param n+  pruneParams (ParamSet mname variadic pset) =+    ParamSet mname variadic (reduceOrPassMode <$> pset)+   where+    reduceOrPassMode =+      second $+        bool+          fmap+          ((pure .) . maybe annNNull)+          (isReduceSets opts)  -- Reduce set members that aren't used; breaks if hasAttr is used+          (fromMaybe annNNull) -    pruneBinding :: Binding (Maybe NExprLoc) -> Maybe (Binding NExprLoc)-    pruneBinding (NamedVar _ Nothing _)  = Nothing-    pruneBinding (NamedVar xs (Just x) pos) =-        Just (NamedVar (NE.map pruneKeyName xs) x pos)-    pruneBinding (Inherit _ [] _)  = Nothing-    pruneBinding (Inherit (join -> Nothing) _ _) = Nothing-    pruneBinding (Inherit (join -> m) xs pos) =-        Just (Inherit m (map pruneKeyName xs) pos)+  pruneBinding :: Binding (Maybe NExprLoc) -> Maybe (Binding NExprLoc)+  pruneBinding (NamedVar _                 Nothing  _  ) = Nothing+  pruneBinding (NamedVar xs                (Just x) pos) = pure $ NamedVar (pruneKeyName <$> xs) x pos+  pruneBinding (Inherit  _                 []       _  ) = Nothing+  pruneBinding (Inherit  (join -> Nothing) _        _  ) = Nothing+  pruneBinding (Inherit  (join -> m)       xs       pos) = pure $ Inherit m xs pos  reducingEvalExpr-    :: (Framed e m, Has e Options, Exception r, MonadCatch m, MonadIO m)-    => (NExprLocF (m a) -> m a)-    -> Maybe FilePath-    -> NExprLoc-    -> m (NExprLoc, Either r a)-reducingEvalExpr eval mpath expr = do-    expr'  <- flagExprLoc =<< liftIO (reduceExpr mpath expr)-    eres   <- catch (Right <$> cata (addEvalFlags eval) expr') (pure . Left)-    opts :: Options <- asks (view hasLens)-    expr'' <- pruneTree opts expr'-    return (fromMaybe nNull expr'', eres)-  where-    addEvalFlags k (FlaggedF (b, x)) = liftIO (writeIORef b True) *> k x+  :: (Framed e m, Has e Options, Exception r, MonadCatch m, MonadIO m)+  => (NExprLocF (m a) -> m a)+  -> Maybe Path+  -> NExprLoc+  -> m (NExprLoc, Either r a)+reducingEvalExpr eval mpath expr =+  do+    expr'           <- flagExprLoc =<< liftIO (reduceExpr mpath expr)+    eres <- (`catch` pure . Left) $+      pure <$> foldFix (addEvalFlags eval) expr'+    opts <- askOptions+    expr''          <- pruneTree opts expr'+    pure (fromMaybe annNNull expr'', eres)+ where+  addEvalFlags k (FlaggedF (b, x)) = liftIO (writeIORef b True) *> k x++instance Monad m => Scoped NExprLoc (Reducer m) where+  askScopes   = askScopesReader+  clearScopes = clearScopesReader @(Reducer m) @NExprLoc+  pushScopes  = pushScopesReader+  lookupVar   = lookupVarReader
src/Nix/Render.hs view
@@ -1,35 +1,141 @@-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}+{-# language UndecidableInstances #-}+{-# language CPP #-}+{-# language ConstraintKinds #-}+{-# language DefaultSignatures #-}+{-# language TypeFamilies #-}+{-# language TypeOperators #-}+{-# language MultiWayIf #-}  module Nix.Render where -import           Data.ByteString (ByteString)-import           Data.List.NonEmpty (NonEmpty((:|)))-import qualified Data.Set as Set-import           Data.Void+import           Nix.Prelude+import qualified Data.Set                      as Set+import           Nix.Utils.Fix1                 ( Fix1T+                                                , MonadFix1T+                                                )+import           Nix.Expr.Types                 ( NPos(..)+                                                , NSourcePos(..)+                                                ) import           Nix.Expr.Types.Annotated+import           Prettyprinter+import qualified System.Directory              as S+import qualified System.PosixCompat.Files      as S import           Text.Megaparsec.Error-import           Text.Megaparsec.Pos (SourcePos(..))-import           Text.PrettyPrint.ANSI.Leijen+import           Text.Megaparsec.Pos+import qualified Data.Text                     as Text -class Monad m => MonadFile m where-    readFile :: FilePath -> m ByteString+class (MonadFail m, MonadIO m) => MonadFile m where+    readFile :: Path -> m Text+    default readFile :: (MonadTrans t, MonadIO m', MonadFile m', m ~ t m') => Path -> m Text+    readFile = liftIO . Nix.Prelude.readFile+    listDirectory :: Path -> m [Path]+    default listDirectory :: (MonadTrans t, MonadFile m', m ~ t m') => Path -> m [Path]+    listDirectory = lift . listDirectory+    getCurrentDirectory :: m Path+    default getCurrentDirectory :: (MonadTrans t, MonadFile m', m ~ t m') => m Path+    getCurrentDirectory = lift getCurrentDirectory+    canonicalizePath :: Path -> m Path+    default canonicalizePath :: (MonadTrans t, MonadFile m', m ~ t m') => Path -> m Path+    canonicalizePath = lift . canonicalizePath+    getHomeDirectory :: m Path+    default getHomeDirectory :: (MonadTrans t, MonadFile m', m ~ t m') => m Path+    getHomeDirectory = lift getHomeDirectory+    doesPathExist :: Path -> m Bool+    default doesPathExist :: (MonadTrans t, MonadFile m', m ~ t m') => Path -> m Bool+    doesPathExist = lift . doesPathExist+    doesFileExist :: Path -> m Bool+    default doesFileExist :: (MonadTrans t, MonadFile m', m ~ t m') => Path -> m Bool+    doesFileExist = lift . doesFileExist+    doesDirectoryExist :: Path -> m Bool+    default doesDirectoryExist :: (MonadTrans t, MonadFile m', m ~ t m') => Path -> m Bool+    doesDirectoryExist = lift . doesDirectoryExist+    getSymbolicLinkStatus :: Path -> m S.FileStatus+    default getSymbolicLinkStatus :: (MonadTrans t, MonadFile m', m ~ t m') => Path -> m S.FileStatus+    getSymbolicLinkStatus = lift . getSymbolicLinkStatus -posAndMsg :: SourcePos -> Doc -> ParseError t Void-posAndMsg beg msg =-    FancyError (beg :| [])-        (Set.fromList [ErrorFail (show msg) :: ErrorFancy Void])+instance MonadFile IO where+  readFile              = Nix.Prelude.readFile+  listDirectory         = coerce S.listDirectory+  getCurrentDirectory   = coerce S.getCurrentDirectory+  canonicalizePath      = coerce S.canonicalizePath+  getHomeDirectory      = coerce S.getHomeDirectory+  doesPathExist         = coerce S.doesPathExist+  doesFileExist         = coerce S.doesFileExist+  doesDirectoryExist    = coerce S.doesDirectoryExist+  getSymbolicLinkStatus = coerce S.getSymbolicLinkStatus -renderLocation :: MonadFile m => SrcSpan -> Doc -> m Doc-renderLocation (SrcSpan beg@(SourcePos "<string>" _ _) _) msg =-    return $ text $ init $ parseErrorPretty @Char (posAndMsg beg msg) -renderLocation (SrcSpan beg@(SourcePos path _ _) _) msg = do-    contents <- Nix.Render.readFile path-    return $ text $ init $ parseErrorPretty' contents (posAndMsg beg msg)+instance (MonadFix1T t m, MonadIO (Fix1T t m), MonadFail (Fix1T t m), MonadFile m) => MonadFile (Fix1T t m)++posAndMsg :: NSourcePos -> Doc a -> ParseError s Void+posAndMsg (NSourcePos _ (coerce -> lineNo) _) msg =+  FancyError+    (unPos lineNo)+    (Set.fromList $ one (ErrorFail (show msg) :: ErrorFancy Void))++renderLocation :: MonadFile m => SrcSpan -> Doc a -> m (Doc a)+renderLocation (SrcSpan (NSourcePos file (coerce -> begLine) (coerce -> begCol)) (NSourcePos file' (coerce -> endLine) (coerce -> endCol))) msg+  | file == file' && file == "<string>" && begLine == endLine =+    pure $ "In raw input string at position " <> pretty (unPos begCol)++  | file /= "<string>" && file == file' =+    bool+      (pure msg)+      (do+        txt <- sourceContext file begLine begCol endLine endCol msg+        pure $+          vsep+            [ "In file " <> errorContext file begLine begCol endLine endCol <> ":"+            , txt+            ]+      )+      =<< doesFileExist file+renderLocation (SrcSpan beg end) msg = fail $ "Don't know how to render range from " <> show beg <>" to " <> show end <>" for fail: " <> show msg++errorContext :: Path -> Pos -> Pos -> Pos -> Pos -> Doc a+errorContext (coerce @Path @FilePath -> path) bl bc _el _ec =+  pretty path <> ":" <> pretty (unPos bl) <> ":" <> pretty (unPos bc)++sourceContext+  :: MonadFile m => Path -> Pos -> Pos -> Pos -> Pos -> Doc a -> m (Doc a)+sourceContext path (unPos -> begLine) (unPos -> _begCol) (unPos -> endLine) (unPos -> _endCol) msg+  = do+    let beg' = max 1 $ begLine - 3+        end' =         endLine + 3+    ls <-+      fmap pretty+      .   take (end' - beg')+      .   drop (pred beg')+      .   lines+      <$> Nix.Render.readFile path+    let+      longest = Text.length $ show $ beg' + length ls - 1+      pad :: Int -> Text+      pad n =+        let+          ns :: Text+          ns = show n+          nsp = Text.replicate (longest - Text.length ns) " " <> ns+        in+          if+          | n == begLine && n == endLine -> "==> " <> nsp <> " |  "+          | n >= begLine && n <= endLine -> "  > " <> nsp <> " |  "+          | otherwise                    -> "    " <> nsp <> " |  "+      composeLine n l =+        one (pretty (pad n) <> l)+        <> whenTrue+            (one $+              pretty $+                Text.replicate (Text.length (pad n) - 3) " "+                <> "|"+                <> Text.replicate (_begCol + 1) " "+                <> Text.replicate (_endCol - _begCol) "^"+            )+            (begLine == endLine && n == endLine)+        -- XXX: Consider inserting the message here when it is small enough.+        -- ATM some messages are so huge that they take prevalence over the source listing.+        -- ++ [ indent (length $ pad n) msg | n == endLine ]++      ls' = fold $ zipWith composeLine [beg' ..] ls++    pure $ vsep $ ls' <> one (indent (Text.length $ pad begLine) msg)
src/Nix/Render/Frame.hs view
@@ -1,175 +1,260 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MultiWayIf #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}+{-# language CPP #-}+{-# language AllowAmbiguousTypes #-}+{-# language ConstraintKinds #-}+{-# language MultiWayIf #-}+{-# language TypeFamilies #-} ++-- | Code for rendering/representation of the messages packaged with their context (Frames). module Nix.Render.Frame where -import           Control.Monad.Reader-import           Data.Fix-import           Data.Typeable-import           Nix.Eval+import           Nix.Prelude         hiding ( Comparison )+import           GHC.Exception              ( ErrorCall )+import           Data.Fix                   ( Fix(..) )+import           Nix.Eval            hiding ( addMetaInfo ) import           Nix.Exec-import           Nix.Expr+import           Nix.Expr.Types+import           Nix.Expr.Types.Annotated import           Nix.Frames import           Nix.Normal import           Nix.Options import           Nix.Pretty import           Nix.Render import           Nix.Thunk-import           Nix.Utils 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+import           Prettyprinter       hiding ( list )+import qualified Text.Show                 as Text+import           Text.Megaparsec.Pos        ( sourcePosPretty)+import qualified Text.Show.Pretty          as PS -renderFrames :: forall v e m.-               (MonadReader e m, Has e Options,-                MonadVar m, MonadFile m, Typeable m, Typeable v)-             => Frames -> m Doc-renderFrames [] = pure mempty-renderFrames (x:xs) = do-    opts :: Options <- asks (view hasLens)-    frames <--        if | verbose opts <= ErrorsOnly ->-             renderFrame @v x-           | verbose opts <= Informational -> do-             f <- renderFrame @v x-             pure $ concatMap go (reverse xs) ++ f-           | otherwise ->-             concat <$> mapM (renderFrame @v) (reverse (x:xs))-    pure $ case frames of-        [] -> mempty-        _  -> foldr1 (P.<$>) frames-  where-    go :: NixFrame -> [Doc]-    go f = case framePos @v @m f of-        Just pos ->-            [text "While evaluating at "-                <> text (sourcePosPretty pos)-                <> colon]-        Nothing -> []+renderFrames+  :: forall v t f e m ann+   . ( MonadReader e m+     , Has e Options+     , MonadFile m+     , MonadCitedThunks t f m+     , Typeable v+     )+  => Frames+  -> m (Doc ann)+renderFrames []       = stub+renderFrames xss@(x : xs) =+  do+    opts <- askOptions+    let+      verbosity :: Verbosity+      verbosity = getVerbosity opts+    renderedFrames <- if+        | verbosity <= ErrorsOnly -> render1 x+      --  2021-10-22: NOTE: List reverse is completely conterproductive. `reverse` of list famously neest to traverse the whole list to take the last element+        | verbosity <= Informational -> (foldMap renderPosition (reverse xs) <>) <$> render1 x+        | otherwise -> foldMapM render1 (reverse xss)+    pure $+      handlePresence+        mempty+        vsep+        renderedFrames+ where+  render1 :: NixFrame -> m [Doc ann1]+  render1 = renderFrame @v @t @f -framePos :: forall v (m :: * -> *). (Typeable m, Typeable v) => NixFrame-         -> Maybe SourcePos-framePos (NixFrame _ f)-    | Just (e :: EvalFrame m v) <- fromException f = case e of-          EvaluatingExpr _ (Fix (Compose (Ann (SrcSpan beg _) _))) ->-              Just beg-          _ -> Nothing-    | otherwise = Nothing+  renderPosition :: NixFrame -> [Doc ann]+  renderPosition =+    whenJust+      (\ pos -> one ("While evaluating at " <> pretty (sourcePosPretty $ toSourcePos pos) <> colon))+      . framePos @v @m -renderFrame :: forall v e m.-              (MonadReader e m, Has e Options, MonadVar m,-               MonadFile m, Typeable m, Typeable v)-            => NixFrame -> m [Doc]+framePos+  :: forall v (m :: Type -> Type)+   . (Typeable m, Typeable v)+  => NixFrame+  -> Maybe NSourcePos+framePos (NixFrame _ f) =+  (\case+    EvaluatingExpr _ (Ann (SrcSpan beg _) _) -> pure beg+    _ -> Nothing+  )+  =<< fromException @(EvalFrame m v) f++renderFrame+  :: forall v t f e m ann+   . ( MonadReader e m+     , Has e Options+     , MonadFile m+     , MonadCitedThunks t f m+     , Typeable v+     )+  => NixFrame+  -> m [Doc ann] renderFrame (NixFrame level f)-    | Just (e :: EvalFrame m v) <- fromException f = renderEvalFrame level e-    | Just (e :: ThunkLoop)     <- fromException f = renderThunkLoop level e-    | Just (e :: ValueFrame m)  <- fromException f = renderValueFrame level e-    | Just (_ :: NormalLoop m)  <- fromException f =-      pure [text "<<loop during normalization>>"]-    | Just (e :: ExecFrame m)   <- fromException f = renderExecFrame level e-    | Just (e :: ErrorCall)     <- fromException f = pure [text (show e)]-    | otherwise = error $ "Unrecognized frame: " ++ show f+  | Just (e :: EvalFrame      m v) <- fromException f = renderEvalFrame  level  e+  | Just (e :: ThunkLoop         ) <- fromException f = renderThunkLoop  level  e+  | Just (e :: ValueFrame t f m  ) <- fromException f = renderValueFrame level  e+  | Just (e :: NormalLoop t f m  ) <- fromException f = renderNormalLoop level  e+  | Just (e :: ExecFrame  t f m  ) <- fromException f = renderExecFrame  level  e+  | Just (e :: ErrorCall         ) <- fromException f = pure $ one $ pretty (Text.show e)+  | Just (e :: SynHoleInfo    m v) <- fromException f = pure $ one $ pretty (Text.show e)+  | otherwise = fail $ "Unrecognized frame: " <> show f  wrapExpr :: NExprF r -> NExpr wrapExpr x = Fix (Fix (NSym "<?>") <$ x) -renderEvalFrame :: (MonadReader e m, Has e Options, MonadFile m)-                => NixLevel -> EvalFrame m v -> m [Doc]-renderEvalFrame level f = do-    opts :: Options <- asks (view hasLens)+renderEvalFrame+  :: forall e m v ann+  . (MonadReader e m, Has e Options, MonadFile m)+  => NixLevel+  -> EvalFrame m v+  -> m [Doc ann]+renderEvalFrame level f =+  do+    opts <- askOptions+    let+      addMetaInfo :: ([Doc ann] -> [Doc ann]) -> SrcSpan -> Doc ann -> m [Doc ann]+      addMetaInfo trans loc = fmap (trans . one) . renderLocation loc+     case f of-        EvaluatingExpr _scope e@(Fix (Compose (Ann ann _))) ->-            fmap (:[]) $ renderLocation ann-                =<< renderExpr level "While evaluating" "Expression" e+      EvaluatingExpr scope e@(Ann loc _) ->+        addMetaInfo+          (scopeInfo <>)+          loc+          =<< renderExpr level "While evaluating" "Expression" e+         where+          scopeInfo :: [Doc ann]+          scopeInfo =+            one (pretty $ Text.show scope) `whenTrue` isShowScopes opts -        ForcingExpr _scope e@(Fix (Compose (Ann ann _)))-            | thunks opts ->-                  fmap (:[]) $ renderLocation ann-                      =<< renderExpr level "While forcing thunk from"-                                     "Forcing thunk" e+      ForcingExpr _scope e@(Ann loc _) | isThunks opts ->+        addMetaInfo+          id+          loc+          =<< renderExpr level "While forcing thunk from" "Forcing thunk" e -        Calling name ann ->-            fmap (:[]) $ renderLocation ann $-                text "While calling builtins." <> text name+      Calling name loc ->+        addMetaInfo+          id+          loc+          $ "While calling `builtins." <> prettyVarName name <> "`" -        _ -> pure []+      SynHole synfo ->+        sequenceA+          [ renderLocation loc =<<+              renderExpr level "While evaluating" "Syntactic Hole" e+          , pure $ pretty $ Text.show $ _synHoleInfo_scope synfo+          ]+         where+          e@(Ann loc _) = _synHoleInfo_expr synfo -renderExpr :: (MonadReader e m, Has e Options, MonadFile m)-           => NixLevel -> String -> String -> NExprLoc -> m Doc-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 =-              prettyNix (Fix (Fix (NSym "<?>") <$ x))-    pure $ if verbose opts >= Chatty-           then text (longLabel ++ ":\n>>>>>>>>")-                    P.<$> indent 2 rendered-                    P.<$> text "<<<<<<<<"-           else text shortLabel <> text ": " </> rendered+      ForcingExpr _ _ -> stub -renderValueFrame :: (MonadReader e m, Has e Options, MonadFile m)-                 => NixLevel -> ValueFrame m -> m [Doc]-renderValueFrame level = pure . (:[]) . \case-    ForcingThunk       -> text "ForcingThunk"-    ConcerningValue _v -> text "ConcerningValue"-    Comparison _ _     -> text "Comparing"-    Addition _ _       -> text "Adding"-    Division _ _       -> text "Dividing"-    Multiplication _ _ -> text "Multiplying" -    Coercion x y ->-        text desc <> text (describeValue x)-            <> text " to " <> text (describeValue y)-      where-        desc | level <= Error = "Cannot coerce "-             | otherwise     = "While coercing "+renderExpr+  :: (MonadReader e m, Has e Options, MonadFile m)+  => NixLevel+  -> Text+  -> Text+  -> NExprLoc+  -> m (Doc ann)+renderExpr _level longLabel shortLabel e@(Ann _ x) =+  do+    opts <- askOptions+    let+      verbosity :: Verbosity+      verbosity = getVerbosity opts -    CoercionToJsonNF _v -> text "CoercionToJsonNF"-    CoercionFromJson _j -> text "CoercionFromJson"-    ExpectationNF _t _v -> text "ExpectationNF"-    Expectation _t _v   -> text "Expectation"+      expr :: NExpr+      expr = stripAnnotation e -renderValue :: (MonadReader e m, Has e Options, MonadFile m, MonadVar m)-            => NixLevel -> String -> String -> NValue m -> m Doc-renderValue _level _longLabel _shortLabel v = do-    opts :: Options <- asks (view hasLens)-    if values opts-        then prettyNValueProv v-        else prettyNValue v+      concise = prettyNix $ Fix $ Fix (NSym "<?>") <$ x -renderExecFrame :: (MonadReader e m, Has e Options, MonadVar m, MonadFile m)-                => NixLevel -> ExecFrame m -> m [Doc]-renderExecFrame level = \case-    Assertion ann v ->-        fmap (:[]) $ renderLocation ann-            =<< ((text "Assertion failed:" </>)-                     <$> renderValue level "" "" v)+      chatty =+        bool+          (pretty $ PS.ppShow expr)+          (prettyNix expr)+          (verbosity == Chatty) -renderThunkLoop :: (MonadReader e m, Has e Options, MonadFile m)-                => NixLevel -> ThunkLoop -> m [Doc]-renderThunkLoop _level = pure . (:[]) . \case-    ThunkLoop Nothing -> text "<<loop>>"-    ThunkLoop (Just n) ->-        text $ "<<loop forcing thunk #" ++ show n ++ ">>"+    pure $+      bool+        (pretty shortLabel <> fillSep [": ", concise])+        (vsep [pretty (longLabel <> ":\n>>>>>>>>"), indent 2 chatty, "<<<<<<<<"])+        (verbosity >= Chatty)++renderValueFrame+  :: forall e t f m ann+   . (MonadReader e m, Has e Options, MonadFile m, MonadCitedThunks t f m)+  => NixLevel+  -> ValueFrame t f m+  -> m [Doc ann]+renderValueFrame level = fmap one . \case+  ForcingThunk    _t -> pure "ForcingThunk" -- jww (2019-03-18): NYI+  ConcerningValue _v -> pure "ConcerningValue"+  Comparison     _ _ -> pure "Comparing"+  Addition       _ _ -> pure "Adding"+  Division       _ _ -> pure "Dividing"+  Multiplication _ _ -> pure "Multiplying"++  Coercion       x y -> pure+    $ fold [desc, pretty (describeValue x), " to ", pretty (describeValue y)]+   where+    desc =+      bool+        "While coercing "+        "Cannot coerce "+        (level <= Error)++  CoercionToJson v ->+    ("CoercionToJson " <>) <$> dumbRenderValue v+  CoercionFromJson _j -> pure "CoercionFromJson"+  Expectation t v     ->+    (msg <>) <$> dumbRenderValue v+   where+    msg = "Expected " <> pretty (describeValue t) <> ", but saw "++--  2021-10-28: NOTE: notice it ignores `level`, `longlabel` & `shortlabel`, to underline that `dumbRenderValue` synonym was created+renderValue+  :: forall e t f m ann+   . (MonadReader e m, Has e Options, MonadFile m, MonadCitedThunks t f m)+  => NixLevel+  -> Text+  -> Text+  -> NValue t f m+  -> m (Doc ann)+renderValue _level _longLabel _shortLabel v =+  do+    opts <- askOptions+    bool+      prettyNValue+      prettyNValueProv+      (isValues opts)+      <$> removeEffects v++dumbRenderValue+  :: forall e t f m ann+   . (MonadReader e m, Has e Options, MonadFile m, MonadCitedThunks t f m)+   => (NValue t f m -> m (Doc ann))+dumbRenderValue = renderValue Info mempty mempty++renderExecFrame+  :: (MonadReader e m, Has e Options, MonadFile m, MonadCitedThunks t f m)+  => NixLevel+  -> ExecFrame t f m+  -> m [Doc ann]+renderExecFrame _level (Assertion ann v) =+  fmap+    one+    $ renderLocation ann . fillSep . on (<>) one "Assertion failed:" =<< dumbRenderValue v++renderThunkLoop+  :: (MonadReader e m, Has e Options, MonadFile m, Show (ThunkId m))+  => NixLevel+  -> ThunkLoop+  -> m [Doc ann]+renderThunkLoop _level (ThunkLoop n) =+  pure . one . pretty $ "Infinite recursion in thunk " <> n++renderNormalLoop+  :: (MonadReader e m, Has e Options, MonadFile m, MonadCitedThunks t f m)+  => NixLevel+  -> NormalLoop t f m+  -> m [Doc ann]+renderNormalLoop _level (NormalLoop v) =+  one . ("Infinite recursion during normalization forcing " <>) <$> dumbRenderValue v
src/Nix/Scope.hs view
@@ -1,83 +1,141 @@-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE DeriveFoldable #-}-{-# LANGUAGE DeriveTraversable #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}+{-# language UndecidableInstances #-}+{-# language AllowAmbiguousTypes #-}+{-# language ConstraintKinds #-}+{-# language FunctionalDependencies #-}+{-# language GeneralizedNewtypeDeriving #-}  module Nix.Scope where -import           Control.Applicative-import           Control.Monad.Reader-import qualified Data.HashMap.Lazy as M-import           Data.Semigroup-import           Data.Text (Text)+import           Nix.Prelude+import qualified Data.HashMap.Lazy             as M+import qualified Text.Show import           Lens.Family2-import           Nix.Utils+import           Nix.Expr.Types -newtype Scope a = Scope { getScope :: AttrSet a }-    deriving (Functor, Foldable, Traversable)+--  2021-07-19: NOTE: Scopes can gain from sequentiality, HashMap (aka AttrSet) may not be proper to it.+newtype Scope a = Scope (AttrSet a)+  deriving+    ( Eq, Ord, Generic+    , Typeable, NFData+    , Read, Hashable+    , Semigroup, Monoid+    , Functor, Foldable, Traversable+    , One+    )  instance Show (Scope a) where-    show (Scope m) = show (M.keys m)--newScope :: AttrSet a -> Scope a-newScope = Scope+  show (Scope m) = show $ M.keys m -scopeLookup :: Text -> [Scope v] -> Maybe v-scopeLookup key = foldr go Nothing-  where-    go (Scope m) rest = M.lookup key m <|> rest+scopeLookup :: VarName -> [Scope a] -> Maybe a+scopeLookup key = foldr fun Nothing+ where+  fun+    :: Scope a+    -> Maybe a+    -> Maybe a+  fun (Scope m) rest = M.lookup key m <|> rest -data Scopes m v = Scopes-    { lexicalScopes :: [Scope v]-    , dynamicScopes :: [m (Scope v)]+data Scopes m a =+  Scopes+    { lexicalScopes :: [Scope a]+    , dynamicScopes :: [m (Scope a)]     } -instance Show (Scopes m v) where-    show (Scopes m v) =-        "Scopes: " ++ show m ++ ", and "-            ++ show (length v) ++ " with-scopes"+instance Show (Scopes m a) where+  show (Scopes m a) =+    "Scopes: " <> show m <> ", and " <> show (length a) <> " with-scopes" -instance Semigroup (Scopes m v) where-    Scopes ls lw <> Scopes rs rw = Scopes (ls <> rs) (lw <> rw)+instance Semigroup (Scopes m a) where+  Scopes ls lw <> Scopes rs rw = Scopes (ls <> rs) (lw <> rw) -instance Monoid (Scopes m v) where-    mempty  = emptyScopes-    mappend = (<>)+instance Monoid (Scopes m a) where+  mempty = emptyScopes -type Scoped e v m = (MonadReader e m, Has e (Scopes m v))+emptyScopes :: Scopes m a+emptyScopes = Scopes mempty mempty -emptyScopes :: Scopes m v-emptyScopes = Scopes [] []+class Scoped a m | m -> a where+  askScopes :: m (Scopes m a)+  clearScopes   :: m r -> m r+  pushScopes    :: Scopes m a -> m r -> m r+  lookupVar     :: VarName -> m (Maybe a) -currentScopes :: Scoped e v m => m (Scopes m v)-currentScopes = asks (view hasLens)+askScopesReader+  :: forall m a e+  . ( MonadReader e m+    , Has e (Scopes m a)+    )+  => m (Scopes m a)+askScopesReader = askLocal -clearScopes :: forall v m e r. Scoped e v m => m r -> m r-clearScopes = local (set hasLens (emptyScopes @m @v))+clearScopesReader+  :: forall m a e r+  . ( MonadReader e m+    , Has e (Scopes m a)+    )+  => m r+  -> m r+clearScopesReader = local $ set hasLens $ emptyScopes @m @a -pushScope :: forall v m e r. Scoped e v m => AttrSet v -> m r -> m r-pushScope s = pushScopes (Scopes [Scope s] [])+pushScope+  :: Scoped a m+  => Scope a+  -> m r+  -> m r+pushScope scope = pushScopes $ Scopes (one scope) mempty -pushWeakScope :: forall v m e r. Scoped e v m => m (AttrSet v) -> m r -> m r-pushWeakScope s = pushScopes (Scopes [] [Scope <$> s])+pushWeakScope+  :: ( Functor m+     , Scoped a m+     )+  => m (Scope a)+  -> m r+  -> m r+pushWeakScope scope = pushScopes $ Scopes mempty $ one scope -pushScopes :: Scoped e v m => Scopes m v -> m r -> m r-pushScopes s = local (over hasLens (s <>))+pushScopesReader+  :: ( MonadReader e m+     , Has e (Scopes m a)+     )+  => Scopes m a+  -> m r+  -> m r+pushScopesReader s = local $ over hasLens (s <>) -lookupVar :: forall e v m. (Scoped e v m, Monad m) => Text -> m (Maybe v)-lookupVar k = do-    mres <- asks (scopeLookup k . lexicalScopes @m . view hasLens)-    case mres of-        Just sym -> return $ Just sym-        Nothing -> do-            ws <- asks (dynamicScopes . view hasLens)-            foldr (\x -> liftM2 (<|>) (M.lookup k . getScope <$> x))-                  (return Nothing) ws+lookupVarReader+  :: forall m a e+  . ( MonadReader e m+    , Has e (Scopes m a)+    )+  => VarName+  -> m (Maybe a)+lookupVarReader k =+  do+    mres <- asks $ scopeLookup k . lexicalScopes @m . view hasLens -withScopes :: forall v m e a. Scoped e v m => Scopes m v -> m a -> m a-withScopes scope = clearScopes @v . pushScopes scope+    maybe+      (do+        ws <- asks $ dynamicScopes . view hasLens++        foldr+          (\ weakscope rest ->+            do+              mres' <- M.lookup k . coerce @(Scope a) <$> weakscope++              maybe+                rest+                (pure . pure)+                mres'+          )+          (pure Nothing)+          ws+      )+      (pure . pure)+      mres++withScopes+  :: Scoped a m+  => Scopes m a+  -> m r+  -> m r+withScopes scopes = clearScopes . pushScopes scopes
+ src/Nix/Standard.hs view
@@ -0,0 +1,375 @@+{-# language TypeFamilies #-}+{-# language CPP #-}+{-# language GeneralizedNewtypeDeriving #-}+{-# language UndecidableInstances #-}++{-# options_ghc -Wno-orphans #-}+++module Nix.Standard where++import           Nix.Prelude+import           Control.Comonad                ( Comonad )+import           Control.Comonad.Env            ( ComonadEnv )+import           Control.Monad.Catch            ( MonadThrow+                                                , MonadCatch+                                                , MonadMask+                                                )+#if !MIN_VERSION_base(4,13,0)+import           Control.Monad.Fail             ( MonadFail )+#endif+import           Control.Monad.Free             ( Free(Free) )+import           Control.Monad.Fix              ( MonadFix )+import           Control.Monad.Ref              ( MonadRef(newRef)+                                                , MonadAtomicRef+                                                )+import qualified Text.Show+import           Nix.Cited+import           Nix.Cited.Basic+import           Nix.Context+import           Nix.Effects+import           Nix.Effects.Basic+import           Nix.Effects.Derivation+import           Nix.Expr.Types.Annotated+import           Nix.Fresh+import           Nix.Fresh.Basic+import           Nix.Options+import           Nix.Render+import           Nix.Scope+import           Nix.Thunk+import           Nix.Thunk.Basic+import           Nix.Utils.Fix1                 ( Fix1T(Fix1T) )+import           Nix.Value+import           Nix.Value.Monad+++newtype StdCited m a =+  StdCited+    (Cited (StdThunk m) (StdCited m) m a)+  deriving+    ( Generic, Typeable+    , Functor, Applicative, Comonad, ComonadEnv [Provenance m (StdValue m)]+    , Foldable, Traversable+    )++newtype StdThunk m =+  StdThunk+    (StdCited m (NThunkF m (StdValue m)))+type StdValue' m = NValue' (StdThunk m) (StdCited m) m (StdValue m)+type StdValue m = NValue (StdThunk m) (StdCited m) m+type StandardIO = StandardT (StdIdT IO)+type StdVal = StdValue StandardIO+type StdThun = StdThunk StandardIO+type StdIO = StandardIO ()++-- | Type alias:+--+-- > Cited (StdThunk m) (StdCited m) m (NThunkF m (StdValue m))+type CitedStdThunk m = Cited (StdThunk m) (StdCited m) m (NThunkF m (StdValue m))++instance Show (StdThunk m) where+  show _ = toString thunkStubText++instance HasCitations1 m (StdValue m) (StdCited m) where+  citations1 (StdCited c) = citations1 c+  addProvenance1 x (StdCited c) = StdCited $ addProvenance1 x c++instance HasCitations m (StdValue m) (StdThunk m) where+  citations (StdThunk c) = citations1 c+  addProvenance x (StdThunk c) = StdThunk $ addProvenance1 x c++instance MonadReader (Context m (StdValue m)) m => Scoped (StdValue m) m where+  askScopes   = askScopesReader+  clearScopes = clearScopesReader @m @(StdValue m)+  pushScopes  = pushScopesReader+  lookupVar   = lookupVarReader++instance+  ( MonadFix m+  , MonadFile m+  , MonadCatch m+  , MonadEnv m+  , MonadPaths m+  , MonadExec m+  , MonadHttp m+  , MonadInstantiate m+  , MonadIntrospect m+  , MonadPlus m+  , MonadPutStr m+  , MonadStore m+  , MonadAtomicRef m+  , Typeable m+  , Scoped (StdValue m) m+  , MonadReader (Context m (StdValue m)) m+  , MonadState (HashMap Path NExprLoc, HashMap Text Text) m+  , MonadDataErrorContext (StdThunk m) (StdCited m) m+  , MonadThunk (StdThunk m) m (StdValue m)+  , MonadValue (StdValue m) m+  )+  => MonadEffects (StdThunk m) (StdCited m) m where+  toAbsolutePath   = defaultToAbsolutePath+  findEnvPath      = defaultFindEnvPath+  findPath         = defaultFindPath+  importPath       = defaultImportPath+  pathToDefaultNix = defaultPathToDefaultNix+  derivationStrict = defaultDerivationStrict+  traceEffect      = defaultTraceEffect++-- 2021-07-24:+-- This instance currently is to satisfy @MonadThunk@ requirements for @normalForm@ function.+-- As it is seen from the instance - it does superficial type class jump.+-- It is just a type boundary for thunking.+instance+  ( Typeable       m+  , MonadThunkId   m+  , MonadAtomicRef m+  , MonadCatch     m+  , MonadReader (Context m (StdValue m)) m+  )+  => MonadThunk (StdThunk m) m (StdValue m) where++  thunkId+    :: StdThunk m+    -> ThunkId  m+  thunkId = thunkId @(CitedStdThunk m) . coerce+  {-# inline thunkId #-}++  thunk+    :: m (StdValue m)+    -> m (StdThunk m)+  thunk = fmap coerce . thunk @(CitedStdThunk m)+  {-# inline thunk #-}++  query+    :: m (StdValue m)+    ->    StdThunk m+    -> m (StdValue m)+  query b = query @(CitedStdThunk m) b . coerce+  {-# inline query #-}++  force+    ::    StdThunk m+    -> m (StdValue m)+  force = force @(CitedStdThunk m) . coerce+  {-# inline force #-}++  forceEff+    ::    StdThunk m+    -> m (StdValue m)+  forceEff = forceEff @(CitedStdThunk m) . coerce+  {-# inline forceEff #-}++  further+    ::    StdThunk m+    -> m (StdThunk m)+  further = fmap coerce . further @(CitedStdThunk m) . coerce+  {-# inline further #-}+++-- * @instance MonadThunkF@ (Kleisli functor HOFs)++-- | This is a functorized version in CPS.++-- Please do not use MonadThunkF instances to define MonadThunk. as MonadThunk uses specialized functions.+instance+  ( Typeable       m+  , MonadThunkId   m+  , MonadAtomicRef m+  , MonadCatch     m+  , MonadReader (Context m (StdValue m)) m+  )+  => MonadThunkF (StdThunk m) m (StdValue m) where++  queryF+    :: ( StdValue m+       -> m r+       )+    -> m r+    -> StdThunk m+    -> m r+  queryF k b = queryF @(CitedStdThunk m) k b . coerce++  forceF+    :: ( StdValue m+       -> m r+       )+    -> StdThunk m+    -> m r+  forceF k = forceF @(CitedStdThunk m) k . coerce++  forceEffF+    :: ( StdValue m+       -> m r+       )+    -> StdThunk m+    -> m r+  forceEffF k = forceEffF @(CitedStdThunk m) k . coerce++  furtherF+    :: ( m (StdValue m)+       -> m (StdValue m)+       )+    ->    StdThunk m+    -> m (StdThunk m)+  furtherF k = fmap coerce . furtherF @(CitedStdThunk m) k . coerce+++-- * @instance MonadValue (StdValue m) m@++instance+  ( MonadAtomicRef m+  , MonadCatch m+  , Typeable m+  , MonadReader (Context m (StdValue m)) m+  , MonadThunkId m+  )+  => MonadValue (StdValue m) m where++  defer+    :: m (StdValue m)+    -> m (StdValue m)+  defer = fmap (pure . coerce) . thunk @(CitedStdThunk m)++  demand+    :: StdValue m+    -> m (StdValue m)+  demand = go -- lock to ensure no type class jumps.+   where+    go :: StdValue m -> m (StdValue m)+    go =+      free+        (go <=< force @(CitedStdThunk m) . coerce)+        (pure . Free)++  inform+    :: StdValue m+    -> m (StdValue m)+  inform = go -- lock to ensure no type class jumps.+   where+    go :: StdValue m -> m (StdValue m)+    go =+      free+        ((pure . coerce <$>) . (further @(CitedStdThunk m) . coerce))+        ((Free <$>) . bindNValue' id go)+++-- * @instance MonadValueF (StdValue m) m@++instance+  ( MonadAtomicRef m+  , MonadCatch m+  , Typeable m+  , MonadReader (Context m (StdValue m)) m+  , MonadThunkId m+  )+  => MonadValueF (StdValue m) m where++  demandF+    :: ( StdValue m+      -> m r+      )+    -> StdValue m+    -> m r+  demandF f = f <=< demand++  informF+    :: ( m (StdValue m)+      -> m (StdValue m)+      )+    -> StdValue m+    -> m (StdValue m)+  informF f = f . inform+++{------------------------------------------------------------------------}++-- jww (2019-03-22): NYI+-- whileForcingThunk+--   :: forall t f m s e r . (Exception s, Convertible e t f m) => s -> m r -> m r+-- whileForcingThunk frame =+--   withFrame Debug (ForcingThunk @t @f @m) . withFrame Debug frame++newtype StandardTF r m a+  = StandardTF+      (ReaderT+        (Context r (StdValue r))+        (StateT (HashMap Path NExprLoc, HashMap Text Text) m)+        a+      )+  deriving+    ( Functor+    , Applicative+    , Alternative+    , Monad+    , MonadFail+    , MonadPlus+    , MonadFix+    , MonadIO+    , MonadCatch+    , MonadThrow+    , MonadMask+    , MonadReader (Context r (StdValue r))+    , MonadState (HashMap Path NExprLoc, HashMap Text Text)+    )++instance MonadTrans (StandardTF r) where+  lift = StandardTF . lift . lift+  {-# inline lift #-}++instance (MonadPutStr r, MonadPutStr m)+  => MonadPutStr (StandardTF r m)+instance (MonadHttp r, MonadHttp m)+  => MonadHttp (StandardTF r m)+instance (MonadEnv r, MonadEnv m)+  => MonadEnv (StandardTF r m)+instance (MonadPaths r, MonadPaths m)+  => MonadPaths (StandardTF r m)+instance (MonadInstantiate r, MonadInstantiate m)+  => MonadInstantiate (StandardTF r m)+instance (MonadExec r, MonadExec m)+  => MonadExec (StandardTF r m)+instance (MonadIntrospect r, MonadIntrospect m)+  => MonadIntrospect (StandardTF r m)++---------------------------------------------------------------------------------++type StandardT m = Fix1T StandardTF m++instance MonadTrans (Fix1T StandardTF) where+  lift = Fix1T . lift+  {-# inline lift #-}++instance MonadThunkId m+  => MonadThunkId (StandardT m) where++  type ThunkId (StandardT m) = ThunkId m++mkStandardT+  :: ReaderT+      (Context (StandardT m) (StdValue (StandardT m)))+      (StateT (HashMap Path NExprLoc, HashMap Text Text) m)+      a+  -> StandardT m a+mkStandardT = coerce++runStandardT+  :: StandardT m a+  -> ReaderT+      (Context (StandardT m) (StdValue (StandardT m)))+      (StateT (HashMap Path NExprLoc, HashMap Text Text) m)+      a+runStandardT = coerce++runWithBasicEffects+  :: (MonadIO m, MonadAtomicRef m)+  => Options+  -> StandardT (StdIdT m) a+  -> m a+runWithBasicEffects opts =+  fun . (`evalStateT` mempty) . (`runReaderT` newContext opts) . runStandardT+ where+  fun action =+    runFreshIdT action =<< newRef (1 :: Int)++runWithBasicEffectsIO :: Options -> StandardIO a -> IO a+runWithBasicEffectsIO = runWithBasicEffects
+ src/Nix/String.hs view
@@ -0,0 +1,262 @@+{-# language GeneralizedNewtypeDeriving #-}++module Nix.String+  ( NixString+  , getStringContext+  , mkNixString+  , StringContext(..)+  , ContextFlavor(..)+  , NixLikeContext(..)+  , NixLikeContextValue(..)+  , toNixLikeContext+  , fromNixLikeContext+  , hasContext+  , intercalateNixString+  , getStringNoContext+  , ignoreContext+  , mkNixStringWithoutContext+  , mkNixStringWithSingletonContext+  , modifyNixContents+  , WithStringContext+  , WithStringContextT(..)+  , extractNixString+  , addStringContext+  , addSingletonStringContext+  , runWithStringContextT+  , runWithStringContextT'+  , runWithStringContext+  , runWithStringContext'+  )+where+++++import           Nix.Prelude             hiding ( Type, TVar )+import           Control.Monad.Writer           ( WriterT(..), MonadWriter(tell))+import qualified Data.HashMap.Lazy             as M+import qualified Data.HashSet                  as S+import qualified Data.Text                     as Text+import           Nix.Expr.Types                 ( VarName(..)+                                                , AttrSet+                                                )+++-- * Types++-- ** Context++-- | A Nix 'StringContext' ...+data StringContext =+  StringContext+    { getStringContextFlavor :: !ContextFlavor+    , getStringContextPath   :: !VarName+    }+  deriving (Eq, Ord, Show, Generic)++instance Hashable StringContext++-- | A 'ContextFlavor' describes the sum of possible derivations for string contexts+data ContextFlavor+  = DirectPath+  | AllOutputs+  | DerivationOutput !Text+  deriving (Show, Eq, Ord, Generic)++instance Hashable ContextFlavor++newtype NixLikeContext =+  NixLikeContext+    { getNixLikeContext :: AttrSet NixLikeContextValue+    }+  deriving (Eq, Ord, Show, Generic)++data NixLikeContextValue =+  NixLikeContextValue+    { nlcvPath :: !Bool+    , nlcvAllOutputs :: !Bool+    , nlcvOutputs :: ![Text]+    }+  deriving (Show, Eq, Ord, Generic)++instance Semigroup NixLikeContextValue where+  a <> b =+    NixLikeContextValue+      { nlcvPath       = nlcvPath       a || nlcvPath       b+      , nlcvAllOutputs = nlcvAllOutputs a || nlcvAllOutputs b+      , nlcvOutputs    = nlcvOutputs    a <> nlcvOutputs    b+      }++instance Monoid NixLikeContextValue where+  mempty = NixLikeContextValue False False mempty+++-- ** StringContext accumulator++-- | A monad for accumulating string context while producing a result string.+newtype WithStringContextT m a =+  WithStringContextT+    (WriterT (S.HashSet StringContext) m a )+  deriving (Functor, Applicative, Monad, MonadTrans, MonadWriter (S.HashSet StringContext))++type WithStringContext = WithStringContextT Identity+++-- ** NixString++data NixString =+  NixString+    { getStringContext :: !(S.HashSet StringContext)+    , getStringContent :: !Text+    }+  deriving (Eq, Ord, Show, Generic)++instance Semigroup NixString where+  NixString s1 t1 <> NixString s2 t2 = NixString (s1 <> s2) (t1 <> t2)++instance Monoid NixString where+ mempty = NixString mempty mempty++instance Hashable NixString+++-- * Functions++-- ** Makers++-- | Constructs NixString without a context+mkNixStringWithoutContext :: Text -> NixString+mkNixStringWithoutContext = NixString mempty++-- | Create NixString using a singleton context+mkNixStringWithSingletonContext+  :: StringContext -> VarName -> NixString+mkNixStringWithSingletonContext c s = NixString (one c) (coerce @VarName @Text s)++-- | Create NixString from a Text and context+mkNixString+  :: S.HashSet StringContext -> Text -> NixString+mkNixString = NixString+++-- ** Checkers++-- | Returns True if the NixString has an associated context+hasContext :: NixString -> Bool+hasContext (NixString c _) = isPresent c+++-- ** Getters++fromNixLikeContext :: NixLikeContext -> S.HashSet StringContext+fromNixLikeContext =+  S.fromList . (uncurry toStringContexts <=< M.toList . getNixLikeContext)++-- | Extract the string contents from a NixString that has no context+getStringNoContext :: NixString -> Maybe Text+getStringNoContext (NixString c s)+  | null c    = pure s+  | otherwise = mempty++-- | Extract the string contents from a NixString even if the NixString has an associated context+ignoreContext :: NixString -> Text+ignoreContext (NixString _ s) = s++-- | Get the contents of a 'NixString' and write its context into the resulting set.+extractNixString :: Monad m => NixString -> WithStringContextT m Text+extractNixString (NixString c s) =+  WithStringContextT $+    s <$ tell c+++-- ** Setters++-- this really should be 2 args, then with @toStringContexts path@ laziness it would tail recurse.+-- for now tuple dissected internaly with laziness preservation.+toStringContexts :: VarName -> NixLikeContextValue -> [StringContext]+toStringContexts path = go+ where+  go :: NixLikeContextValue -> [StringContext]+  go cv =+    case cv of+      NixLikeContextValue True _    _ ->+        mkLstCtxFor DirectPath cv { nlcvPath = False }+      NixLikeContextValue _    True _ ->+        mkLstCtxFor AllOutputs cv { nlcvAllOutputs = False }+      NixLikeContextValue _    _    ls | isPresent ls ->+        mkCtxFor . DerivationOutput <$> ls+      _ -> mempty+   where+    mkCtxFor :: ContextFlavor -> StringContext+    mkCtxFor context = StringContext context path+    mkLstCtxFor :: ContextFlavor -> NixLikeContextValue -> [StringContext]+    mkLstCtxFor t c = one (mkCtxFor t) <> go c+++toNixLikeContextValue :: StringContext -> (NixLikeContextValue, VarName)+toNixLikeContextValue sc =+  ( case getStringContextFlavor sc of+      DirectPath         -> NixLikeContextValue True False mempty+      AllOutputs         -> NixLikeContextValue False True mempty+      DerivationOutput t -> NixLikeContextValue False False $ one t+  , getStringContextPath sc+  )++toNixLikeContext :: S.HashSet StringContext -> NixLikeContext+toNixLikeContext stringContext =+  NixLikeContext $+    S.foldr+      fun+      mempty+      stringContext+ where+  fun :: (StringContext -> AttrSet NixLikeContextValue -> AttrSet NixLikeContextValue)+  fun sc =+    uncurry (M.insertWith (<>)) (swap $ toNixLikeContextValue sc)++-- | Add 'StringContext's into the resulting set.+addStringContext+  :: Monad m => S.HashSet StringContext -> WithStringContextT m ()+addStringContext = WithStringContextT . tell++-- | Add a 'StringContext' into the resulting set.+addSingletonStringContext :: Monad m => StringContext -> WithStringContextT m ()+addSingletonStringContext = WithStringContextT . tell . one++-- | Run an action producing a string with a context and put those into a 'NixString'.+runWithStringContextT :: Monad m => WithStringContextT m Text -> m NixString+runWithStringContextT (WithStringContextT m) =+  uncurry (flip NixString) <$> runWriterT m++-- | Run an action producing a string with a context and put those into a 'NixString'.+runWithStringContext :: WithStringContextT Identity Text -> NixString+runWithStringContext = runIdentity . runWithStringContextT+++-- ** Modifiers++-- | Modify the string part of the NixString, leaving the context unchanged+modifyNixContents :: (Text -> Text) -> NixString -> NixString+modifyNixContents f (NixString c s) = NixString c (f s)++-- | Run an action that manipulates nix strings, and collect the contexts encountered.+-- Warning: this may be unsafe, depending on how you handle the resulting context list.+runWithStringContextT' :: Monad m => WithStringContextT m a -> m (a, S.HashSet StringContext)+runWithStringContextT' (WithStringContextT m) = runWriterT m++-- | Run an action that manipulates nix strings, and collect the contexts encountered.+-- Warning: this may be unsafe, depending on how you handle the resulting context list.+runWithStringContext' :: WithStringContextT Identity a -> (a, S.HashSet StringContext)+runWithStringContext' = runIdentity . runWithStringContextT'++-- | Combine NixStrings with a separator+intercalateNixString :: NixString -> [NixString] -> NixString+intercalateNixString _   []   = mempty+intercalateNixString _   [ns] = ns+intercalateNixString sep nss  =+  uncurry NixString $+    mapPair+      (S.unions . (one (getStringContext  sep) <>) . (getStringContext <$>)+      , Text.intercalate (getStringContent sep) . (getStringContent <$>)+      )+      $ dup nss
+ src/Nix/String/Coerce.hs view
@@ -0,0 +1,138 @@+{-# language CPP #-}++module Nix.String.Coerce where++import           Nix.Prelude+import           Control.Monad.Catch            ( MonadThrow )+import           GHC.Exception                  ( ErrorCall(ErrorCall) )+import qualified Data.HashMap.Lazy             as M+import           Nix.Atoms+import           Nix.Expr.Types                 ( VarName )+import           Nix.Effects+import           Nix.Frames+import           Nix.String+import           Nix.Value+import           Nix.Value.Monad++#ifdef MIN_VERSION_ghc_datasize+import           GHC.DataSize+#endif++-- | Data type to avoid boolean blindness on what used to be called coerceMore+data CoercionLevel+  = CoerceStringlike+  -- ^ Coerce only stringlike types: strings, paths+  | CoerceAny+  -- ^ Coerce everything but functions+  deriving (Eq,Ord,Enum,Bounded)++-- | Data type to avoid boolean blindness on what used to be called copyToStore+data CopyToStoreMode+  = CopyToStore+  -- ^ Add paths to the store as they are encountered+  | DontCopyToStore+  -- ^ Add paths to the store as they are encountered+  deriving (Eq,Ord,Enum,Bounded)++--  2021-10-30: NOTE: This seems like metafunction that really is a bunch of functions thrown together.+-- Both code blocks are `\case` - which means they can be or 2 functions, or just as well can be one `\case` that goes through all of them and does not require a `CoercionLevel`. Use of function shows that - the `CoercionLevel` not once was used polymorphically.+-- Also `CopyToStoreMode` acts only in case of `NVPath` - that is a separate function+coerceToString+  :: forall e t f m+   . ( Framed e m+     , MonadStore m+     , MonadThrow m+     , MonadDataErrorContext t f m+     , MonadValue (NValue t f m) m+     )+  => (NValue t f m -> NValue t f m -> m (NValue t f m))+  -> CopyToStoreMode+  -> CoercionLevel+  -> NValue t f m+  -> m NixString+coerceToString call ctsm clevel =+  bool+    (coerceAnyToNixString call ctsm)+    (coerceStringlikeToNixString ctsm)+    (clevel == CoerceStringlike)++coerceAnyToNixString+  :: forall e t f m+   . ( Framed e m+     , MonadStore m+     , MonadThrow m+     , MonadDataErrorContext t f m+     , MonadValue (NValue t f m) m+     )+  => (NValue t f m -> NValue t f m -> m (NValue t f m))+  -> CopyToStoreMode+  -> NValue t f m+  -> m NixString+coerceAnyToNixString call ctsm = go+ where+  go :: NValue t f m -> m NixString+  go x =+    coerceAny =<< demand x+     where+      coerceAny :: NValue t f m -> m NixString+      coerceAny =+        \case+          -- TODO Return a singleton for "" and "1"+          NVConstant (NBool b) ->+            castToNixString $ "1" `whenTrue` b+          NVConstant (NInt n) ->+            castToNixString $ show n+          NVConstant (NFloat n) ->+            castToNixString $ show n+          NVConstant NNull ->+            castToNixString mempty+          NVList l ->+            nixStringUnwords <$> traverse go l+          v@(NVSet _ s) ->+            fromMaybe+              (err v)+              $ continueOnKey (`call` v) "__toString"+              <|> continueOnKey pure "outPath"+           where+            continueOnKey :: (NValue t f m -> m (NValue t f m)) -> VarName -> Maybe (m NixString)+            continueOnKey f = fmap (go <=< f) . (`M.lookup` s)+            err v' = throwError $ ErrorCall $ "Expected a Set that has `__toString` or `outpath`, but saw: " <> show v'+          v -> coerceStringlike v+       where+        castToNixString = pure . mkNixStringWithoutContext++        nixStringUnwords = intercalateNixString $ mkNixStringWithoutContext " "++      coerceStringlike :: NValue t f m -> m NixString+      coerceStringlike = coerceStringlikeToNixString ctsm++coerceStringlikeToNixString+  :: forall e t f m+   . ( Framed e m+     , MonadStore m+     , MonadThrow m+     , MonadDataErrorContext t f m+     , MonadValue (NValue t f m) m+     )+  => CopyToStoreMode+  -> NValue t f m+  -> m NixString+coerceStringlikeToNixString ctsm =+  (\case+    NVStr ns -> pure ns+    NVPath p -> coercePathToNixString ctsm p+    v -> throwError $ ErrorCall $ "Expected a path or string, but saw: " <> show v+  ) <=< demand++-- | Convert @Path@ into @NixString@.+-- With an additional option to store the resolved path into Nix Store.+coercePathToNixString :: (MonadStore m, Framed e m) => CopyToStoreMode -> Path -> m NixString+coercePathToNixString =+  bool+    (pure . mkNixStringWithoutContext . fromString . coerce)+    ((storePathToNixString <$>) . addPath)+    . (CopyToStore ==)+ where+  storePathToNixString :: StorePath -> NixString+  storePathToNixString (fromString . coerce -> sp) =+    (mkNixStringWithSingletonContext . StringContext DirectPath) sp sp
− src/Nix/Strings.hs
@@ -1,112 +0,0 @@-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}---- | Functions for manipulating nix strings.-module Nix.Strings where--import           Data.List (intercalate, dropWhileEnd, inits)-import           Data.Monoid ((<>))-import           Data.Text (Text)-import qualified Data.Text as T-import           Data.Tuple (swap)-import           Nix.Expr---- | Merge adjacent 'Plain' values with 'mappend'.-mergePlain :: [Antiquoted Text r] -> [Antiquoted Text r]-mergePlain [] = []-mergePlain (Plain a: EscapedNewline : Plain b: xs) =-    mergePlain (Plain (a <> "\n" <> b) : xs)-mergePlain (Plain a: Plain b: xs) = mergePlain (Plain (a <> b) : xs)-mergePlain (x:xs) = x : mergePlain xs---- | Remove 'Plain' values equal to 'mempty', as they don't have any--- informational content.-removePlainEmpty :: [Antiquoted Text r] -> [Antiquoted Text r]-removePlainEmpty = filter f where-  f (Plain x) = x /= mempty-  f _ = True--  -- trimEnd xs-  --     | null xs = xs-  --     | otherwise = case last xs of-  --           Plain x -> init xs ++ [Plain (T.dropWhileEnd (== ' ') x)]-  --           _ -> xs---- | Equivalent to case splitting on 'Antiquoted' strings.-runAntiquoted :: v -> (v -> a) -> (r -> a) -> Antiquoted v r -> a-runAntiquoted _  f _ (Plain v)      = f v-runAntiquoted nl f _ EscapedNewline = f nl-runAntiquoted _  _ k (Antiquoted r) = k r---- | Split a stream representing a string with antiquotes on line breaks.-splitLines :: [Antiquoted Text r] -> [[Antiquoted Text r]]-splitLines = uncurry (flip (:)) . go where-  go (Plain t : xs) = (Plain l :) <$> foldr f (go xs) ls where-    (l : ls) = T.split (=='\n') t-    f prefix (finished, current) = ((Plain prefix : current) : finished, [])-  go (Antiquoted a : xs) = (Antiquoted a :) <$> go xs-  go (EscapedNewline : xs) = (EscapedNewline :) <$> go xs-  go [] = ([],[])---- | Join a stream of strings containing antiquotes again. This is the inverse--- of 'splitLines'.-unsplitLines :: [[Antiquoted Text r]] -> [Antiquoted Text r]-unsplitLines = intercalate [Plain "\n"]---- | Form an indented string by stripping spaces equal to the minimal indent.-stripIndent :: [Antiquoted Text r] -> NString r-stripIndent [] = Indented 0 []-stripIndent xs =-  Indented minIndent-      . removePlainEmpty-      . mergePlain-      . map snd-      . dropWhileEnd cleanup-      . (\ys -> zip (map (\case [] -> Nothing-                                x -> Just (last x))-                        (inits ys)) ys)-      . unsplitLines $ ls'-  where-    ls = stripEmptyOpening $ splitLines xs-    ls' = map (dropSpaces minIndent) ls--    minIndent = case stripEmptyLines ls of-      [] -> 0-      nonEmptyLs -> minimum $ map (countSpaces . mergePlain) nonEmptyLs--    stripEmptyLines = filter $ \case-      [Plain t] -> not $ T.null $ T.strip t-      _ -> True--    stripEmptyOpening ([Plain t]:ts) | T.null (T.strip t) = ts-    stripEmptyOpening ts = ts--    countSpaces (Antiquoted _:_) = 0-    countSpaces (EscapedNewline:_) = 0-    countSpaces (Plain t : _) = T.length . T.takeWhile (== ' ') $ t-    countSpaces [] = 0--    dropSpaces 0 x = x-    dropSpaces n (Plain t : cs) = Plain (T.drop n t) : cs-    dropSpaces _ _ = error "stripIndent: impossible"--    cleanup (Nothing, Plain y) = T.all (== ' ') y-    cleanup (Just (Plain x), Plain y)-        | "\n" `T.isSuffixOf` x = T.all (== ' ') y-    cleanup _ = False--escapeCodes :: [(Char, Char)]-escapeCodes =-  [ ('\n', 'n' )-  , ('\r', 'r' )-  , ('\t', 't' )-  , ('\\', '\\')-  , ('$' , '$' )-  , ('"', '"')-  ]--fromEscapeCode :: Char -> Maybe Char-fromEscapeCode = (`lookup` map swap escapeCodes)--toEscapeCode :: Char -> Maybe Char-toEscapeCode = (`lookup` escapeCodes)
src/Nix/TH.hs view
@@ -1,74 +1,101 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE LambdaCase #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeSynonymInstances #-}- {-# OPTIONS_GHC -Wno-missing-fields #-}+{-# OPTIONS_GHC -Wno-type-defaults #-}  module Nix.TH where -import           Data.Fix-import           Data.Foldable-import           Data.Generics.Aliases-import           Data.Set (Set)-import qualified Data.Set as Set-import qualified Data.Text as Text+import           Data.Fix                       ( Fix(Fix) )+import           Data.Generics.Aliases          ( extQ )+import qualified Data.Set                      as Set import           Language.Haskell.TH import           Language.Haskell.TH.Quote import           Nix.Atoms-import           Nix.Expr+import           Nix.Expr.Types+import           Nix.Expr.Types.Annotated import           Nix.Parser+import           Nix.Prelude +removeMissingNames :: Set VarName -> Q (Set VarName)+removeMissingNames =+  fmap Set.fromAscList+    . filterM (fmap isJust . lookupValueName . toString)+    . Set.toAscList+ quoteExprExp :: String -> ExpQ quoteExprExp s = do-    expr <- case parseNixTextLoc (Text.pack s) of-        Failure err -> fail $ show err-        Success e   -> return e-    dataToExpQ (const Nothing `extQ` metaExp (freeVars expr)) expr+  expr <- parseExpr $ fromString s+  vars <- removeMissingNames $ getFreeVars expr+  dataToExpQ (extQOnFreeVars metaExp vars) expr  quoteExprPat :: String -> PatQ quoteExprPat s = do-    expr <- case parseNixTextLoc (Text.pack s) of-        Failure err -> fail $ show err-        Success e   -> return e-    dataToPatQ (const Nothing `extQ` metaPat (freeVars expr)) expr+  expr <- parseExpr @Q $ fromString s+  vars <- removeMissingNames $ getFreeVars expr+  dataToPatQ (extQOnFreeVars @_ @NExprLoc @PatQ metaPat vars) expr -freeVars :: NExprLoc -> Set VarName-freeVars = cata $ \case-    NSym_ _ var -> Set.singleton var-    Compose (Ann _ x) -> fold x+-- | Helper function.+extQOnFreeVars+  :: (Typeable b, Typeable loc)+  => (Set VarName -> loc -> Maybe q)+  -> Set VarName+  -> b+  -> Maybe q+extQOnFreeVars f = extQ (const Nothing) . f  class ToExpr a where-    toExpr :: a -> NExprLoc+  toExpr :: a -> NExpr -instance ToExpr NExprLoc where-    toExpr = id+instance ToExpr NExpr where+  toExpr = id  instance ToExpr VarName where-    toExpr = Fix . NSym_ nullSpan+  toExpr = Fix . NSym +instance {-# OVERLAPPING #-} ToExpr String where+  toExpr = Fix . NStr . fromString++instance ToExpr Text where+  toExpr = toExpr . toString+ instance ToExpr Int where-    toExpr = Fix . NConstant_ nullSpan . NInt . fromIntegral+  toExpr = Fix . NConstant . NInt . fromIntegral +instance ToExpr Bool where+  toExpr = Fix . NConstant . NBool+ instance ToExpr Integer where-    toExpr = Fix . NConstant_ nullSpan . NInt+  toExpr = Fix . NConstant . NInt  instance ToExpr Float where-    toExpr = Fix . NConstant_ nullSpan . NFloat+  toExpr = Fix . NConstant . NFloat -metaExp :: Set VarName -> NExprLoc -> Maybe ExpQ-metaExp fvs (Fix (NSym_ _ x)) | x `Set.member` fvs =-    Just [| toExpr $(varE (mkName (Text.unpack x))) |]+instance (ToExpr a) => ToExpr [a] where+  toExpr = Fix . NList . fmap toExpr++instance (ToExpr a) => ToExpr (NonEmpty a) where+  toExpr = toExpr . toList++instance ToExpr () where+  toExpr () = Fix $ NConstant NNull++instance (ToExpr a) => ToExpr (Maybe a) where+  toExpr = maybe (toExpr ()) toExpr++instance (ToExpr a, ToExpr b) => ToExpr (Either a b) where+  toExpr = either toExpr toExpr++metaExp :: Set VarName -> NExpr -> Maybe ExpQ+metaExp fvs (Fix (NSym x)) | x `Set.member` fvs =+  pure [| toExpr $(varE (mkName $ toString x)) |] metaExp _ _ = Nothing  metaPat :: Set VarName -> NExprLoc -> Maybe PatQ-metaPat fvs (Fix (NSym_ _ x)) | x `Set.member` fvs =-    Just (varP (mkName (Text.unpack x)))+metaPat fvs (NSymAnn _ x) | x `Set.member` fvs =+  pure $ varP $ mkName $ toString x metaPat _ _ = Nothing +-- Use of @QuasiQuoter@ requires @String@.+-- After @Text -> String@ migrations done, _maybe_ think to use @QuasiText@. nix :: QuasiQuoter-nix = QuasiQuoter-    { quoteExp = quoteExprExp-    , quotePat = quoteExprPat-    }+nix = QuasiQuoter { quoteExp = quoteExprExp, quotePat = quoteExprPat }
src/Nix/Thunk.hs view
@@ -1,111 +1,117 @@-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE DeriveFoldable #-}-{-# LANGUAGE DeriveTraversable #-}-{-# LANGUAGE CPP #-}+{-# language DefaultSignatures #-}+{-# language FunctionalDependencies #-}+{-# language TypeFamilies #-}+{-# language TypeOperators #-} -#if ENABLE_TRACING-{-# LANGUAGE BangPatterns #-}-#endif+module Nix.Thunk where -{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE TypeFamilies #-}+import           Nix.Prelude+import           Control.Monad.Trans.Writer ( WriterT )+import qualified Text.Show -module Nix.Thunk where -import Control.Exception-import Control.Monad.Catch-import Data.Typeable+-- ** @class MonadThunkId@ & @instances@ -#if ENABLE_TRACING-import Data.IORef-import System.IO.Unsafe-import Nix.Utils+class+  ( Monad m+  , Eq (ThunkId m)+  , Ord (ThunkId m)+  , Show (ThunkId m)+  , Typeable (ThunkId m)+  )+  => MonadThunkId m+ where+  type ThunkId m :: Type -counter :: IORef Int-counter = unsafePerformIO $ newIORef 0-{-# NOINLINE counter #-}-#endif+  freshId :: m (ThunkId m)+  default freshId+    :: ( MonadThunkId m'+      , MonadTrans t+      , m ~ t m'+      , ThunkId m ~ ThunkId m'+      )+    => m (ThunkId m)+  freshId = lift freshId -data Deferred m v = Deferred (m v) | Computed v-    deriving (Functor, Foldable, Traversable) -class Monad m => MonadVar m where-    type Var m :: * -> *-    newVar :: a -> m (Var m a)-    readVar :: Var m a -> m a-    writeVar :: Var m a -> a -> m ()-    atomicModifyVar :: Var m a -> (a -> (a, b)) -> m b+-- *** Instances -class Monad m => MonadThunk v t m | v -> m, v -> t, t -> m, t -> v where-    thunk :: m v -> m t-    force :: t -> (v -> m r) -> m r-    value :: v -> t+instance+  MonadThunkId m+  => MonadThunkId (ReaderT r m)+ where+  type ThunkId (ReaderT r m) = ThunkId m -data Thunk m v-    = Value v-    | Thunk Int (Var m Bool) (Var m (Deferred m v))+instance+  ( Monoid w+  , MonadThunkId m+  )+  => MonadThunkId (WriterT w m)+ where+  type ThunkId (WriterT w m) = ThunkId m -newtype ThunkLoop = ThunkLoop (Maybe Int)-    deriving (Show, Typeable)+instance+  MonadThunkId m+  => MonadThunkId (ExceptT e m)+ where+  type ThunkId (ExceptT e m) = ThunkId m -instance Exception ThunkLoop+instance+  MonadThunkId m+  => MonadThunkId (StateT s m)+ where+  type ThunkId (StateT s m) = ThunkId m -valueRef :: v -> Thunk m v-valueRef = Value -buildThunk :: MonadVar m => m v -> m (Thunk m v)-buildThunk action =-#if ENABLE_TRACING-    let !x = unsafePerformIO (atomicModifyIORef' counter (\c -> (succ c, c))) in-    Thunk x-#else-    Thunk 0-#endif-        <$> newVar False <*> newVar (Deferred action)+-- ** @class MonadThunk@ -forceThunk :: (MonadVar m, MonadThrow m) => Thunk m v -> (v -> m a) -> m a-forceThunk (Value ref) k = k ref-#if ENABLE_TRACING-forceThunk (Thunk n active ref) k = do-#else-forceThunk (Thunk _ active ref) k = do-#endif-    eres <- readVar ref-    case eres of-        Computed v -> k v-        Deferred action -> do-            nowActive <- atomicModifyVar active (True,)-            if nowActive-                then-#if ENABLE_TRACING-                    throwM $ ThunkLoop (Just n)-#else-                    throwM $ ThunkLoop Nothing-#endif-                else do-#if ENABLE_TRACING-                    traceM $ "Forcing " ++ show n-#endif-                    v <- action-                    writeVar ref (Computed v)-                    _ <- atomicModifyVar active (False,)-                    k v+class+  MonadThunkId m+  => MonadThunk t m a | t -> m, t -> a+ where -forceEffects :: MonadVar m => Thunk m v -> (v -> m a) -> m a-forceEffects (Value ref) k = k ref-forceEffects (Thunk _ active ref) k = do-    nowActive <- atomicModifyVar active (True,)-    if nowActive-        then return $ error "forceEffects: a value was expected"-        else do-            eres <- readVar ref-            case eres of-                Computed v -> k v-                Deferred action -> do-                    v <- action-                    writeVar ref (Computed v)-                    _ <- atomicModifyVar active (False,)-                    k v+  -- | Return thunk ID.+  thunkId  :: t -> ThunkId m++  -- | Create new thunk+  thunk    :: m a -> m t++  -- | Non-blocking query.+  --   If thunk got computed+  --   then return its value+  --   otherwise return default value (1st arg).+  query   :: m a -> t -> m a+  force    :: t -> m a+  forceEff :: t -> m a++  -- | Modify the action to be performed by the thunk. For some implicits+  --   this modifies the thunk, for others it may create a new thunk.+  further  :: t -> m t+++-- ** @class MonadThunk@++-- | Class of Kleisli functors for easiness of customized implementation developlemnt.+class+  MonadThunkF t m a | t -> m, t -> a+ where+  queryF   :: (a   -> m r) -> m r -> t -> m r+  forceF    :: (a   -> m r) -> t   -> m r+  forceEffF :: (a   -> m r) -> t   -> m r+  furtherF  :: (m a -> m a) -> t   -> m t+++-- ** @newtype ThunkLoop@++newtype ThunkLoop = ThunkLoop Text -- contains rendering of ThunkId+  deriving Typeable++instance Show ThunkLoop where+  show (ThunkLoop i) = toString $ "ThunkLoop " <> i++instance Exception ThunkLoop++-- ** Utils++thunkStubText :: Text+thunkStubText = "<thunk>"
+ src/Nix/Thunk/Basic.hs view
@@ -0,0 +1,227 @@+{-# language ConstraintKinds #-}+{-# language UndecidableInstances #-}+{-# options_ghc -Wno-unused-do-bind #-}+++module Nix.Thunk.Basic+  ( NThunkF(..)+  , Deferred(..)+  , deferred+  , MonadBasicThunk+  ) where++import           Nix.Prelude+import           Control.Monad.Ref              ( MonadRef(Ref, newRef, readRef, writeRef)+                                                , MonadAtomicRef(atomicModifyRef)+                                                )+import           Control.Monad.Catch            ( MonadCatch(..)+                                                , MonadThrow(throwM)+                                                )+import qualified Text.Show+import           Nix.Thunk+++-- * Data type @Deferred@++-- | Data is computed OR in a lazy thunk state which+-- is still not evaluated.+data Deferred m v = Computed v | Deferred (m v)+  deriving (Functor, Foldable, Traversable)++-- ** Utils++-- | Apply second if @Deferred@, otherwise (@Computed@) - apply first.+-- Analog of @either@ for @Deferred = Computed|Deferred@.+deferred :: (v -> b) -> (m v -> b) -> Deferred m v -> b+deferred f1 f2 =+  \case+    Computed v -> f1 v+    Deferred action -> f2 action+{-# inline deferred #-}+++-- * Thunk references & lock handling++-- | Thunk resource reference (@ref-tf: Ref m@), and as such also also hold+-- a @Bool@ lock flag.+type ThunkRef m = Ref m Bool++-- | Reference (@ref-tf: Ref m v@) to a value that the thunk holds.+type ThunkValueRef m v = Ref m (Deferred m v)++-- | @ref-tf@ lock instruction for @Ref m@ (@ThunkRef@).+lockVal :: Bool -> (Bool, Bool)+lockVal = (True, )++-- | @ref-tf@ unlock instruction for @Ref m@ (@ThunkRef@).+unlockVal :: Bool -> (Bool, Bool)+unlockVal = (False, )++-- | Takes @ref-tf: Ref m@ reference, returns Bool result of the operation.+lock+  :: ( MonadBasicThunk m+    , MonadCatch m+    )+  => ThunkRef m+  -> m Bool+lock r = atomicModifyRef r lockVal++-- | Takes @ref-tf: Ref m@ reference, returns Bool result of the operation.+unlock+  :: ( MonadBasicThunk m+    , MonadCatch m+    )+  => ThunkRef m+  -> m Bool+unlock r = atomicModifyRef r unlockVal+++-- * Data type for thunks: @NThunkF@++-- | The type of very basic thunks+data NThunkF m v =+  Thunk (ThunkId m) (ThunkRef m) (ThunkValueRef m v)++instance (Eq v, Eq (ThunkId m)) => Eq (NThunkF m v) where+  Thunk x _ _ == Thunk y _ _ = x == y++instance Show (NThunkF m v) where+  show Thunk{} = toString thunkStubText++type MonadBasicThunk m = (MonadThunkId m, MonadAtomicRef m)+++-- ** @instance MonadThunk NThunkF@++instance (MonadBasicThunk m, MonadCatch m)+  => MonadThunk (NThunkF m v) m v where++  thunkId :: NThunkF m v -> ThunkId m+  thunkId (Thunk n _ _) = n++  thunk :: m v -> m (NThunkF m v)+  thunk action =+    do+      freshThunkId <- freshId+      liftA2 (Thunk freshThunkId)+        (newRef   False          )+        (newRef $ Deferred action)++  query :: m v -> NThunkF m v -> m v+  query vStub (Thunk _ _ lTValRef) =+    deferred pure (const vStub) =<< readRef lTValRef++  force :: NThunkF m v -> m v+  force = forceMain++  forceEff :: NThunkF m v -> m v+  forceEff = forceMain++  further :: NThunkF m v -> m (NThunkF m v)+  further t@(Thunk _ _ ref) =+    const (pure t) =<< atomicModifyRef ref dup+++-- *** United body of `force*`++-- | Always returns computed @m v@.+--+-- Checks if resource is computed,+-- if not - with locking evaluates the resource.+forceMain+  :: forall v m+   . ( MonadBasicThunk m+    , MonadCatch m+    )+  => NThunkF m v+  -> m v+forceMain (Thunk tIdV tRefV tValRefV) =+  deferred pure computeW =<< readRef tValRefV+ where+  computeW :: m v -> m v+  computeW vDefferred =+    do+      locked <- lock tRefV+      bool+        lockFailedV+        (do+          v <- vDefferred `catch` bindFailedW+          writeRef tValRefV $ Computed v  -- Proclaim value computed+          unlockRef+          pure v+        )+        $ not locked+   where+    lockFailedV :: m a+    lockFailedV = throwM $ ThunkLoop $ show tIdV++    bindFailedW :: SomeException -> m b+    bindFailedW (e :: SomeException) =+      do+        unlockRef+        throwM e++    unlockRef :: m Bool+    unlockRef = unlock tRefV+{-# inline forceMain #-} -- it is big function, but internal, and look at its use.++++-- ** Kleisli functor HOFs: @instance MonadThunkF NThunkF@++instance (MonadBasicThunk m, MonadCatch m)+  => MonadThunkF (NThunkF m v) m v where++  queryF+    :: (v -> m r)+    -> m r+    -> NThunkF m v+    -> m r+  queryF k n (Thunk _ thunkRef thunkValRef) =+    do+      locked <- lock thunkRef+      bool+        n+        go+        (not locked)+    where+      go =+        do+          eres <- readRef thunkValRef+          res  <-+            deferred+              k+              (const n)+              eres+          unlockRef+          pure res++      unlockRef = unlock thunkRef++  forceF+    :: (v -> m a)+    -> NThunkF m v+    -> m a+  forceF k = k <=< force++  forceEffF+    :: (v -> m r)+    -> NThunkF m v+    -> m r+  forceEffF k = k <=< forceEff++  furtherF+    :: (m v -> m v)+    -> NThunkF m v+    -> m (NThunkF m v)+  furtherF k t@(Thunk _ _ ref) =+    do+      _modifiedIt <- atomicModifyRef ref $+        \x ->+          deferred+            (const (x, x))+            (\ d -> (Deferred (k d), x))+            x+      pure t++
src/Nix/Type/Assumption.hs view
@@ -1,44 +1,74 @@-module Nix.Type.Assumption (-  Assumption(..),-  empty,-  lookup,-  remove,-  extend,-  keys,-  merge,-  mergeAssumptions,-  singleton,-) where+{-# language TypeFamilies #-} -import Prelude hiding (lookup)+-- | Basing on the Nix (Hindley–Milner) type system (that provides decidable type inference):+-- gathering assumptions (inference evidence) about polymorphic types.+module Nix.Type.Assumption+  ( Assumption(..)+  , empty+  , lookup+  , remove+  , extend+  , keys+  , merge+  , singleton+  )+where -import Nix.Type.Type+import           Nix.Prelude             hiding ( Type+                                                , empty+                                                ) -import Data.Foldable+import           Nix.Expr.Types+import           Nix.Type.Type -newtype Assumption = Assumption { assumptions :: [(Name, Type)] }+newtype Assumption = Assumption [(VarName, Type)]   deriving (Eq, Show) +-- We pretend that Assumptions can be inconsistent (nonunique keys),+-- (just like people in real life).+-- The consistency between assumptions is the inference responcibility.+instance Semigroup Assumption where+  (<>) = merge++instance Monoid Assumption where+  mempty = empty++instance One Assumption where+  type OneItem Assumption = (VarName, Type)+  one vt = Assumption $ one vt++--  2022-01-12: NOTE: `empty` implies Alternative. Either have Alternative or use `mempty` empty :: Assumption-empty = Assumption []+empty = Assumption mempty -extend :: Assumption -> (Name, Type) -> Assumption-extend (Assumption a) (x, s) = Assumption ((x, s) : a)+extend :: Assumption -> (VarName, Type) -> Assumption+extend a vt =+  one (coerce vt) <> a -remove :: Assumption -> Name -> Assumption-remove (Assumption a) var = Assumption (filter (\(n, _) -> n /= var) a)+remove :: Assumption -> VarName -> Assumption+remove a var =+  coerce+    rmVar+    a+ where+  rmVar :: [(VarName, Type)] -> [(VarName, Type)]+  rmVar =+    filter+      ((/=) var . fst) -lookup :: Name -> Assumption -> [Type]-lookup key (Assumption a) = map snd (filter (\(n, _) -> n == key) a)+lookup :: VarName -> Assumption -> [Type]+lookup key a =+  snd <$>+    filter+      ((==) key . fst)+      (coerce a)  merge :: Assumption -> Assumption -> Assumption-merge (Assumption a) (Assumption b) = Assumption (a ++ b)--mergeAssumptions :: [Assumption] -> Assumption-mergeAssumptions = foldl' merge empty+merge =+  coerce ((<>) @[(VarName, Type)]) -singleton :: Name -> Type -> Assumption-singleton x y = Assumption [(x, y)]+singleton :: VarName -> Type -> Assumption+singleton = curry one -keys :: Assumption -> [Name]-keys (Assumption a) = map fst a+keys :: Assumption -> [VarName]+keys (Assumption a) = fst <$> a
src/Nix/Type/Env.hs view
@@ -1,70 +1,82 @@-module Nix.Type.Env (-  Env(..),-  empty,-  lookup,-  remove,-  extend,-  extends,-  merge,-  mergeEnvs,-  singleton,-  keys,-  fromList,-  toList,-) where+{-# language TypeFamilies #-} -import           Prelude hiding (lookup)+module Nix.Type.Env+  ( Env(..)+  , empty+  , lookup+  , remove+  , extend+  , extends+  , merge+  , mergeEnvs+  , singleton+  , keys+  , fromList+  , toList+  )+where +import           Nix.Prelude             hiding ( empty+                                                , toList+                                                , fromList+                                                )++import           Nix.Expr.Types import           Nix.Type.Type -import           Data.Foldable hiding (toList)-import qualified Data.Map as Map-import           Data.Semigroup+import qualified Data.Map                      as Map ----------------------------------------------------------------------------------- Typing Environment-------------------------------------------------------------------------------- -newtype Env = TypeEnv { types :: Map.Map Name [Scheme] }+-- * Typing Environment++newtype Env = TypeEnv (Map VarName [Scheme])   deriving (Eq, Show) +instance Semigroup Env where+  -- | Right-biased merge (override). Analogous to @//@ in @Nix@+  -- Since nature of environment is to update & grow.+  (<>) = mergeRight++instance Monoid Env where+  mempty = empty++instance One Env where+  type OneItem Env = (VarName, Scheme)+  one (x, y) = TypeEnv $ one (x, one y)+ empty :: Env-empty = TypeEnv Map.empty+empty = TypeEnv mempty -extend :: Env -> (Name, [Scheme]) -> Env-extend env (x, s) = env { types = Map.insert x s (types env) }+extend :: Env -> (VarName, [Scheme]) -> Env+extend env (x, s) = coerce (Map.insert x s) env -remove :: Env -> Name -> Env-remove (TypeEnv env) var = TypeEnv (Map.delete var env)+remove :: Env -> VarName -> Env+remove env var = TypeEnv $ Map.delete var $ coerce env -extends :: Env -> [(Name, [Scheme])] -> Env-extends env xs =-    env { types = Map.union (Map.fromList xs) (types env) }+extends :: Env -> [(VarName, [Scheme])] -> Env+extends env xs = fromList xs <> coerce env -lookup :: Name -> Env -> Maybe [Scheme]-lookup key (TypeEnv tys) = Map.lookup key tys+lookup :: VarName -> Env -> Maybe [Scheme]+lookup key tys = Map.lookup key $ coerce tys  merge :: Env -> Env -> Env-merge (TypeEnv a) (TypeEnv b) = TypeEnv (Map.union a b)+merge a b = TypeEnv $ coerce a <> coerce b +mergeRight :: Env -> Env -> Env+mergeRight = flip merge+ mergeEnvs :: [Env] -> Env-mergeEnvs = foldl' merge empty+mergeEnvs = foldl' (<>) mempty -singleton :: Name -> Scheme -> Env-singleton x y = TypeEnv (Map.singleton x [y])+singleton :: VarName -> Scheme -> Env+singleton = curry one -keys :: Env -> [Name]+keys :: Env -> [VarName] keys (TypeEnv env) = Map.keys env -fromList :: [(Name, [Scheme])] -> Env-fromList xs = TypeEnv (Map.fromList xs)+fromList :: [(VarName, [Scheme])] -> Env+fromList xs = coerce $ Map.fromList xs -toList :: Env -> [(Name, [Scheme])]+toList :: Env -> [(VarName, [Scheme])] toList (TypeEnv env) = Map.toList env -instance Semigroup Env where-  (<>) = merge--instance Monoid Env where-  mempty = empty-  mappend = merge
src/Nix/Type/Infer.hs view
@@ -1,612 +1,853 @@-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeSynonymInstances #-}--{-# OPTIONS_GHC -Wno-name-shadowing #-}--module Nix.Type.Infer (-  Constraint(..),-  TypeError(..),-  InferError(..),-  Subst(..),-  inferTop-) where--import           Control.Applicative-import           Control.Arrow-import           Control.Monad.Catch-import           Control.Monad.Except-import           Control.Monad.Logic-import           Control.Monad.Reader-import           Control.Monad.ST-import           Control.Monad.State-import           Data.Fix-import           Data.Foldable-import qualified Data.HashMap.Lazy as M-import           Data.List (delete, find, nub, intersect, (\\))-import           Data.Map (Map)-import qualified Data.Map as Map-import           Data.Maybe (fromJust)-import           Data.STRef-import           Data.Semigroup-import qualified Data.Set as Set-import           Data.Text (Text)-import           Nix.Atoms-import           Nix.Convert-import           Nix.Eval (MonadEval(..))-import qualified Nix.Eval as Eval-import           Nix.Expr.Types-import           Nix.Expr.Types.Annotated-import           Nix.Scope-import           Nix.Thunk-import qualified Nix.Type.Assumption as As-import           Nix.Type.Env-import qualified Nix.Type.Env as Env-import           Nix.Type.Type-import           Nix.Utils------------------------------------------------------------------------------------ Classes------------------------------------------------------------------------------------ | Inference monad-newtype Infer s a = Infer-    { getInfer ::-        ReaderT (Set.Set TVar, Scopes (Infer s) (JThunk s))-            (StateT InferState (ExceptT InferError (ST s))) a-    }-    deriving (Functor, Applicative, Alternative, Monad, MonadPlus, MonadFix,-              MonadReader (Set.Set TVar, Scopes (Infer s) (JThunk s)),-              MonadState InferState, MonadError InferError)---- | Inference state-newtype InferState = InferState { count :: Int }---- | Initial inference state-initInfer :: InferState-initInfer = InferState { count = 0 }--data Constraint-    = EqConst Type Type-    | ExpInstConst Type Scheme-    | ImpInstConst Type (Set.Set TVar) Type-    deriving (Show, Eq, Ord)--newtype Subst = Subst (Map TVar Type)-  deriving (Eq, Ord, Show, Semigroup, Monoid)--class Substitutable a where-  apply :: Subst -> a -> a--instance Substitutable TVar where-  apply (Subst s) a = tv-    where t = TVar a-          (TVar tv) = Map.findWithDefault t a s--instance Substitutable Type where-  apply _ (TCon a)           = TCon a-  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 :~> t2)        = apply s t1 :~> apply s t2-  apply s (TMany ts)         = TMany (map (apply s) ts)--instance Substitutable Scheme where-  apply (Subst s) (Forall as t) = Forall as $ apply s' t-    where s' = Subst $ foldr Map.delete s as--instance Substitutable Constraint where-   apply s (EqConst t1 t2)         = EqConst (apply s t1) (apply s t2)-   apply s (ExpInstConst t sc)     = ExpInstConst (apply s t) (apply s sc)-   apply s (ImpInstConst t1 ms t2) = ImpInstConst (apply s t1) (apply s ms) (apply s t2)--instance Substitutable a => Substitutable [a] where-  apply = map . apply--instance (Ord a, Substitutable a) => Substitutable (Set.Set a) where-  apply = Set.map . apply---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 :~> t2) = ftv t1 `Set.union` ftv t2-  ftv (TMany ts)  = Set.unions (map ftv ts)--instance FreeTypeVars TVar where-  ftv = Set.singleton--instance FreeTypeVars Scheme where-  ftv (Forall as t) = ftv t `Set.difference` Set.fromList as--instance FreeTypeVars a => FreeTypeVars [a] where-  ftv   = foldr (Set.union . ftv) Set.empty--instance (Ord a, FreeTypeVars a) => FreeTypeVars (Set.Set a) where-  ftv   = foldr (Set.union . ftv) Set.empty---class ActiveTypeVars a where-  atv :: a -> Set.Set TVar--instance ActiveTypeVars Constraint where-  atv (EqConst t1 t2)         = ftv t1 `Set.union` ftv t2-  atv (ImpInstConst t1 ms t2) = ftv t1 `Set.union` (ftv ms `Set.intersection` ftv t2)-  atv (ExpInstConst t s)      = ftv t `Set.union` ftv s--instance ActiveTypeVars a => ActiveTypeVars [a] where-  atv = foldr (Set.union . atv) Set.empty--data TypeError-  = UnificationFail Type Type-  | InfiniteType TVar Type-  | UnboundVariables [Text]-  | Ambigious [Constraint]-  | UnificationMismatch [Type] [Type]-  deriving (Eq, Show)--data InferError-  = TypeInferenceErrors [TypeError]-  | TypeInferenceAborted-  | forall s. Exception s => EvaluationError s--typeError :: MonadError InferError m => TypeError -> m ()-typeError err = throwError $ TypeInferenceErrors [err]--deriving instance Show InferError-instance Exception InferError--instance Semigroup InferError where-    x <> _ = x--instance Monoid InferError where-    mempty  = TypeInferenceAborted-    mappend = (<>)------------------------------------------------------------------------------------ Inference------------------------------------------------------------------------------------ | Run the inference monad-runInfer' :: Infer s a -> ST s (Either InferError a)-runInfer' = runExceptT-          . (`evalStateT` initInfer)-          . (`runReaderT` (Set.empty, emptyScopes))-          . getInfer--runInfer :: (forall s. Infer s a) -> Either InferError a-runInfer m = runST (runInfer' m)--inferType :: Env -> NExpr -> Infer s [(Subst, Type)]-inferType env ex = do-  Judgment as cs t <- infer ex-  let unbounds = Set.fromList (As.keys as) `Set.difference`-                 Set.fromList (Env.keys env)-  unless (Set.null unbounds) $-      typeError $ UnboundVariables (nub (Set.toList unbounds))-  let cs' = [ ExpInstConst t s-            | (x, ss) <- Env.toList env-            , s <- ss-            , t <- As.lookup x as]-  inferState <- get-  let eres = (`evalState` inferState) $ runSolver $ do-          subst <- solve (cs ++ cs')-          return (subst, subst `apply` t)-  case eres of-      Left errs -> throwError $ TypeInferenceErrors errs-      Right xs  -> pure xs---- | Solve for the toplevel type of an expression in a given environment-inferExpr :: Env -> NExpr -> Either InferError [Scheme]-inferExpr env ex = case runInfer (inferType env ex) of-  Left err -> Left err-  Right xs -> Right $ map (\(subst, ty) -> closeOver (subst `apply` ty)) xs---- | Canonicalize and return the polymorphic toplevel type.-closeOver :: Type -> Scheme-closeOver = normalize . generalize Set.empty--extendMSet :: TVar -> Infer s a -> Infer s a-extendMSet x = Infer . local (first (Set.insert x)) . getInfer--letters :: [String]-letters = [1..] >>= flip replicateM ['a'..'z']--fresh :: MonadState InferState m => m Type-fresh = do-    s <- get-    put s{count = count s + 1}-    return $ TVar $ TV (letters !! count s)--instantiate :: MonadState InferState m => Scheme -> m Type-instantiate (Forall as t) = do-    as' <- mapM (const fresh) as-    let s = Subst $ Map.fromList $ zip as as'-    return $ apply s t--generalize :: Set.Set TVar -> Type -> Scheme-generalize free t  = Forall as t-    where as = Set.toList $ ftv t `Set.difference` free--unops :: Type -> NUnaryOp -> [Constraint]-unops u1 = \case-    NNot -> [ EqConst u1 (typeFun [typeBool, typeBool]) ]-    NNeg -> [ EqConst u1 (TMany [ typeFun [typeInt,   typeInt]-                               , typeFun [typeFloat, typeFloat] ]) ]--binops :: Type -> NBinaryOp -> [Constraint]-binops u1 = \case-    NApp    -> []                -- this is handled separately--    -- Equality tells you nothing about the types, because any two types are-    -- allowed.-    NEq     -> []-    NNEq    -> []--    NGt     -> inequality-    NGte    -> inequality-    NLt     -> inequality-    NLte    -> inequality--    NAnd    -> [ EqConst u1 (typeFun [typeBool, typeBool, typeBool]) ]-    NOr     -> [ EqConst u1 (typeFun [typeBool, typeBool, typeBool]) ]-    NImpl   -> [ EqConst u1 (typeFun [typeBool, typeBool, typeBool]) ]--    NConcat -> [ EqConst u1 (TMany [ typeFun [typeList,   typeList,   typeList]-                                  , typeFun [typeList,   typeNull,   typeList]-                                  , typeFun [typeNull,   typeList,   typeList]-                                  ]) ]--    NUpdate -> [ EqConst u1 (TMany [ typeFun [typeSet,    typeSet,    typeSet]-                                  , typeFun [typeSet,    typeNull,   typeSet]-                                  , typeFun [typeNull,   typeSet,    typeSet]-                                  ]) ]--    NPlus   -> [ EqConst u1 (TMany [ typeFun [typeInt,    typeInt,    typeInt]-                                  , typeFun [typeFloat,  typeFloat,  typeFloat]-                                  , typeFun [typeInt,    typeFloat,  typeFloat]-                                  , typeFun [typeFloat,  typeInt,    typeFloat]-                                  , typeFun [typeString, typeString, typeString]-                                  , typeFun [typePath,   typePath,   typePath]-                                  , typeFun [typeString, typeString, typePath]-                                  ]) ]-    NMinus  -> arithmetic-    NMult   -> arithmetic-    NDiv    -> arithmetic-  where-    inequality =-        [ EqConst u1 (TMany [ typeFun [typeInt,    typeInt,    typeBool]-                            , typeFun [typeFloat,  typeFloat,  typeBool]-                            , typeFun [typeInt,    typeFloat,  typeBool]-                            , typeFun [typeFloat,  typeInt,    typeBool]-                            ]) ]--    arithmetic =-        [ EqConst u1 (TMany [ typeFun [typeInt,    typeInt,    typeInt]-                            , typeFun [typeFloat,  typeFloat,  typeFloat]-                            , typeFun [typeInt,    typeFloat,  typeFloat]-                            , typeFun [typeFloat,  typeInt,    typeFloat]-                            ]) ]--instance MonadVar (Infer s) where-    type Var (Infer s) = STRef s--    newVar x     = Infer $ lift $ lift $ lift $ newSTRef x-    readVar x    = Infer $ lift $ lift $ lift $ readSTRef x-    writeVar x y = Infer $ lift $ lift $ lift $ writeSTRef x y-    atomicModifyVar x f = Infer $ lift $ lift $ lift $ do-        res <- snd . f <$> readSTRef x-        _ <- modifySTRef x (fst . f)-        return res--newtype JThunk s = JThunk (Thunk (Infer s) (Judgment s))--instance MonadThrow (Infer s) where-    throwM = throwError . EvaluationError--instance MonadCatch (Infer s) where-    catch m h = catchError m $ \case-        EvaluationError e ->-            maybe (error $ "Exception was not an exception: " ++ show e) h-                  (fromException (toException e))-        err -> error $ "Unexpected error: " ++ show err--instance MonadThunk (Judgment s) (JThunk s) (Infer s) where-    thunk = fmap JThunk . buildThunk--    force (JThunk t) f = catch (forceThunk t f) $ \(_ :: ThunkLoop) ->-        -- If we have a thunk loop, we just don't know the type.-        f =<< Judgment As.empty [] <$> fresh--    value = JThunk . valueRef--instance MonadEval (Judgment s) (Infer s) where-    freeVariable var = do-        tv <- fresh-        return $ Judgment (As.singleton var tv) [] tv--    -- If we fail to look up an attribute, we just don't know the type.-    attrMissing _ _ = Judgment As.empty [] <$> fresh--    evaledSym _ = pure--    evalCurPos =-        return $ Judgment As.empty [] $ TSet False $ M.fromList-            [ ("file", typePath)-            , ("line", typeInt)-            , ("col",  typeInt) ]--    evalConstant c  = return $ Judgment As.empty [] (go c)-      where-        go = \case-          NInt _   -> typeInt-          NFloat _ -> typeFloat-          NBool _  -> typeBool-          NNull    -> typeNull--    evalString      = const $ return $ Judgment As.empty [] typeString-    evalLiteralPath = const $ return $ Judgment As.empty [] typePath-    evalEnvPath     = const $ return $ Judgment As.empty [] typePath--    evalUnary op (Judgment as1 cs1 t1) = do-        tv <- fresh-        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 :~> t2 :~> tv) op)-            tv--    evalWith = Eval.evalWithAttrSet--    evalIf (Judgment as1 cs1 t1) t f = do-        Judgment as2 cs2 t2 <- t-        Judgment as3 cs3 t3 <- f-        return $ Judgment-            (as1 `As.merge` as2 `As.merge` as3)-            (cs1 ++ cs2 ++ cs3 ++ [EqConst t1 typeBool, EqConst t2 t3])-            t2--    evalAssert (Judgment as1 cs1 t1) body = do-        Judgment as2 cs2 t2 <- body-        return $ Judgment-            (as1 `As.merge` as2)-            (cs1 ++ cs2 ++ [EqConst t1 typeBool])-            t2--    evalApp (Judgment as1 cs1 t1) e2 = do-        Judgment as2 cs2 t2 <- e2-        tv <- fresh-        return $ Judgment-            (as1 `As.merge` as2)-            (cs1 ++ cs2 ++ [EqConst t1 (t2 :~> tv)])-            tv--    evalAbs (Param x) k = do-        tv@(TVar a) <- fresh-        ((), Judgment as cs t) <--            extendMSet a (k (pure (Judgment (As.singleton x tv) [] tv))-                            (\_ b -> ((),) <$> b))-        return $ Judgment-            (as `As.remove` x)-            (cs ++ [EqConst t' tv | t' <- As.lookup x as])-            (tv :~> t)--    evalAbs (ParamSet ps variadic _mname) k = do-        js <- fmap concat $ forM ps $ \(name, _) -> do-                tv <- fresh-                pure [(name, tv)]--        let (env, tys) = (\f -> foldl' f (As.empty, M.empty) js)-                $ \(as1, t1) (k, t) ->-                    (as1 `As.merge` As.singleton k t, M.insert k t t1)-            arg   = pure $ Judgment env [] (TSet True tys)-            call  = k arg $ \args b -> (args,) <$> b-            names = map fst js--        (args, Judgment as cs t) <--            foldr (\(_, TVar a) -> extendMSet a) call js--        ty <- TSet variadic <$> traverse (inferredType <$>) args--        return $ Judgment-            (foldl' As.remove as names)-            (cs ++ [ EqConst t' (tys M.! x)-                   | x  <- names-                   , t' <- As.lookup x as])-            (ty :~> t)--    evalError = throwError . EvaluationError--data Judgment s = Judgment-    { assumptions     :: As.Assumption-    , typeConstraints :: [Constraint]-    , inferredType    :: Type-    }-    deriving Show--instance FromValue (Text, DList Text) (Infer s) (Judgment s) where-    fromValueMay _ = return Nothing-    fromValue _ = error "Unused"--instance FromValue (AttrSet (JThunk s), AttrSet SourcePos) (Infer s) (Judgment s) where-    fromValueMay (Judgment _ _ (TSet _ xs)) = do-        let sing _ = Judgment As.empty []-        pure $ Just (M.mapWithKey (\k v -> value (sing k v)) xs, M.empty)-    fromValueMay _ = pure Nothing-    fromValue = fromValueMay >=> \case-        Just v  -> pure v-        Nothing -> pure (M.empty, M.empty)--instance ToValue (AttrSet (JThunk s), AttrSet SourcePos) (Infer s) (Judgment s) where-    toValue (xs, _) = Judgment-        <$> foldrM go As.empty xs-        <*> (concat <$> traverse (`force` (pure . typeConstraints)) xs)-        <*> (TSet True <$> traverse (`force` (pure . inferredType)) xs)-      where-        go x rest = force x $ \x' -> pure $ As.merge (assumptions x') rest--instance ToValue [JThunk s] (Infer s) (Judgment s) where-    toValue xs = Judgment-        <$> foldrM go As.empty xs-        <*> (concat <$> traverse (`force` (pure . typeConstraints)) xs)-        <*> (TList <$> traverse (`force` (pure . inferredType)) xs)-      where-        go x rest = force x $ \x' -> pure $ As.merge (assumptions x') rest--instance ToValue Bool (Infer s) (Judgment s) where-    toValue _ = pure $ Judgment As.empty [] typeBool--infer :: NExpr -> Infer s (Judgment s)-infer = cata Eval.eval--inferTop :: Env -> [(Text, NExpr)] -> Either InferError Env-inferTop env [] = Right env-inferTop env ((name, ex):xs) = case inferExpr env ex of-  Left err -> Left err-  Right ty -> inferTop (extend env (name, ty)) xs--normalize :: Scheme -> Scheme-normalize (Forall _ body) = Forall (map snd ord) (normtype body)-  where-    ord = zip (nub $ fv body) (map TV letters)--    fv (TVar a)    = [a]-    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 (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"------------------------------------------------------------------------------------ Constraint Solver----------------------------------------------------------------------------------newtype Solver m a = Solver (LogicT (StateT [TypeError] m) a)-    deriving (Functor, Applicative, Alternative, Monad, MonadPlus,-              MonadLogic, MonadState [TypeError])--instance MonadTrans Solver where-    lift = Solver . lift . lift--instance Monad m => MonadError TypeError (Solver m) where-    throwError err = Solver $ lift (modify (err:)) >> mzero-    catchError _ _ = error "This is never used"--runSolver :: Monad m => Solver m a -> m (Either [TypeError] [a])-runSolver (Solver s) = do-    res <- runStateT (observeAllT s) []-    pure $ case res of-        (x:xs, _) -> Right (x:xs)-        (_, es)   -> Left (nub es)---- | The empty substitution-emptySubst :: Subst-emptySubst = mempty---- | Compose substitutions-compose :: Subst -> Subst -> Subst-Subst s1 `compose` Subst s2 =-    Subst $ Map.map (apply (Subst s1)) s2 `Map.union` s1--unifyMany :: Monad m => [Type] -> [Type] -> Solver m Subst-unifyMany [] [] = return emptySubst-unifyMany (t1 : ts1) (t2 : ts2) =-  do su1 <- unifies t1 t2-     su2 <- unifyMany (apply su1 ts1) (apply su1 ts2)-     return (su2 `compose` su1)-unifyMany t1 t2 = throwError $ UnificationMismatch t1 t2--allSameType :: [Type] -> Bool-allSameType [] = True-allSameType [_] = True-allSameType (x:y:ys) = x == y && allSameType (y:ys)--unifies :: Monad m => Type -> Type -> Solver m Subst-unifies t1 t2 | t1 == t2 = return emptySubst-unifies (TVar v) t = v `bind` t-unifies t (TVar v) = v `bind` t-unifies (TList xs) (TList ys)-    | allSameType xs && allSameType ys = case (xs, ys) of-          (x:_, y:_) -> unifies x y-          _ -> return emptySubst-    | length xs == length ys = unifyMany xs ys--- We assume that lists of different lengths containing various types cannot--- be unified.-unifies t1@(TList _) t2@(TList _) = throwError $ UnificationFail t1 t2-unifies (TSet True _) (TSet True _) = return emptySubst-unifies (TSet False b) (TSet True s)-    | M.keys b `intersect` M.keys s == M.keys s = return emptySubst-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 (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--bind :: Monad m => TVar -> Type -> Solver m Subst-bind a t | t == TVar a     = return emptySubst-         | occursCheck a t = throwError $ InfiniteType a t-         | otherwise       = return (Subst $ Map.singleton a t)--occursCheck ::  FreeTypeVars a => TVar -> a -> Bool-occursCheck a t = a `Set.member` ftv t--nextSolvable :: [Constraint] -> (Constraint, [Constraint])-nextSolvable xs = fromJust (find solvable (chooseOne xs))-  where-    chooseOne xs = [(x, ys) | x <- xs, let ys = delete x xs]--    solvable (EqConst{}, _)      = True-    solvable (ExpInstConst{}, _) = True-    solvable (ImpInstConst _t1 ms t2, cs) =-        Set.null ((ftv t2 `Set.difference` ms) `Set.intersection` atv cs)--considering :: [a] -> Solver m a-considering xs = Solver $ LogicT $ \c n -> foldr c n xs--solve :: MonadState InferState m => [Constraint] -> Solver m Subst-solve [] = return emptySubst-solve cs = solve' (nextSolvable cs)-  where-    solve' (EqConst t1 t2, cs) =-      unifies t1 t2 >>- \su1 ->-      solve (apply su1 cs) >>- \su2 ->-          return (su2 `compose` su1)--    solve' (ImpInstConst t1 ms t2, cs) =-      solve (ExpInstConst t1 (generalize ms t2) : cs)--    solve' (ExpInstConst t s, cs) = do-      s' <- lift $ instantiate s-      solve (EqConst t s' : cs)+{-# language MultiWayIf #-}+{-# language CPP #-}+{-# language AllowAmbiguousTypes #-}+{-# language ConstraintKinds #-}+{-# language ExistentialQuantification #-}+{-# language GeneralizedNewtypeDeriving #-}+{-# language RankNTypes #-}+{-# language TypeFamilies #-}++{-# options_ghc -Wno-name-shadowing #-}++module Nix.Type.Infer+  ( Constraint(..)+  , TypeError(..)+  , InferError(..)+  , Subst(..)+  , inferTop+  )+where++import           Nix.Prelude             hiding ( Constraint+                                                , Type+                                                , TVar+                                                )+import           Control.Monad.Catch            ( MonadThrow(..)+                                                , MonadCatch(..)+                                                )+import           Control.Monad.Except           ( MonadError(throwError,catchError) )+import           Control.Monad.Logic+import           Control.Monad.Fix              ( MonadFix )+import           Control.Monad.Ref              ( MonadAtomicRef(..)+                                                , MonadRef(..)+                                                )+import           Control.Monad.ST               ( ST+                                                , runST+                                                )+import           Data.Fix                       ( foldFix )+import qualified Data.HashMap.Lazy             as M+import           Data.List                      ( delete+                                                , intersect+                                                , (\\)+                                                , (!!)+                                                )+import qualified Data.List                     as List+import qualified Data.Map                      as Map+import           Data.Maybe                     ( fromJust )+import qualified Data.Set                      as Set+import           Nix.Atoms+import           Nix.Convert+import           Nix.Eval                       ( MonadEval(..) )+import qualified Nix.Eval                      as Eval+                                                ( eval+                                                , evalWithAttrSet+                                                )+import           Nix.Expr.Types+import           Nix.Fresh+import           Nix.String+import           Nix.Scope+import           Nix.Type.Assumption     hiding ( extend )+import qualified Nix.Type.Assumption           as Assumption+import           Nix.Type.Env+import qualified Nix.Type.Env                  as Env+import           Nix.Type.Type+import           Nix.Value.Monad+++normalizeScheme :: Scheme -> Scheme+normalizeScheme (Forall _ body) = Forall (snd <$> ord) (normtype body)+ where+  ord =+    zip+      (ordNub $ fv body)+      (TV . fromString <$> letters)++  fv (TVar a  ) = one a+  fv (a :~> b ) = on (<>) fv a b+  fv (TCon _  ) = mempty+  fv (TSet _ a) = foldMap fv $ M.elems a+  fv (TList a ) = foldMap fv a+  fv (TMany ts) = foldMap fv ts++  normtype (a :~> b ) = normtype a :~> normtype b+  normtype (TCon a  ) = TCon a+  normtype (TSet b a) = TSet b $ normtype <$> a+  normtype (TList a ) = TList $ normtype <$> a+  normtype (TMany ts) = TMany $ normtype <$> ts+  normtype (TVar  a ) =+    maybe+      (error "type variable not in signature")+      TVar+      (List.lookup a ord)++generalize :: Set.Set TVar -> Type -> Scheme+generalize free t = Forall as t+ where+  as = Set.toList $ free `Set.difference` ftv t++-- | Canonicalize and return the polymorphic toplevel type.+closeOver :: Type -> Scheme+closeOver = normalizeScheme . generalize mempty++-- When `[]` becomes `NonEmpty` - function becomes just `all`+-- | Check if all elements are of the same type.+allSameType :: [Type] -> Bool+allSameType = allSame+ where+  allSame :: Eq a => [a] -> Bool+  allSame [] = True+  allSame (x:xs) = all (x ==) xs++-- * data type @TypeError@++data TypeError+  = UnificationFail Type Type+  | InfiniteType TVar Type+  | UnboundVariables [VarName]+  | Ambigious [Constraint]+  | UnificationMismatch [Type] [Type]+  deriving (Eq, Show, Ord)++-- * @InferError@++data InferError+  = TypeInferenceErrors [TypeError]+  | TypeInferenceAborted+  | forall s. Exception s => EvaluationError s++typeError :: MonadError InferError m => TypeError -> m ()+typeError err = throwError $ TypeInferenceErrors $ one err++-- ** Instances++deriving instance Show InferError+instance Exception InferError++instance Semigroup InferError where+  (<>) = const++instance Monoid InferError where+  mempty  = TypeInferenceAborted++-- * @InferState@: inference state++-- | Inference state (stage).+newtype InferState = InferState Int+ deriving+  (Eq, Num, Enum, Ord)++instance Semigroup InferState where+  (<>) = (+)++instance Monoid InferState where+  mempty = 0++-- | Initial inference state+initInfer :: InferState+initInfer = InferState 0++letters :: [String]+letters =+  do+    l <- [1 ..]+    replicateM+      l+      ['a' .. 'z']++freshTVar :: MonadState InferState m => m TVar+freshTVar =+  do+    s <- get+    put $ succ s+    pure $ TV $ fromString $ letters !! coerce s++fresh :: MonadState InferState m => m Type+fresh = TVar <$> freshTVar++intoFresh :: (Traversable t, MonadState InferState f) => t a -> f (t Type)+intoFresh =+  traverse (const fresh)++instantiate :: MonadState InferState m => Scheme -> m Type+instantiate (Forall as t) =+  fmap ((`apply` t) . coerce . Map.fromList . zip as) (intoFresh as)++-- * @Constraint@ data type++data Constraint+  = EqConst Type Type+  | ExpInstConst Type Scheme+  | ImpInstConst Type (Set.Set TVar) Type+  deriving (Show, Eq, Ord)++-- * @Subst@ data type++-- | Substitution of the basic type definition by a type variable.+newtype Subst = Subst (Map TVar Type)+  deriving (Eq, Ord, Show, Semigroup, Monoid)++-- | Compose substitutions+compose :: Subst -> Subst -> Subst+compose a@(Subst s2) (Subst s1) =+  coerce $ --+    apply a <$>+      (s2 <> s1)++-- * class @Substitutable@++class Substitutable a where+  apply :: Subst -> a -> a++-- ** Instances++instance Substitutable TVar where+  apply (Subst s) a = tv+   where+    (TVar tv) = Map.findWithDefault (TVar a) a s++instance Substitutable Type where+  apply _         (  TCon a   ) = TCon a+  apply s         (  TSet b a ) = TSet b $ apply s <$> a+  apply s         (  TList a  ) = TList  $ apply s <$> a+  apply (Subst s) t@(TVar  a  ) = Map.findWithDefault t a s+  apply s         (  t1 :~> t2) = ((:~>) `on` apply s) t1 t2+  apply s         (  TMany ts ) = TMany  $ apply s <$> ts++instance Substitutable Scheme where+  apply (Subst s) (Forall as t) = Forall as $ apply s' t+   where+    s' = Subst $ foldr Map.delete s as++instance Substitutable Constraint where+  apply s (EqConst      t1 t2) = on EqConst (apply s) t1 t2+  apply s (ExpInstConst t  sc) =+    ExpInstConst+      (apply s t)+      (apply s sc)+  apply s (ImpInstConst t1 ms t2) =+    ImpInstConst+      (apply s t1)+      (apply s ms)+      (apply s t2)++instance Substitutable a => Substitutable [a] where+  apply = fmap . apply++instance (Ord a, Substitutable a) => Substitutable (Set.Set a) where+  apply = Set.map . apply+++-- * data type @Judgment@++data Judgment s =+  Judgment+    { assumptions     :: Assumption+    , typeConstraints :: [Constraint]+    , inferredType    :: Type+    }+    deriving Show++inferred :: Type -> Judgment s+inferred = Judgment mempty mempty++-- * @InferT@: inference monad++type InferTInternals s m a =+  ReaderT+    (Set.Set TVar, Scopes (InferT s m) (Judgment s))+    (StateT InferState (ExceptT InferError m))+    a++-- | Inference monad+newtype InferT s m a =+  InferT+    { getInfer ::+        InferTInternals s m a+    }+    deriving+      ( Functor+      , Applicative+      , Alternative+      , Monad+      , MonadPlus+      , MonadFix+      , MonadReader (Set.Set TVar, Scopes (InferT s m) (Judgment s))+      , MonadFail+      , MonadState InferState+      , MonadError InferError+      )++extendMSet :: forall s m a . Monad m => TVar -> InferT s m a -> InferT s m a+extendMSet x = coerce putSetElementM+ where+  putSetElementM :: InferTInternals s m a -> InferTInternals s m a+  putSetElementM = local (first . Set.insert $ x)++-- ** Instances++instance MonadTrans (InferT s) where+  lift = InferT . lift . lift . lift++instance MonadRef m => MonadRef (InferT s m) where+  type Ref (InferT s m) = Ref m+  newRef x = liftInfer $ newRef x+  readRef x = liftInfer $ readRef x+  writeRef x y = liftInfer $ writeRef x y++instance MonadAtomicRef m => MonadAtomicRef (InferT s m) where+  atomicModifyRef x f =+    liftInfer $+      do+        res <- snd . f <$> readRef x+        _   <- modifyRef x $ fst . f+        pure res++instance Monad m => MonadThrow (InferT s m) where+  throwM = throwError . EvaluationError++instance Monad m => MonadCatch (InferT s m) where+  catch m h =+    catchError m $+      \case+        EvaluationError e ->+          maybe+            (error $ "Exception was not an exception: " <> show e)+            h+            (fromException $ toException e)+        err -> error $ "Unexpected error: " <> show err++-- instance MonadThunkId m => MonadThunkId (InferT s m) where+--   type ThunkId (InferT s m) = ThunkId m++instance+  Monad m+  => FromValue NixString (InferT s m) (Judgment s)+ where+  fromValueMay _ = stub+  fromValue _ = error "Unused"++instance+  MonadInfer m+  => FromValue ( AttrSet (Judgment s)+              , PositionSet+              ) (InferT s m) (Judgment s)+ where+  fromValueMay (Judgment _ _ (TSet _ xs)) =+    do+      let sing = const inferred+      pure $ pure (M.mapWithKey sing xs, mempty)+  fromValueMay _ = stub+  fromValue =+    pure .+      maybeToMonoid+      <=< fromValueMay++foldInitializedWith :: (Traversable t, Applicative f) => (t c -> c) -> (b -> c) -> (a -> f b) -> t a -> f c+foldInitializedWith fld getter init =+  -- maybe here is some law?+  fmap fld . traverse (fmap getter . init)++toJudgment :: forall t m s . (Traversable t, Monad m) => (t Type -> Type) -> t (Judgment s) -> InferT s m (Judgment s)+toJudgment c xs =+  liftA3 Judgment+    (foldWith fold assumptions    )+    (foldWith fold typeConstraints)+    (foldWith c    inferredType   )+   where+    foldWith :: (t a -> a) -> (Judgment s -> a) -> InferT s m a+    foldWith g f = foldInitializedWith g f demand xs++instance MonadInfer m+  => ToValue (AttrSet (Judgment s), PositionSet)+            (InferT s m) (Judgment s) where+  toValue :: (AttrSet (Judgment s), PositionSet) -> InferT s m (Judgment s)+  toValue (xs, _) = toJudgment (TSet Variadic) xs -- why variadic? Probably `Closed` (`mempty`)?++instance MonadInfer m => ToValue [Judgment s] (InferT s m) (Judgment s) where+  toValue = toJudgment TList++instance MonadInfer m => ToValue Bool (InferT s m) (Judgment s) where+  toValue _ = pure $ inferred typeBool++instance+  Monad m+  => Scoped (Judgment s) (InferT s m) where+  askScopes   = askScopesReader+  clearScopes = clearScopesReader @(InferT s m) @(Judgment s)+  pushScopes  = pushScopesReader+  lookupVar   = lookupVarReader++-- newtype JThunkT s m = JThunk (NThunkF (InferT s m) (Judgment s))++--  2021-02-22: NOTE: Seems like suporflous instance+instance Monad m => MonadValue (Judgment s) (InferT s m) where+  defer+    :: InferT s m (Judgment s)+    -> InferT s m (Judgment s)+  defer  = id++  demand+    :: Judgment s+    -> InferT s m (Judgment s)+  demand = pure++  inform+    :: Judgment s+    -> InferT s m (Judgment s)+  inform = pure+++--  2021-02-22: NOTE: Seems like suporflous instance+instance Monad m => MonadValueF (Judgment s) (InferT s m) where++  demandF+    :: ( Judgment s+      -> InferT s m r)+    -> Judgment s+    -> InferT s m r+  demandF f = f++  informF+    :: ( InferT s m (Judgment s)+      -> InferT s m (Judgment s)+      )+    -> Judgment s+    -> InferT s m (Judgment s)+  informF f = f . pure++{-+instance MonadInfer m+  => MonadThunk (JThunkT s m) (InferT s m) (Judgment s) where++  thunkId (JThunk x) = thunkId x++  thunk = fmap JThunk . thunk++  query b (JThunk x) = query b x++  -- If we have a thunk loop, we just don't know the type.+  force (JThunk t) = catch (force t)+    $ \(_ :: ThunkLoop) ->+                           f =<< Judgment mempty mempty <$> fresh++  -- If we have a thunk loop, we just don't know the type.+  forceEff (JThunk t) = catch (forceEff t)+    $ \(_ :: ThunkLoop) ->+                           f =<< Judgment mempty mempty <$> fresh+-}++polymorphicVar :: MonadInfer m => VarName -> InferT s m (Judgment s)+polymorphicVar var =+  fmap+    (join $ (`Judgment` mempty) . curry one var)+    fresh++constInfer :: Applicative f => Type -> b -> f (Judgment s)+constInfer x = const $ pure $ inferred x++instance MonadInfer m => MonadEval (Judgment s) (InferT s m) where+  freeVariable = polymorphicVar++  synHole = polymorphicVar++  -- If we fail to look up an attribute, we just don't know the type.+  attrMissing _ _ = inferred <$> fresh++  evaledSym _ = pure++  evalCurPos =+    pure $+      inferred $+        TSet mempty $+          M.fromList+            [ ("file", typePath)+            , ("line", typeInt )+            , ("col" , typeInt )+            ]++  evalConstant c = pure $ inferred $ fun c+   where+    fun = \case+      NURI   _ -> typeString+      NInt   _ -> typeInt+      NFloat _ -> typeFloat+      NBool  _ -> typeBool+      NNull    -> typeNull++  evalString      = constInfer typeString+  evalLiteralPath = constInfer typePath+  evalEnvPath     = constInfer typePath++  evalUnary op (Judgment as1 cs1 t1) =+    (Judgment as1 =<< (cs1 <>) . (`unops` op) . (t1 :~>)) <$> fresh++  evalBinary op (Judgment as1 cs1 t1) e2 =+    do+      Judgment as2 cs2 t2 <- e2+      (Judgment (as1 <> as2) =<< ((cs1 <> cs2) <>) . (`binops` op) . ((t1 :~> t2) :~>)) <$> fresh++  evalWith = Eval.evalWithAttrSet++  evalIf (Judgment as1 cs1 t1) t f = do+    Judgment as2 cs2 t2 <- t+    Judgment as3 cs3 t3 <- f+    pure $+      Judgment+        (as1 <> as2 <> as3)+        (cs1 <> cs2 <> cs3 <> [EqConst t1 typeBool, EqConst t2 t3])+        t2++  evalAssert (Judgment as1 cs1 t1) body = do+    Judgment as2 cs2 t2 <- body+    pure $+      Judgment+        (as1 <> as2)+        (cs1 <> cs2 <> one (EqConst t1 typeBool))+        t2++  evalApp (Judgment as1 cs1 t1) e2 = do+    Judgment as2 cs2 t2 <- e2+    tv                  <- fresh+    pure $+      Judgment+        (as1 <> as2)+        (cs1 <> cs2 <> one (EqConst t1 (t2 :~> tv)))+        tv++  evalAbs (Param x) k = do+    a <- freshTVar+    let tv = TVar a+    ((), Judgment as cs t) <-+      extendMSet+        a+        $ k+          (pure (join ((`Judgment` mempty) . curry one x ) tv))+          $ const $ fmap (mempty,)+    pure $+      Judgment+        (as `Assumption.remove` x)+        (cs <> [ EqConst t' tv | t' <- Assumption.lookup x as ])+        (tv :~> t)++  evalAbs (ParamSet _mname variadic pset) k = do+    js <- foldInitializedWith fold one intoFresh pset++    let+      f (as1, t1) (k, t) = (as1 <> one (k, t), M.insert k t t1)+      (env, tys) = foldl' f mempty js+      arg   = pure $ Judgment env mempty $ TSet Variadic tys+      call  = k arg $ \args b -> (args, ) <$> b+      names = fst <$> js++    (args, Judgment as cs t) <- foldr (extendMSet . (\ (TVar a) -> a) . snd) call js++    ty <- foldInitializedWith (TSet variadic) inferredType id args++    pure $+      Judgment+        (foldl' Assumption.remove as names)+        (cs <> [ EqConst t' (tys M.! x) | x <- names, t' <- Assumption.lookup x as ])+        (ty :~> t)++  evalError = throwError . EvaluationError++-- * class @FreeTypeVars@++class FreeTypeVars a where+  ftv :: a -> Set.Set TVar++occursCheck :: FreeTypeVars a => TVar -> a -> Bool+occursCheck a t = a `Set.member` ftv t++-- ** Instances++instance FreeTypeVars Type where+  ftv TCon{}      = mempty+  ftv (TVar a   ) = one a+  ftv (TSet _ a ) = Set.unions $ ftv <$> M.elems a+  ftv (TList a  ) = Set.unions $ ftv <$> a+  ftv (t1 :~> t2) = ftv t1 <> ftv t2+  ftv (TMany ts ) = Set.unions $ ftv <$> ts++instance FreeTypeVars TVar where+  ftv = one++instance FreeTypeVars Scheme where+  ftv (Forall as t) = ftv t `Set.difference` Set.fromList as++instance FreeTypeVars a => FreeTypeVars [a] where+  ftv = foldr ((<>) . ftv) mempty++instance (Ord a, FreeTypeVars a) => FreeTypeVars (Set.Set a) where+  ftv = foldr ((<>) . ftv) mempty++-- * class @ActiveTypeVars@++class ActiveTypeVars a where+  atv :: a -> Set.Set TVar++-- ** Instances++instance ActiveTypeVars Constraint where+  atv (EqConst      t1 t2   ) = ftv t1 <> ftv t2+  atv (ImpInstConst t1 ms t2) = ftv t1 <> (ftv ms `Set.intersection` ftv t2)+  atv (ExpInstConst t  s    ) = ftv t  <> ftv s++instance ActiveTypeVars a => ActiveTypeVars [a] where+  atv = foldr ((<>) . atv) mempty++-- * Other++type MonadInfer m+  = ({- MonadThunkId m,-}+     MonadAtomicRef m, MonadFix m)++-- | Run the inference monad+runInfer' :: MonadInfer m => InferT s m a -> m (Either InferError a)+runInfer' =+  runExceptT+    . (`evalStateT` initInfer)+    . (`runReaderT` mempty)+    . getInfer++runInfer :: (forall s . InferT s (FreshIdT Int (ST s)) a) -> Either InferError a+runInfer m =+  runST $ runFreshIdT (runInfer' m) =<< newRef (1 :: Int)++inferType+  :: forall s m . MonadInfer m => Env -> NExpr -> InferT s m [(Subst, Type)]+inferType env ex =+  do+    Judgment as cs t <- infer ex+    let+      unbounds :: Set VarName+      unbounds =+        (Set.difference `on` Set.fromList)+          (Assumption.keys as )+          (       Env.keys env)+    when+      (isPresent unbounds)+      $ typeError $ UnboundVariables $ ordNub $ Set.toList unbounds++    inferState <- get+    let+      cs' =+        [ ExpInstConst t s+            | (x, ss) <- Env.toList env+            , s       <- ss+            , t       <- Assumption.lookup x as+        ]+      evalResult =+        (`evalState` inferState) . runSolver $ second (`apply` t) . join (,) <$> solve (cs <> cs')++    either+      (throwError . TypeInferenceErrors)+      pure+      evalResult++-- | Solve for the toplevel type of an expression in a given environment+inferExpr :: Env -> NExpr -> Either InferError [Scheme]+inferExpr env ex =+  closeOver . uncurry apply <<$>> runInfer (inferType env ex)++unops :: Type -> NUnaryOp -> [Constraint]+unops u1 op =+  one $+    EqConst u1 $+      case op of+        NNot -> mkUnaryConstr typeBool+        NNeg -> TMany $ mkUnaryConstr <$> [typeInt, typeFloat]+ where+  mkUnaryConstr :: Type -> Type+  mkUnaryConstr = typeFun . mk2same+   where+    mk2same :: a -> NonEmpty a+    mk2same a = a :| one a++binops :: Type -> NBinaryOp -> [Constraint]+binops u1 op =+  if+    -- Equality tells nothing about the types, because any two types are allowed.+    | op `elem` [ NEq   , NNEq               ] -> mempty+    | op `elem` [ NGt   , NGte , NLt  , NLte ] -> inequality+    | op `elem` [ NAnd  , NOr  , NImpl       ] -> gate+    | op ==       NConcat                      -> concatenation+    | op `elem` [ NMinus, NMult, NDiv        ] -> arithmetic+    | op ==       NUpdate                      -> rUnion+    | op ==       NPlus                        -> addition+    | otherwise -> fail "GHC so far can not infer that this pattern match is full, so make it happy."++ where++  mk3 :: a -> a -> a -> NonEmpty a+  mk3 a b c = a :| [b, c]++  mk3same :: a -> NonEmpty a+  mk3same a = a :| [a, a]++  allConst :: Type -> [Constraint]+  allConst = one . EqConst u1 . typeFun . mk3same++  gate          = allConst typeBool+  concatenation = allConst typeList++  eqConstrMtx :: [NonEmpty Type] -> [Constraint]+  eqConstrMtx = one . EqConst u1 . TMany . fmap typeFun++  inequality =+    eqConstrMtx+      [ mk3 typeInt   typeInt   typeBool+      , mk3 typeFloat typeFloat typeBool+      , mk3 typeInt   typeFloat typeBool+      , mk3 typeFloat typeInt   typeBool+      ]++  arithmetic =+    eqConstrMtx+      [ mk3same typeInt+      , mk3same typeFloat+      , mk3 typeInt   typeFloat typeFloat+      , mk3 typeFloat typeInt   typeFloat+      ]++  rUnion =+    eqConstrMtx+      [ mk3same typeSet+      , mk3 typeSet  typeNull typeSet+      , mk3 typeNull typeSet  typeSet+      ]++  addition =+    eqConstrMtx+      [ mk3same typeInt+      , mk3same typeFloat+      , mk3 typeInt    typeFloat  typeFloat+      , mk3 typeFloat  typeInt    typeFloat+      , mk3same typeString+      , mk3same typePath+      , mk3 typeString typeString typePath+      ]++liftInfer :: Monad m => m a -> InferT s m a+liftInfer = InferT . lift . lift . lift++-- * Other++infer :: MonadInfer m => NExpr -> InferT s m (Judgment s)+infer = foldFix Eval.eval++inferTop :: Env -> [(VarName, NExpr)] -> Either InferError Env+inferTop env []                = pure env+inferTop env ((name, ex) : xs) =+  (\ ty -> inferTop (extend env (name, ty)) xs)+    =<< inferExpr env ex++-- * Other++newtype Solver m a = Solver (LogicT (StateT [TypeError] m) a)+    deriving (Functor, Applicative, Alternative, Monad, MonadPlus,+              MonadLogic, MonadState [TypeError])++runSolver :: forall m a . Monad m => Solver m a -> m (Either [TypeError] [a])+runSolver (Solver s) =+  uncurry report <$> runStateT (observeAllT s) mempty+ where+  report :: [a] -> [TypeError] -> Either [TypeError] [a]+  report xs e =+    handlePresence+      (Left $ ordNub e)+      pure+      xs++-- ** Instances++instance MonadTrans Solver where+  lift = Solver . lift . lift++instance Monad m => MonadError TypeError (Solver m) where+  throwError err = Solver $ lift (modify (err :)) *> mempty+  catchError _ _ = error "This is never used"++-- * Other++bind :: Monad m => TVar -> Type -> Solver m Subst+bind a t | t == TVar a     = stub+         | occursCheck a t = throwError $ InfiniteType a t+         | otherwise       = pure $ Subst $ one (a, t)++considering :: [a] -> Solver m a+considering xs = Solver $ LogicT $ \c n -> foldr c n xs++unifies :: Monad m => Type -> Type -> Solver m Subst+unifies t1 t2 | t1 == t2  = stub+unifies (TVar v) t        = v `bind` t+unifies t        (TVar v) = v `bind` t+unifies (TList xs) (TList ys)+  | allSameType xs && allSameType ys =+      case (xs, ys) of+        (x : _, y : _) -> unifies x y+        _              -> stub+  | length xs == length ys = unifyMany xs ys+-- Putting a statement that lists of different lengths containing various types would not+-- be unified.+unifies t1@(TList _    ) t2@(TList _    ) = throwError $ UnificationFail t1 t2+unifies (TSet Variadic _) (TSet Variadic _)                                 = stub+unifies (TSet Closed   s) (TSet Closed   b) | null (M.keys b \\ M.keys s)   = stub+unifies (TSet _ a) (TSet _ b) | (M.keys a `intersect` M.keys b) == M.keys b = stub+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++unifyMany :: Monad m => [Type] -> [Type] -> Solver m Subst+unifyMany []         []         = stub+unifyMany (t1 : ts1) (t2 : ts2) =+  do+    su1 <- unifies t1 t2+    su2 <-+      (unifyMany `on` apply su1) ts1 ts2+    pure $ compose su1 su2+unifyMany t1 t2 = throwError $ UnificationMismatch t1 t2++nextSolvable :: [Constraint] -> (Constraint, [Constraint])+nextSolvable = fromJust . find solvable . pickFirstOne+ where+  pickFirstOne :: Eq a => [a] -> [(a, [a])]+  pickFirstOne xs = [ (x, ys) | x <- xs, let ys = delete x xs ]++  solvable :: (Constraint, [Constraint]) -> Bool+  solvable (EqConst{}     , _) = True+  solvable (ExpInstConst{}, _) = True+  solvable (ImpInstConst _t1 ms t2, cs) =+    null $ (ms `Set.difference` ftv t2) `Set.intersection` atv cs++solve :: forall m . MonadState InferState m => [Constraint] -> Solver m Subst+solve [] = stub+solve cs = solve' $ nextSolvable cs+ where+  solve' (ImpInstConst t1 ms t2, cs) =+    solve (ExpInstConst t1 (generalize ms t2) : cs)+  solve' (ExpInstConst t s, cs) =+    do+      s' <- lift $ instantiate s+      solve (EqConst t s' : cs)+  solve' (EqConst t1 t2, cs) =+    (\ su1 ->+      (pure . compose su1) -<< solve ((`apply` cs) su1)+    ) -<<+    unifies t1 t2++infixr 1 -<<+-- | @LogicT@ fair conjunction, since library has only @>>-@+(-<<) :: Monad m => (a -> Solver m b) -> Solver m a -> Solver m b+(-<<) = flip (>>-)
src/Nix/Type/Type.hs view
@@ -1,42 +1,51 @@+-- | The basis of the Nix type system (type-level).+--   Based on the Hindley–Milner type system.+--   Therefore -> from this the type inference follows. module Nix.Type.Type where -import qualified Data.HashMap.Lazy as M-import           Data.Text (Text)-import           Nix.Utils+import           Nix.Prelude                 hiding ( Type, TVar )+import           Nix.Expr.Types -newtype TVar = TV String-  deriving (Show, Eq, Ord)+-- | Hindrey-Milner type interface -data Type-  = TVar TVar                -- type variable-  | TCon String              -- known type-  | TSet Bool (AttrSet Type) -- heterogenous map, bool if variadic-  | TList [Type]             -- heterogenous list-  | (:~>) Type Type          -- type -> type-  | TMany [Type]             -- variant type+-- | Type variable in the Nix type system.+newtype TVar = TV Text   deriving (Show, Eq, Ord) -data Scheme = Forall [TVar] Type -- forall a b. a -> b+-- | The basic type definitions in the Nix type system (type-level code).+data Type+  = TVar TVar                -- ^ Type variable in the Nix type system.+  | TCon Text                -- ^ Concrete (non-polymorphic, constant) type in the Nix type system.+  | TSet Variadic (AttrSet Type) -- ^ Heterogeneous map in the Nix type system. @True@ -> variadic.+  | TList [Type]             -- ^ Heterogeneous list in the Nix type system.+  | (:~>) Type Type          -- ^ Type arrow (@Type -> Type@) in the Nix type system.+  | TMany [Type]             -- ^ Variant type (term). Since relating to Nix type system, more precicely -+                             --   dynamic types in dynamicly typed language (which is Nix).   deriving (Show, Eq, Ord) --- This models a set that unifies with any other set.-typeSet :: Type-typeSet = TSet True M.empty--typeList :: Type-typeList = TList []- infixr 1 :~> -typeFun :: [Type] -> Type-typeFun = foldr1 (:~>)+-- | Hindley–Milner type system uses "scheme" term for "polytypes".+--   Types containing @forall@ quantifiers: @forall a . a@.+--   Note: HM allows only top-level @forall@ quantification, so no @RankNTypes@ in it.+data Scheme = Forall [TVar] Type -- ^ @Forall [TVar] Type@: the Nix type system @forall vars. type@.+  deriving (Show, Eq, Ord) -typeInt, typeFloat, typeBool, typeString, typePath, typeNull :: Type+-- | Concrete types in the Nix type system.+typeNull, typeBool, typeInt, typeFloat, typeString, typePath :: Type+typeNull   = TCon "null"+typeBool   = TCon "boolean" typeInt    = TCon "integer" typeFloat  = TCon "float"-typeBool   = TCon "boolean" typeString = TCon "string" typePath   = TCon "path"-typeNull   = TCon "null" -type Name = Text+-- This models a set that unifies with any other set.+typeSet :: Type+typeSet = TSet mempty mempty++typeList :: Type+typeList = TList mempty++typeFun :: NonEmpty Type -> Type+typeFun (head_ :| tail_) = foldr (:~>) head_ tail_
+ src/Nix/Unused.hs view
@@ -0,0 +1,83 @@+{-# language FunctionalDependencies #-}+{-# language TemplateHaskell #-}++{-# options_ghc -Wno-missing-signatures #-}++-- | This module holds unused code.+-- So, if someone wants something - look here, use it & move to appropriate place.+module Nix.Unused+ where++import           Nix.Prelude+import           Control.Monad.Free             ( Free(..) )+import           Data.Fix                       ( Fix(..) )+import           Lens.Family2.TH                ( makeLensesBy )++-- * From "Nix.Utils"++-- | > type AlgM f m a = f a -> m a+type AlgM f m a = f a -> m a++whenFree :: (Monoid b)+  => (f (Free f a) -> b) -> Free f a -> b+whenFree =+  free+    mempty+{-# inline whenFree #-}++whenPure :: (Monoid b)+  => (a -> b) -> Free f a -> b+whenPure f =+  free+    f+    mempty+{-# inline whenPure #-}++-- | Replace:+--  @Pure a -> a@+--  @Free -> Fix@+freeToFix :: Functor f => (a -> Fix f) -> Free f a -> Fix f+freeToFix f = go+ where+  go =+    free+      f+      $ Fix . (go <$>)++-- | Replace:+--  @a -> Pure a@+--  @Fix -> Free@+fixToFree :: Functor f => Fix f -> Free f a+fixToFree = Free . go+ where+  go (Fix f) = Free . go <$> f+++loeb :: Functor f => f (f a -> a) -> f a+loeb x = go+ where+  go = ($ go) <$> x++adiM+  :: ( Traversable t+     , Monad m+     )+  => Transform t (m a)+  -> AlgM t m a+  -> Fix t+  -> m a+adiM g f = g $ f <=< traverse (adiM g f) . unFix++para :: Functor f => (f (Fix f, a) -> a) -> Fix f -> a+para f = f . fmap (id &&& para f) . unFix++paraM :: (Traversable f, Monad m) => (f (Fix f, a) -> m a) -> Fix f -> m a+paraM f = f <=< traverse (\x -> (x, ) <$> paraM f x) . unFix++cataP :: Functor f => (Fix f -> f a -> a) -> Fix f -> a+cataP f x = f x . fmap (cataP f) . unFix $ x++cataPM :: (Traversable f, Monad m) => (Fix f -> f a -> m a) -> Fix f -> m a+cataPM f x = f x <=< traverse (cataPM f) . unFix $ x++$(makeLensesBy (\n -> pure $ "_" <> n) ''Fix)
src/Nix/Utils.hs view
@@ -1,110 +1,375 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TupleSections #-}+{-# language CPP #-}+{-# language GeneralizedNewtypeDeriving #-} -module Nix.Utils (module Nix.Utils, module X) where+-- | This is a module of custom "Prelude" code.+-- It is for import for projects other then @HNix@.+-- For @HNix@ - this module gets reexported by "Prelude", so for @HNix@ please fix-up pass-through there.+module Nix.Utils+  ( stub+  , pass+  , dup+  , both+  , mapPair+  , iterateN+  , nestM+  , applyAll+  , traverse2+  , lifted -import           Control.Arrow ((&&&))-import           Control.Monad-import           Control.Monad.Fix-import qualified Data.Aeson as A-import qualified Data.Aeson.Encoding as A-import           Data.Fix-import           Data.HashMap.Lazy (HashMap)-import qualified Data.HashMap.Lazy as M-import           Data.List (sortOn)-import           Data.Monoid (Endo)-import           Data.Text (Text)-import qualified Data.Vector as V-import           Lens.Family2 as X-import           Lens.Family2.Stock (_1, _2)+  , whenTrue+  , whenFalse+  , whenJust+  , isPresent+  , handlePresence+  , whenText+  , free +  , Path(..)+  , isAbsolute+  , (</>)+  , joinPath+  , splitDirectories+  , takeDirectory+  , takeFileName+  , takeBaseName+  , takeExtension+  , takeExtensions+  , addExtension+  , dropExtensions+  , replaceExtension+  , readFile++  , Alg+  , Transform+  , TransformF+  , loebM+  , adi++  , Has(..)+  , askLocal++  , KeyMap++  , trace+  , traceM+  , module X+  )+ where++import           Relude                  hiding ( pass+                                                , force+                                                , readFile+                                                , whenJust+                                                , whenNothing+                                                , trace+                                                , traceM+                                                )++import           Data.Binary                    ( Binary )+import           Data.Data                      ( Data )+import           Codec.Serialise                ( Serialise )+import           Control.Monad                  ( foldM )+import           Control.Monad.Fix              ( MonadFix(..) )+import           Control.Monad.Free             ( Free(..) )+import           Control.Monad.Trans.Control    ( MonadTransControl(..) )+import qualified Data.Aeson                    as A+import           Data.Fix                       ( Fix(..) )+import qualified Data.Text                     as Text+import           Lens.Family2                  as X+                                                ( view+                                                , over+                                                , LensLike'+                                                , Lens'+                                                )+import           Lens.Family2.Stock             ( _1+                                                , _2+                                                )+import qualified System.FilePath              as FilePath+ #if ENABLE_TRACING-import           Debug.Trace as X+import qualified Relude.Debug                 as X #else-import           Prelude as X+-- Well, since it is currently CPP intermingled with Debug.Trace, required to use String here. trace :: String -> a -> a trace = const id+{-# inline trace #-} traceM :: Monad m => String -> m ()-traceM = const (return ())+traceM = const stub+{-# inline traceM #-} #endif -type DList a = Endo [a]+-- * Helpers -type AttrSet = HashMap Text+-- After migration from the @relude@ - @relude: pass -> stub@+-- | @pure mempty@: Short-curcuit, stub.+stub :: (Applicative f, Monoid a) => f a+stub = pure mempty+{-# inline stub #-} --- | An f-algebra defines how to reduced the fixed-point of a functor to a---   value.-type Alg f a = f a -> a+-- | Alias for 'stub', since "Relude" has more specialized @pure ()@.+pass :: (Applicative f) => f ()+pass = stub+{-# inline pass #-} -type AlgM f m a = f a -> m a+-- | Duplicates object into a tuple.+dup :: a -> (a, a)+dup x = (x, x)+{-# inline dup #-} --- | An "transform" here is a modification of a catamorphism.-type Transform f a = (Fix f -> a) -> Fix f -> a+-- | Apply a single function to both components of a pair.+--+-- > both succ (1,2) == (2,3)+--+-- Taken From package @extra@+both :: (a -> b) -> (a, a) -> (b, b)+both f (x,y) = (f x, f y)+{-# inline both #-} -(<&>) :: Functor f => f a -> (a -> c) -> f c-(<&>) = flip (<$>)+-- | Gives tuple laziness.+--+-- Takem from @utility-ht@.+mapPair :: (a -> c, b -> d) -> (a,b) -> (c,d)+mapPair ~(f,g) ~(a,b) = (f a, g b)+{-# inline mapPair #-} -(??) :: Functor f => f (a -> b) -> a -> f b-fab ?? a = fmap ($ a) fab+iterateN+  :: forall a+   . Int -- ^ Recursively apply 'Int' times+  -> (a -> a) -- ^ the function+  -> a -- ^ starting from argument+  -> a+iterateN n f x =+  -- It is hard to read - yes. It is a non-recursive momoized action - yes.+  fix ((<*> (0 /=)) . ((bool x . f) .) . (. pred)) n -loeb :: Functor f => f (f a -> a) -> f a-loeb x = go where go = fmap ($ go) x+nestM+  :: Monad m+  => Int -- ^ Recursively apply 'Int' times+  -> (a -> m a) -- ^ function (Kleisli arrow).+  -> a -- ^ to value+  -> m a -- ^ & join layers of 'm'+nestM 0 _ x = pure x+nestM n f x =+  foldM (const . f) x $ replicate @() n mempty -- fuses. But also, can it be fix join?+{-# inline nestM #-} -loebM :: (MonadFix m, Traversable t) => t (t a -> m a) -> m (t a)-loebM f = mfix $ \a -> mapM ($ a) f+-- | In `foldr` order apply functions.+applyAll :: Foldable t => t (a -> a) -> a -> a+applyAll = flip (foldr id) -para :: Functor f => (f (Fix f, a) -> a) -> Fix f -> a-para f = f . fmap (id &&& para f) . unFix+traverse2+  :: ( Applicative m+     , Applicative n+     , Traversable t+     )+  => ( a+     -> m (n b)+     ) -- ^ Run function that runs 2 'Applicative' actions+  -> t a -- ^ on every element in 'Traversable'+  -> m (n (t b)) -- ^ collect the results.+traverse2 f x = sequenceA <$> traverse f x -paraM :: (Traversable f, Monad m) => (f (Fix f, a) -> m a) -> Fix f -> m a-paraM f = f <=< traverse (\x -> (x,) <$> paraM f x) . unFix+--  2021-08-21: NOTE: Someone needs to put in normal words, what this does.+-- This function is pretty spefic & used only once, in "Nix.Normal".+lifted+  :: (MonadTransControl u, Monad (u m), Monad m)+  => ((a -> m (StT u b)) -> m (StT u b))+  -> (a -> u m b)+  -> u m b+lifted f k =+  restoreT . pure =<< liftWith (\run -> f (run . k)) -cataP :: Functor f => (Fix f -> f a -> a) -> Fix f -> a-cataP f x = f x . fmap (cataP f) . unFix $ x -cataPM :: (Traversable f, Monad m) => (Fix f -> f a -> m a) -> Fix f -> m a-cataPM f x = f x <=< traverse (cataPM f) . unFix $ x+-- * Eliminators -transport :: Functor g => (forall x. f x -> g x) -> Fix f -> Fix g-transport f (Fix x) = Fix $ fmap (transport f) (f x)+whenTrue :: (Monoid a)+  => a -> Bool -> a+whenTrue =+  bool+    mempty+{-# inline whenTrue #-} +whenFalse :: (Monoid a)+  => a  -> Bool  -> a+whenFalse f =+  bool+    f+    mempty+{-# inline whenFalse #-}++whenJust+  :: Monoid b+  => (a -> b)+  -> Maybe a+  -> b+whenJust =+  maybe+    mempty+{-# inline whenJust #-}++isPresent :: Foldable t => t a -> Bool+isPresent = not . null+{-# inline isPresent #-}+++-- | 'maybe'-like eliminator, for foldable empty/inhabited structures.+handlePresence :: Foldable t => b -> (t a -> b) -> t a -> b+handlePresence d f t =+  bool+    d+    (f t)+    (isPresent t)+{-# inline handlePresence #-}++whenText+  :: a -> (Text -> a) -> Text -> a+whenText e f t =+  bool+    e+    (f t)+    (not $ Text.null t)++-- | Lambda analog of @maybe@ or @either@ for Free monad.+free :: (a -> b) -> (f (Free f a) -> b) -> Free f a -> b+free fP fF fr =+  case fr of+    Pure a -> fP a+    Free fa -> fF fa+{-# inline free #-}+++-- * Path++-- | Explicit type boundary between FilePath & String.+newtype Path = Path FilePath+  deriving+    ( Eq, Ord, Generic+    , Typeable, Data, NFData, Serialise, Binary, A.ToJSON, A.FromJSON+    , Show, Read, Hashable+    , Semigroup, Monoid+    )++instance ToText Path where+  toText = toText @String . coerce++instance IsString Path where+  fromString = coerce++-- ** Path functions++-- | This set of @Path@ funcs is to control system filepath types & typesafety and to easily migrate from FilePath to anything suitable (like @path@ or so).++-- | 'Path's 'FilePath.isAbsolute'.+isAbsolute :: Path -> Bool+isAbsolute = coerce FilePath.isAbsolute++-- | 'Path's 'FilePath.(</>)'.+(</>) :: Path -> Path -> Path+(</>) = coerce (FilePath.</>)+infixr 5 </>++-- | 'Path's 'FilePath.joinPath'.+joinPath :: [Path] -> Path+joinPath = coerce FilePath.joinPath++-- | 'Path's 'FilePath.splitDirectories'.+splitDirectories :: Path -> [Path]+splitDirectories = coerce FilePath.splitDirectories++-- | 'Path's 'FilePath.takeDirectory'.+takeDirectory :: Path -> Path+takeDirectory = coerce FilePath.takeDirectory++-- | 'Path's 'FilePath.takeFileName'.+takeFileName :: Path -> Path+takeFileName = coerce FilePath.takeFileName++-- | 'Path's 'FilePath.takeBaseName'.+takeBaseName :: Path -> String+takeBaseName = coerce FilePath.takeBaseName++-- | 'Path's 'FilePath.takeExtension'.+takeExtension :: Path -> String+takeExtension = coerce FilePath.takeExtensions++-- | 'Path's 'FilePath.takeExtensions'.+takeExtensions :: Path -> String+takeExtensions = coerce FilePath.takeExtensions++-- | 'Path's 'FilePath.addExtensions'.+addExtension :: Path -> String -> Path+addExtension = coerce FilePath.addExtension++-- | 'Path's 'FilePath.dropExtensions'.+dropExtensions :: Path -> Path+dropExtensions = coerce FilePath.dropExtensions++-- | 'Path's 'FilePath.replaceExtension'.+replaceExtension :: Path -> String -> Path+replaceExtension = coerce FilePath.replaceExtension++-- | 'Path's 'FilePath.readFile'.+readFile :: MonadIO m => Path -> m Text+readFile = fmap decodeUtf8 . readFileBS . coerce+++-- * Recursion scheme++-- | F-algebra defines how to reduce the fixed-point of a functor to a value.+-- > type Alg f a = f a -> a+type Alg f a = f a -> a++-- | Do according transformation.+--+-- It is a transformation of a recursion scheme.+-- See @TransformF@.+type Transform f a = TransformF (Fix f) a+-- | Do according transformation.+--+-- It is a transformation between functors.+type TransformF f a = (f -> a) -> f -> a++loebM :: (MonadFix m, Traversable t) => t (t a -> m a) -> m (t a)+loebM f = mfix $ \a -> (`traverse` f) ($ a)+{-# inline loebM #-}+ -- | adi is Abstracting Definitional Interpreters: -- --     https://arxiv.org/abs/1707.04755 --+--   All ADI does is interleaves every layer of evaluation by inserting intermitten layers between them, in that way the evaluation can be extended/embelished in any way wanted. Look at its use to see great examples.+-- --   Essentially, it does for evaluation what recursion schemes do for --   representation: allows threading layers through existing structure, only --   in this case through behavior.-adi :: Functor f => (f a -> a) -> ((Fix f -> a) -> Fix f -> a) -> Fix f -> a-adi f g = g (f . fmap (adi f g) . unFix)+adi+  :: Functor f+  => Transform f a+  -> Alg f a+  -> Fix f+  -> a+adi g f = g $ f . (adi g f <$>) . unFix -adiM :: (Traversable t, Monad m)-     => (t a -> m a) -> ((Fix t -> m a) -> Fix t -> m a) -> Fix t -> m a-adiM f g = g ((f <=< traverse (adiM f g)) . unFix) +-- * Has lens+ class Has a b where-    hasLens :: Lens' a b+  hasLens :: Lens' a b  instance Has a a where-    hasLens f = f+  hasLens f = f  instance Has (a, b) a where-    hasLens = _1+  hasLens = _1  instance Has (a, b) b where-    hasLens = _2+  hasLens = _2 -toEncodingSorted :: A.Value -> A.Encoding-toEncodingSorted = \case-    A.Object m ->-        A.pairs . mconcat-                . fmap (\(k, v) -> A.pair k $ toEncodingSorted v)-                . sortOn fst-                $ M.toList m-    A.Array l -> A.list toEncodingSorted $ V.toList l-    v -> A.toEncoding v+-- | Retrive monad state by 'Lens''.+askLocal :: (MonadReader t m, Has t a) => m a+askLocal = asks $ view hasLens++-- * Other++-- | > Hashmap Text -- type synonym+type KeyMap = HashMap Text
+ src/Nix/Utils/Fix1.hs view
@@ -0,0 +1,127 @@+{-# language TypeFamilies #-}+{-# language ConstraintKinds #-}+{-# language CPP #-}+{-# language GeneralizedNewtypeDeriving #-}+{-# language PolyKinds #-}+{-# language UndecidableInstances #-}++module Nix.Utils.Fix1+  ( Fix1(..)+  , Fix1T(..)+  , MonadFix1T+  )+where++import           Nix.Prelude+import           Control.Monad.Fix              ( MonadFix )+import           Control.Monad.Ref              ( MonadAtomicRef(..)+                                                , MonadRef(..)+                                                )+import           Control.Monad.Catch            ( MonadCatch+                                                , MonadMask+                                                , MonadThrow+                                                )++-- | The fixpoint combinator.+-- Courtesy of Gregory Malecha.+-- https://gist.github.com/gmalecha/ceb3778b9fdaa4374976e325ac8feced+newtype Fix1 (t :: (k -> Type) -> k -> Type) (a :: k) = Fix1 { unFix1 :: t (Fix1 t) a }++deriving instance Generic (Fix1 t a)+deriving instance Functor (t (Fix1 t))+  => Functor (Fix1 t)+deriving instance Applicative (t (Fix1 t))+  => Applicative (Fix1 t)+deriving instance Alternative (t (Fix1 t))+  => Alternative (Fix1 t)+deriving instance Monad (t (Fix1 t))+  => Monad (Fix1 t)+deriving instance MonadPlus (t (Fix1 t))+  => MonadPlus (Fix1 t)+deriving instance MonadFix (t (Fix1 t))+  => MonadFix (Fix1 t)+deriving instance MonadIO (t (Fix1 t))+  => MonadIO (Fix1 t)+deriving instance MonadCatch (t (Fix1 t))+  => MonadCatch (Fix1 t)+deriving instance MonadThrow (t (Fix1 t))+  => MonadThrow (Fix1 t)++deriving instance MonadReader e (t (Fix1 t))+  => MonadReader e (Fix1 t)+deriving instance MonadState s (t (Fix1 t))+  => MonadState s (Fix1 t)++newtype Fix1T (t :: (k -> Type) -> (Type -> Type) -> k -> Type) (m :: Type -> Type) (a :: k)+  = Fix1T { unFix1T :: t (Fix1T t m) m a }++deriving instance Generic (Fix1T t m m)+deriving instance Functor (t (Fix1T t m) m)+  => Functor (Fix1T t m)+deriving instance Applicative (t (Fix1T t m) m)+  => Applicative (Fix1T t m)+deriving instance Alternative (t (Fix1T t m) m)+  => Alternative (Fix1T t m)+deriving instance Monad (t (Fix1T t m) m)+  => Monad (Fix1T t m)+deriving instance MonadFail (t (Fix1T t m) m)+  => MonadFail (Fix1T t m)+deriving instance MonadPlus (t (Fix1T t m) m)+  => MonadPlus (Fix1T t m)+deriving instance MonadFix (t (Fix1T t m) m)+  => MonadFix (Fix1T t m)+deriving instance MonadIO (t (Fix1T t m) m)+  => MonadIO (Fix1T t m)+deriving instance MonadCatch (t (Fix1T t m) m)+  => MonadCatch (Fix1T t m)+deriving instance MonadThrow (t (Fix1T t m) m)+  => MonadThrow (Fix1T t m)+deriving instance MonadMask (t (Fix1T t m) m)+  => MonadMask (Fix1T t m)++deriving instance MonadReader e (t (Fix1T t m) m)+  => MonadReader e (Fix1T t m)+deriving instance MonadState s (t (Fix1T t m) m)+  => MonadState s (Fix1T t m)+++type MonadFix1T t m = (MonadTrans (Fix1T t), Monad (t (Fix1T t m) m))++instance+  ( MonadFix1T t m+  , MonadRef m+  )+  => MonadRef (Fix1T t m)+ where+  type Ref (Fix1T t m) = Ref m++  newRef  = lift . newRef+  {-# inline newRef #-}+  readRef = lift . readRef+  {-# inline readRef #-}+  writeRef r = lift . writeRef r+  {-# inline writeRef #-}++instance+  ( MonadFix1T t m+  , MonadAtomicRef m+  )+  => MonadAtomicRef (Fix1T t m)+ where+  atomicModifyRef r = lift . atomicModifyRef r+  {-# inline atomicModifyRef #-}++{-++newtype Flip (f :: i -> j -> *) (a :: j) (b :: i) = Flip { unFlip :: f b a }++-- | Natural Transformations+--  ( Included from+--   [compdata](https://hackage.haskell.org/package/compdata)+--  )+type (:->) f g = forall a. f a -> g a++class HFunctor f where+  hfmap :: a :-> b -> f a :-> f b++-}
src/Nix/Value.hs view
@@ -1,67 +1,126 @@-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveFoldable #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DeriveTraversable #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}+{-# language CPP #-}+{-# language DeriveAnyClass #-}+{-# language KindSignatures #-}+{-# language ConstraintKinds #-}+{-# language PatternSynonyms #-}+{-# language RankNTypes #-}+{-# language TemplateHaskell #-} -{-# OPTIONS_GHC -Wno-missing-signatures #-}-{-# OPTIONS_GHC -Wno-missing-pattern-synonym-signatures #-}+{-# options_ghc -Wno-missing-signatures #-}+{-# options_ghc -Wno-missing-pattern-synonym-signatures #-} -module Nix.Value where+-- | The core of the type system, Nix language values+module Nix.Value+where -import           Control.Monad-import           Control.Monad.Catch-import           Control.Monad.Trans.Class-import           Control.Monad.Trans.Except-import qualified Data.Aeson as A-import           Data.Align-import           Data.Fix-import           Data.HashMap.Lazy (HashMap)-import qualified Data.HashMap.Lazy as M-import           Data.Hashable-import           Data.Monoid (appEndo)-import           Data.Text (Text)-import           Data.These-import           Data.Typeable (Typeable)-import           GHC.Generics-import           Lens.Family2-import           Lens.Family2.Stock-import           Lens.Family2.TH+import           Nix.Prelude+import           Control.Comonad                ( Comonad+                                                , extract+                                                )+import           Control.Monad.Free             ( Free(..)+                                                , hoistFree+                                                , iter+                                                , iterM+                                                )+import qualified Data.Aeson                    as Aeson+import           Data.Functor.Classes           ( Show1+                                                , liftShowsPrec+                                                , showsUnaryWith+                                                , Eq1(liftEq) )+import qualified Text.Show+import           Text.Show                      ( showsPrec+                                                , showString+                                                , showParen+                                                )+import           Lens.Family2.Stock             ( _2 )+import           Lens.Family2.TH                ( makeTraversals+                                                , makeLenses+                                                ) import           Nix.Atoms import           Nix.Expr.Types-import           Nix.Expr.Types.Annotated-import           Nix.Frames-import           Nix.Scope+import           Nix.String import           Nix.Thunk-import           Nix.Utils --- | An 'NValue' is the most reduced form of an 'NExpr' after evaluation is---   completed. 's' is related to the type of errors that might occur during---   construction or use of a value.-data NValueF m r++-- * @__NValueF__@: Base functor (F)++-- | An NValueF p m r represents all the possible types of Nix values.+--+--   Is is the base functor to form the Free monad of nix expressions.+--   The parameter `r` represents Nix values in their final form (NValue).+--   The parameter `p` represents exactly the same type, but is kept separate+--   or it would prevent NValueF from being a proper functor.+--   It is intended to be hard-coded to the same final type as r.+--   `m` is the monad in which evaluations will run.++-- | An NValue' t f m a is a magic layer between NValueF and the Free monad construction.+--+--   It fixes the `p` parameter of NValueF to the final NValue type, making the+--   definition of NValue' and NValue depend on each other in a recursive+--   fashion.+--+--   It also introduces a `f` parameter for a custom functor that can be used+--   to wrap each intermediate value in the reduced expression tree.+--   This is where expression evaluations can store annotations and other+--   useful information.+--+--   `t` is not really used here, but is needed to type the (NValue t f m)+--   used to tie the knot of the `p` parameter in the inner NValueF.+--+--   `a` is will be an `NValue t f m` when NValue' functor is turned into a+--   Free monad.++-- | 'NValue t f m' is the most reduced form of a 'NExpr' after evaluation is+--   completed. It is a layer cake of NValueF base values, wrapped in the f+--   functor and into the Free recursive construction.+--+--   Concretely, an NValue t f m can either be a thunk, representing a value+--   yet to be evaluated (Pure t), or a know value in WHNF+--   (Free (NValue' t f m (NValue t f m))) = (Free (f (NValueF NValue m NValue))+--   That is, a base value type, wrapped into the generic `f`+--   functor, and based on other NValue's, which can in turn be either thunks,+--   or more already WHNF evaluated values.+--+--   As an example, the value `[1]` will be represented as+--+--   Free (f (NVListF [+--      (Free (f (NVConstantF (NInt 1))))+--   ]))+--+--   Should this 1 be a laziy and yet unevaluated value, it would be represented as+--+--   Free (f (NVListF [ (Pure t) ]))+--+--   Where the t is evaluator dependant, and should contain anough information+--   to be evaluated to an NValue when needed. `demand` of `force` are used to+--   turn a potential thunk into a `m (NValue t f m)`.+--+--   Of course, trees can be much bigger.+--+--   The number of layers and type aliases for similar things is huge, so+--   this module provides ViewPatterns for each NValueF constructor.+--+--   For example, the pattern NVStr' ns matches a NValue' containing an NVStrF,+--   and bind that NVStrF to ns, ignoring the f functor inside.+--   Similarly, the pattern NVStr ns (without prime mark) will match the inner+--   NVstrF value inside an NValue. Of course, the patterns are declined for+--   all the NValueF constructors. The non primed version also has an NVThunk t+--   pattern to account for the possibility of an NValue to no be fully+--   evaluated yet, as opposed to an NValue'.++data NValueF p m r     = NVConstantF NAtom      -- | A string has a value and a context, which can be used to record what a      -- string has been build from-    | NVStrF Text (DList Text)-    | NVPathF FilePath+    | NVStrF NixString+    | NVPathF Path     | NVListF [r]-    | NVSetF (AttrSet r) (AttrSet SourcePos)-    | NVClosureF (Params ()) (m (NValue m) -> m (NValue m))+    | NVSetF PositionSet (AttrSet r)+      -- ^+      --   Quite frequently actions/processing happens with values+      --   (for example - forcing of values & recreation of the monad),+      --   but @SourcePos@ does not change then.+    | NVClosureF (Params ()) (p -> m r)       -- ^ A function is a closed set of parameters representing the "call       --   signature", used at application time to check the type of arguments       --   passed to the function. Since it supports default values which may@@ -73,274 +132,624 @@       --   Note that 'm r' is being used here because effectively a function       --   and its set of default arguments is "never fully evaluated". This       --   enforces in the type that it must be re-evaluated for each call.-    | NVBuiltinF String (m (NValue m) -> m (NValue m))+    | NVBuiltinF VarName (p -> m r)       -- ^ A builtin function is itself already in normal form. Also, it may       --   or may not choose to evaluate its argument in the production of a       --   result.-    deriving (Generic, Typeable, Functor, Foldable, Traversable)+  deriving (Generic, Typeable, Functor) --- | An 'NValueNF' is a fully evaluated value in normal form. An 'NValue m' is---   a value in head normal form, where only the "top layer" has been---   evaluated. An action of type 'm (NValue m)' is a pending evualation that---   has yet to be performed. An 'NThunk m' is either a pending evaluation, or---   a value in head normal form. A 'NThunkSet' is a set of mappings from keys---   to thunks. -type NValueNF m = Fix (NValueF m)      -- normal form-type ValueSet m = AttrSet (NThunk m)+-- ** Eq -data Provenance m = Provenance-    { _lexicalScope :: Scopes m (NThunk m)-    , _originExpr   :: NExprLocF (Maybe (NValue m))-      -- ^ When calling the function x: x + 2 with argument x = 3, the-      --   'originExpr' for the resulting value will be 3 + 2, while the-      --   'contextExpr' will be @(x: x + 2) 3@, preserving not only the-      --   result of the call, but what was called and with what arguments.-    }+instance Eq r => Eq (NValueF p m r) where+  (==) (NVConstantF x) (NVConstantF y) = x == y+  (==) (NVStrF      x) (NVStrF      y) = x == y+  (==) (NVPathF     x) (NVPathF     y) = x == y+  (==) (NVListF     x) (NVListF     y) = x == y+  (==) (NVSetF  _   x) (NVSetF _    y) = x == y+  (==) _               _               = False -data NThunk m = NThunk-    { _thunkProvenance :: [Provenance m]-    , _baseThunk       :: Thunk m (NValue m)-    }+-- ** Eq1 -data NValue m = NValue-    { _valueProvenance :: [Provenance m]-    , _baseValue       :: NValueF m (NThunk m)+instance Eq1 (NValueF p m) where+  liftEq _  (NVConstantF x) (NVConstantF y) = x == y+  liftEq _  (NVStrF      x) (NVStrF      y) = x == y+  liftEq _  (NVPathF     x) (NVPathF     y) = x == y+  liftEq eq (NVListF     x) (NVListF     y) = liftEq eq x y+  liftEq eq (NVSetF  _   x) (NVSetF _    y) = liftEq eq x y+  liftEq _  _               _               = False+++-- ** Show++instance Show r => Show (NValueF p m r) where+  showsPrec d =+    \case+      (NVConstantF atom     ) -> showsCon1 "NVConstant" atom+      (NVStrF      ns       ) -> showsCon1 "NVStr"      $ ignoreContext ns+      (NVListF     lst      ) -> showsCon1 "NVList"     lst+      (NVSetF      _   attrs) -> showsCon1 "NVSet"      attrs+      (NVClosureF  params _ ) -> showsCon1 "NVClosure"  params+      (NVPathF     path     ) -> showsCon1 "NVPath"     path+      (NVBuiltinF  name   _ ) -> showsCon1 "NVBuiltin"  name+   where+    showsCon1 :: Show a => String -> a -> String -> String+    showsCon1 con a =+      showParen (d > 10) $ showString (con <> " ") . showsPrec 11 a+++-- ** Foldable++-- | Folds what the value is known to contain at time of fold.+instance Foldable (NValueF p m) where+  foldMap f = \case+    NVConstantF _  -> mempty+    NVStrF      _  -> mempty+    NVPathF     _  -> mempty+    NVClosureF _ _ -> mempty+    NVBuiltinF _ _ -> mempty+    NVListF     l  -> foldMap f l+    NVSetF     _ s -> foldMap f s+++-- ** Traversable++-- | @sequence@+sequenceNValueF+  :: (Functor n, Monad m, Applicative n)+  => (forall x . n x -> m x)+  -> NValueF p m (n a)+  -> n (NValueF p m a)+sequenceNValueF transform = \case+  NVConstantF a  -> pure $ NVConstantF a+  NVStrF      s  -> pure $ NVStrF s+  NVPathF     p  -> pure $ NVPathF p+  NVListF     l  -> NVListF <$> sequenceA l+  NVSetF     p s -> NVSetF p <$> sequenceA s+  NVClosureF p g -> pure $ NVClosureF p (transform <=< g)+  NVBuiltinF s g -> pure $ NVBuiltinF s (transform <=< g)+++-- ** Monad++-- | @bind@+bindNValueF+  :: (Monad m, Monad n)+  => (forall x . n x -> m x) -- ^ Transform @n@ into @m@.+  -> (a -> n b) -- ^ A Kleisli arrow (see 'Control.Arrow.Kleisli' & Kleisli catagory).+  -> NValueF p m a -- ^ "Unfixed" (openly recursive) value of an embedded Nix language.+  -> n (NValueF p m b) -- ^ An implementation of @transform (f =<< x)@ for embedded Nix language values.+bindNValueF transform f = \case+  NVConstantF a  -> pure $ NVConstantF a+  NVStrF      s  -> pure $ NVStrF s+  NVPathF     p  -> pure $ NVPathF p+  NVListF     l  -> NVListF <$> traverse f l+  NVSetF     p s -> NVSetF p <$> traverse f s+  NVClosureF p g -> pure $ NVClosureF p (transform . f <=< g)+  NVBuiltinF s g -> pure $ NVBuiltinF s (transform . f <=< g)+++-- *** MonadTrans++-- | @lift@+liftNValueF+  :: (MonadTrans u, Monad m)+  => NValueF p m a+  -> NValueF p (u m) a+liftNValueF = hoistNValueF lift++-- **** MonadTransUnlift++-- | @unlift@+unliftNValueF+  :: (MonadTrans u, Monad m)+  => (forall x . u m x -> m x)+  -> NValueF p (u m) a+  -> NValueF p m a+unliftNValueF = hoistNValueF++-- **** Utils++-- | Back & forth hoisting in the monad stack+hoistNValueF+  :: (forall x . m x -> n x)+  -> NValueF p m a+  -> NValueF p n a+hoistNValueF lft =+  \case+    -- Pass-through the:+    --   [ NVConstantF a+    --   , NVStrF s+    --   , NVPathF p+    --   , NVListF l+    --   , NVSetF p s+    --   ]+    NVConstantF a  -> NVConstantF a+    NVStrF      s  -> NVStrF s+    NVPathF     p  -> NVPathF p+    NVListF     l  -> NVListF l+    NVSetF     p s -> NVSetF p s+    NVBuiltinF s g -> NVBuiltinF s (lft . g)+    NVClosureF p g -> NVClosureF p (lft . g)+{-# inline hoistNValueF #-}++-- * @__NValue'__@: forming the (F(A))++-- | NVConstraint constraint the f layer in @NValue'@.+-- It makes bijection between sub category of Hask and Nix Value possible.+-- 'Comonad' enable Nix Value to Hask part.+-- 'Applicative' enable Hask to Nix Value part.+type NVConstraint f = (Comonad f, Applicative f)++-- | At the time of constructor, the expected arguments to closures are values+--   that may contain thunks. The type of such thunks are fixed at that time.+newtype NValue' t f m a =+  NValue'+    {+    -- | Applying F-algebra Base functor data type (@NValueF@) to the F-algebra carrier (@NValue@), forming the \( F(A)-> A \)).+    _nValue :: f (NValueF (NValue t f m) m a)     }+  deriving (Generic, Typeable, Functor, Foldable) -addProvenance :: (NValue m -> Provenance m) -> NValue m -> NValue m-addProvenance f l@(NValue p v) = NValue (f l : p) v+instance (NVConstraint f, Show a) => Show (NValue' t f m a) where+  show (NValue' (extract -> v)) = show v -pattern NVConstant x <- NValue _ (NVConstantF x) -nvConstant x = NValue [] (NVConstantF x)-nvConstantP p x = NValue [p] (NVConstantF x)+-- ** Show1 -pattern NVStr s d <- NValue _ (NVStrF s d)+instance NVConstraint f  => Show1 (NValue' t f m) where+  liftShowsPrec sp sl p = \case+    NVConstant' atom  -> showsUnaryWith showsPrec             "NVConstantF" p atom+    NVStr' ns         -> showsUnaryWith showsPrec             "NVStrF"      p $ ignoreContext ns+    NVList' lst       -> showsUnaryWith (liftShowsPrec sp sl) "NVListF"     p lst+    NVSet'  _   attrs -> showsUnaryWith (liftShowsPrec sp sl) "NVSetF"      p attrs+    NVPath' path      -> showsUnaryWith showsPrec             "NVPathF"     p path+    NVClosure' c    _ -> showsUnaryWith showsPrec             "NVClosureF"  p c+    NVBuiltin' name _ -> showsUnaryWith showsPrec             "NVBuiltinF"  p name -nvStr s d = NValue [] (NVStrF s d)-nvStrP p s d = NValue [p] (NVStrF s d) -pattern NVPath x <- NValue _ (NVPathF x)+-- ** Traversable -nvPath x = NValue [] (NVPathF x)-nvPathP p x = NValue [p] (NVPathF x)+-- | @sequence@+sequenceNValue'+  :: (Functor n, Traversable f, Monad m, Applicative n)+  => (forall x . n x -> m x)+  -> NValue' t f m (n a)+  -> n (NValue' t f m a)+sequenceNValue' transform (NValue' v) =+  NValue' <$> traverse (sequenceNValueF transform) v -pattern NVList l <- NValue _ (NVListF l) -nvList l = NValue [] (NVListF l)-nvListP p l = NValue [p] (NVListF l)+-- ** Profunctor -pattern NVSet s x <- NValue _ (NVSetF s x)+-- | @lmap@+lmapNValueF :: Functor m => (b -> a) -> NValueF a m r -> NValueF b m r+lmapNValueF f = \case+  NVConstantF a  -> NVConstantF a+  NVStrF      s  -> NVStrF s+  NVPathF     p  -> NVPathF p+  NVListF     l  -> NVListF l+  NVSetF     p s -> NVSetF p s+  NVClosureF p g -> NVClosureF p (g . f)+  NVBuiltinF s g -> NVBuiltinF s (g . f) -nvSet s x = NValue [] (NVSetF s x)-nvSetP p s x = NValue [p] (NVSetF s x) -pattern NVClosure x f <- NValue _ (NVClosureF x f)+-- ** Free -nvClosure x f = NValue [] (NVClosureF x f)-nvClosureP p x f = NValue [p] (NVClosureF x f)+-- | @iter@+iterNValue'+  :: forall t f m a r+   . MonadDataContext f m+  => ((NValue' t f m a -> r) -> a -> r)+  -> (NValue' t f m r -> r)+  -> NValue' t f m a+  -> r+iterNValue' k f = fix ((f .) . fmap . k) -pattern NVBuiltin name f <- NValue _ (NVBuiltinF name f)+-- *** Utils -nvBuiltin name f = NValue [] (NVBuiltinF name f)-nvBuiltinP p name f = NValue [p] (NVBuiltinF name f)+-- | @hoistFree@: Back & forth hoisting in the monad stack+hoistNValue'+  :: (Functor m, Functor n, Functor f)+  => (forall x . n x -> m x)+  -> (forall x . m x -> n x)+  -> NValue' t f m a+  -> NValue' t f n a+hoistNValue' run lft (NValue' v) =+  NValue' $ lmapNValueF (hoistNValue lft run) . hoistNValueF lft <$> v+{-# inline hoistNValue' #-} -instance Show (NValueF m (Fix (NValueF m))) where-    showsPrec = flip go where-      go (NVConstantF atom)  = showsCon1 "NVConstant" atom-      go (NVStrF txt ctxt)   = showsCon2 "NVStr"      txt (appEndo ctxt [])-      go (NVListF     lst)   = showsCon1 "NVList"     lst-      go (NVSetF attrs _)    = showsCon1 "NVSet"      attrs-      go (NVClosureF p _)    = showsCon1 "NVClosure"  p-      go (NVPathF p)         = showsCon1 "NVPath"     p-      go (NVBuiltinF name _) = showsCon1 "NVBuiltin"  name+-- ** Monad -      showsCon1 :: Show a => String -> a -> Int -> String -> String-      showsCon1 con a d =-          showParen (d > 10) $ showString (con ++ " ") . showsPrec 11 a+-- |@bind@+bindNValue'+  :: (Traversable f, Monad m, Monad n)+  => (forall x . n x -> m x)+  -> (a -> n b)+  -> NValue' t f m a+  -> n (NValue' t f m b)+bindNValue' transform f (NValue' v) =+  NValue' <$> traverse (bindNValueF transform f) v -      showsCon2 :: (Show a, Show b)-                => String -> a -> b -> Int -> String -> String-      showsCon2 con a b d =-          showParen (d > 10)-              $ showString (con ++ " ")-              . showsPrec 11 a-              . showString " "-              . showsPrec 11 b+-- *** MonadTrans -instance Eq (NValue m) where-    NVConstant (NFloat x) == NVConstant (NInt y)   = x == fromInteger y-    NVConstant (NInt x)   == NVConstant (NFloat y) = fromInteger x == y-    NVConstant (NInt x)   == NVConstant (NInt y)   = x == y-    NVConstant (NFloat x) == NVConstant (NFloat y) = x == y-    NVStr x _ == NVStr y _ = x < y-    NVPath x  == NVPath y  = x < y-    _         == _         = False+-- | @lift@+liftNValue'+  :: (MonadTrans u, Monad m, Functor (u m), Functor f)+  => (forall x . u m x -> m x)+  -> NValue' t f m a+  -> NValue' t f (u m) a+liftNValue' run = hoistNValue' run lift -instance Ord (NValue m) where-    NVConstant (NFloat x) <= NVConstant (NInt y)   = x <= fromInteger y-    NVConstant (NInt x)   <= NVConstant (NFloat y) = fromInteger x <= y-    NVConstant (NInt x)   <= NVConstant (NInt y)   = x <= y-    NVConstant (NFloat x) <= NVConstant (NFloat y) = x <= y-    NVStr x _ <= NVStr y _ = x < y-    NVPath x  <= NVPath y  = x < y-    _         <= _         = False+-- **** MonadTransUnlift -checkComparable :: (Framed e m, Typeable m) => NValue m -> NValue m -> m ()-checkComparable x y = case (x, y) of-    (NVConstant (NFloat _), NVConstant (NInt _))   -> pure ()-    (NVConstant (NInt _),   NVConstant (NFloat _)) -> pure ()-    (NVConstant (NInt _),   NVConstant (NInt _))   -> pure ()-    (NVConstant (NFloat _), NVConstant (NFloat _)) -> pure ()-    (NVStr _ _, NVStr _ _) -> pure ()-    (NVPath _, NVPath _)   -> pure ()-    _ -> throwError $ Comparison x y+-- | @unlift@+unliftNValue'+  :: (MonadTrans u, Monad m, Functor (u m), Functor f)+  => (forall x . u m x -> m x) -- aka "run"+  -> NValue' t f (u m) a+  -> NValue' t f m a+unliftNValue' = hoistNValue' lift -builtin :: Monad m-        => String -> (m (NValue m) -> m (NValue m)) -> m (NValue m)-builtin name f = return $ nvBuiltin name f -builtin2 :: Monad m-         => String -> (m (NValue m) -> m (NValue m) -> m (NValue m))-         -> m (NValue m)-builtin2 name f = builtin name (builtin name . f)+-- ** Bijective Hask subcategory <-> @NValue'@+-- *** @F: Hask subcategory <-> NValue'@+-- #mantra#+-- $Patterns @F: Hask <-> NValue'@+--+-- Since Haskell and Nix are both recursive purely functional lazy languages.+-- And since recursion-schemes.+-- It is possible to create a direct functor between the Hask and Nix categories.+-- Or make Nix a DLS language of Haskell, embed it into a Hask, if you would like.+-- Of course, we mean: pick Hask subcategory and form Nix Category from it.+-- Take subcategory of Hask, and by applying functor to it - have a Nix Category.+-- Wouldn't it be cool and fast?+--+-- In fact - it is what we do here.+--+-- Since it is a proper way of scientific implementation, we would eventually form a+-- lawful functor.+--+-- Module pattens use @language PatternSynonyms@: bidirectional synonyms (@<-@),+-- and @ViewPatterns@: (@->@) at the same time.+-- @ViewPatterns Control.Comonad.extract@ extracts+-- from the @NValue (Free (NValueF a))@+-- the @NValueF a@. Which is @NValueF p m r@. Since it extracted from the+-- @NValue@, which is formed by \( (F a -> a) F a \) in the first place.+-- So @NValueF p m r@ which is extracted here, internally holds the next NValue.+--+-- Facts of bijection between Hask subcategory objects and Nix objects,+-- and between Hask subcategory morphisms and Nix morphisms are seen blow: -builtin3 :: Monad m-         => String-         -> (m (NValue m) -> m (NValue m) -> m (NValue m) -> m (NValue m))-         -> m (NValue m)-builtin3 name f =-    builtin name $ \a -> builtin name $ \b -> builtin name $ \c -> f a b c -isClosureNF :: Monad m => NValueNF m -> Bool-isClosureNF (Fix NVClosureF {}) = True-isClosureNF _ = False+-- | Using of Nulls is generally discouraged (in programming language design et al.), but, if you need it.+pattern NVNull' :: NVConstraint w => NValue' t w m a+pattern NVNull' = NVConstant' NNull -thunkEq :: MonadThunk (NValue m) (NThunk m) m-        => NThunk m -> NThunk m -> m Bool-thunkEq lt rt = force lt $ \lv -> force rt $ \rv -> valueEq lv rv+-- | Haskell constant to the Nix constant,+pattern NVConstant' :: NVConstraint w => NAtom -> NValue' t w m a+pattern NVConstant' x <- NValue' (extract -> NVConstantF x)+  where NVConstant' = NValue' . pure . NVConstantF --- | Checks whether two containers are equal, using the given item equality---   predicate. If there are any item slots that don't match between the two---   containers, the result will be False.-alignEqM-    :: (Align f, Traversable f, Monad m)-    => (a -> b -> m Bool)-    -> f a-    -> f b-    -> m Bool-alignEqM eq fa fb = fmap (either (const False) (const True)) $ runExceptT $ do-    pairs <- forM (Data.Align.align fa fb) $ \case-        These a b -> return (a, b)-        _ -> throwE ()-    forM_ pairs $ \(a, b) -> guard =<< lift (eq a b)+-- | Haskell text & context to the Nix text & context,+pattern NVStr' :: NVConstraint w => NixString -> NValue' t w m a+pattern NVStr' ns <- NValue' (extract -> NVStrF ns)+  where NVStr' = NValue' . pure . NVStrF -isDerivation :: MonadThunk (NValue m) (NThunk m) m-             => AttrSet (NThunk m) -> m Bool-isDerivation m = case M.lookup "type" m of-    Nothing -> pure False-    Just t -> force t $ valueEq (nvStr "derivation" mempty)+-- | Haskell @Path@ to the Nix path,+pattern NVPath' :: NVConstraint w => Path -> NValue' t w m a+pattern NVPath' x <- NValue' (extract -> NVPathF x)+  where NVPath' = NValue' . pure . NVPathF . coerce -valueEq :: MonadThunk (NValue m) (NThunk m) m-        => NValue m -> NValue m -> m Bool-valueEq l r = case (l, r) of-    (NVConstant lc, NVConstant rc) -> pure $ lc == rc-    (NVStr ls _, NVStr rs _) -> pure $ ls == rs-    (NVStr ls _, NVConstant NNull) -> pure $ ls == ""-    (NVConstant NNull, NVStr rs _) -> pure $ "" == rs-    (NVList ls, NVList rs) -> alignEqM thunkEq ls rs-    (NVSet lm _, NVSet rm _) -> do-        let compareAttrs = alignEqM thunkEq lm rm-        isDerivation lm >>= \case-            True -> isDerivation rm >>= \case-                True | Just lp <- M.lookup "outPath" lm-                     , Just rp <- M.lookup "outPath" rm-                       -> thunkEq lp rp-                _ -> compareAttrs-            _ -> compareAttrs-    (NVPath lp, NVPath rp) -> pure $ lp == rp-    _ -> pure False+-- | Haskell @[]@ to the Nix @[]@,+pattern NVList' :: NVConstraint w => [a] -> NValue' t w m a+pattern NVList' l <- NValue' (extract -> NVListF l)+  where NVList' = NValue' . pure . NVListF +-- | Haskell key-value to the Nix key-value,+pattern NVSet' :: NVConstraint w => PositionSet -> AttrSet a -> NValue' t w m a+pattern NVSet' p s <- NValue' (extract -> NVSetF p s)+  where NVSet' p s = NValue' $ pure $ NVSetF p s++-- | Haskell closure to the Nix closure,+pattern NVClosure' :: NVConstraint w => Params () -> (NValue t w m -> m a) -> NValue' t w m a+pattern NVClosure' x f <- NValue' (extract -> NVClosureF x f)+  where NVClosure' x f = NValue' $ pure $ NVClosureF x f++-- | Haskell functions to the Nix functions!+pattern NVBuiltin' :: NVConstraint w => VarName -> (NValue t w m -> m a) -> NValue' t w m a+pattern NVBuiltin' name f <- NValue' (extract -> NVBuiltinF name f)+  where NVBuiltin' name f = NValue' $ pure $ NVBuiltinF name f+{-# complete NVConstant', NVStr', NVPath', NVList', NVSet', NVClosure', NVBuiltin' #-}+++-- * @__NValue__@: Nix language values++-- | 'NValue t f m' is+--   a value in head normal form (it means only the tip of it has been+--   evaluated to the normal form, while the rest of it is in lazy+--   not evaluated form (thunk), this known as WHNF).+--+--   An action 'm (NValue t f m)' is a pending evaluation that+--   has yet to be performed.+--+--   An 't' is either:+--     * a pending evaluation.+--     * a value in head normal form.+--+--   The 'Free' structure is used here to represent the possibility that+--   Nix language allows cycles that may appear during normalization.++type NValue t f m = Free (NValue' t f m) t+++-- ** Free++-- | HOF of @iter@ from @Free@+iterNValue+  :: forall t f m r+   . MonadDataContext f m+  => ((NValue t f m -> r) -> t -> r)+  -> (NValue' t f m r -> r)+  -> NValue t f m+  -> r+iterNValue k f = fix ((iter f .) . fmap . k) -- already almost iterNValue'++iterNValueByDiscardWith+  :: MonadDataContext f m+  => r+  -> (NValue' t f m r -> r)+  -> NValue t f m+  -> r+iterNValueByDiscardWith = iterNValue . const . const+++-- | HOF of @iterM@ from @Free@+iterNValueM+  :: (MonadDataContext f m, Monad n)+  => (forall x . n x -> m x)+  -> ((NValue t f m -> n r) -> t -> n r)+  -> (NValue' t f m (n r) -> n r)+  -> NValue t f m+  -> n r+iterNValueM transform k f = fix (((iterM f <=< go) .) . fmap . k)+  where+    go (Pure x) = Pure <$> x -- It should be a 'sequenceA' if to remote 'transform' form function.+    go (Free fa) = Free <$> bindNValue' transform go fa++-- *** Utils++-- | @hoistFree@, Back & forth hoisting in the monad stack+hoistNValue+  :: (Functor m, Functor n, Functor f)+  => (forall x . n x -> m x)+  -> (forall x . m x -> n x)+  -> NValue t f m+  -> NValue t f n+hoistNValue run lft = hoistFree $ hoistNValue' run lft+{-# inline hoistNValue #-}++-- ** MonadTrans++-- | @lift@+liftNValue+  :: (MonadTrans u, Monad m, Functor (u m), Functor f)+  => (forall x . u m x -> m x)+  -> NValue t f m+  -> NValue t f (u m)+liftNValue f = hoistNValue f lift+++-- *** MonadTransUnlift+-- | @unlift@+unliftNValue+  :: (MonadTrans u, Monad m, Functor (u m), Functor f)+  => (forall x . u m x -> m x)  -- aka "run"+  -> NValue t f (u m)+  -> NValue t f m+unliftNValue = hoistNValue lift+++-- ** Methods @F: Hask → NValue@+--+-- $Methods @F: Hask → NValue@+--+-- The morphisms of the functor @Hask → NValue@.+-- Continuation of the mantra: "Nix.Value#mantra"++-- | Using of Nulls is generally discouraged (in programming language design et al.), but, if you need it.++mkNVStrWithoutContext :: NVConstraint f+  => Text+  -> NValue t f m+mkNVStrWithoutContext = NVStr . mkNixStringWithoutContext+++builtin+  :: forall m f t+   . (MonadThunk t m (NValue t f m), MonadDataContext f m)+  => VarName -- ^ function name+  -> ( NValue t f m+    -> m (NValue t f m)+    ) -- ^ unary function+  -> m (NValue t f m)+builtin = (pure .) . NVBuiltin+++builtin2+  :: (MonadThunk t m (NValue t f m), MonadDataContext f m)+  => VarName -- ^ function name+  -> ( NValue t f m+    -> NValue t f m+    -> m (NValue t f m)+    ) -- ^ binary function+  -> m (NValue t f m)+builtin2 = ((.) <*> (.)) . builtin+++builtin3+  :: (MonadThunk t m (NValue t f m), MonadDataContext f m)+  => VarName -- ^ function name+  -> ( NValue t f m+    -> NValue t f m+    -> NValue t f m+    -> m (NValue t f m)+    ) -- ^ ternary function+  -> m (NValue t f m)+builtin3 =+  liftA2 (.) -- compose 2 together+    builtin+    ((.) . builtin2)++-- *** @F: Evaluation -> NValue@++pattern NVNull = Free NVNull'+pattern NVThunk t = Pure t+pattern NVValue v = Free v+{-# complete NVThunk, NVValue, NVNull #-}+pattern NVConstant x = Free (NVConstant' x)+pattern NVStr ns = Free (NVStr' ns)+pattern NVPath x = Free (NVPath' x)+pattern NVList l = Free (NVList' l)+pattern NVSet s x = Free (NVSet' s x)+pattern NVBuiltin name f = Free (NVBuiltin' name f)+pattern NVClosure x f = Free (NVClosure' x f)+{-# complete NVThunk, NVConstant, NVStr, NVPath, NVList, NVSet, NVClosure, NVBuiltin #-}+++++-- * @TStringContext@++data TStringContext = NoContext | HasContext+ deriving Show++instance Semigroup TStringContext where+  (<>) NoContext NoContext = NoContext+  (<>) _         _         = HasContext+++instance Monoid TStringContext where+  mempty = NoContext++-- * @ValueType@+ data ValueType-    = TInt-    | TFloat-    | TBool-    | TNull-    | TString-    | TList-    | TSet-    | TClosure-    | TPath-    | TBuiltin-    deriving Show+  = TInt+  | TFloat+  | TBool+  | TNull+  | TString TStringContext+  | TList+  | TSet+  | TClosure+  | TPath+  | TBuiltin+ deriving Show -valueType :: NValueF m r -> ValueType-valueType = \case-    NVConstantF a -> case a of-        NInt _    -> TInt-        NFloat _  -> TFloat-        NBool _   -> TBool-        NNull     -> TNull-    NVStrF {}     -> TString-    NVListF {}    -> TList-    NVSetF {}     -> TSet-    NVClosureF {} -> TClosure-    NVPathF {}    -> TPath-    NVBuiltinF {} -> TBuiltin -describeValue :: ValueType -> String-describeValue = \case-    TInt     -> "an integer"-    TFloat   -> "a float"-    TBool    -> "a boolean"-    TNull    -> "a null"-    TString  -> "a string"-    TList    -> "a list"-    TSet     -> "an attr set"-    TClosure -> "a function"-    TPath    -> "a path"-    TBuiltin -> "a builtin function"+-- | Determine type of a value+valueType :: NValueF a m r -> ValueType+valueType =+  \case+    NVConstantF a ->+      case a of+        NURI   _ -> TString mempty+        NInt   _ -> TInt+        NFloat _ -> TFloat+        NBool  _ -> TBool+        NNull    -> TNull+    NVStrF ns  ->+      TString $+        HasContext `whenTrue` hasContext ns+    NVListF{}    -> TList+    NVSetF{}     -> TSet+    NVClosureF{} -> TClosure+    NVPathF{}    -> TPath+    NVBuiltinF{} -> TBuiltin -instance Show (NValueF m (NThunk m)) where-    show = show . describeValue . valueType -instance Show (NValue m) where-    show (NValue _ v)  = show v+-- | Describe type value+describeValue :: ValueType -> Text+describeValue =+  \case+    TInt               -> "an integer"+    TFloat             -> "a float"+    TBool              -> "a boolean"+    TNull              -> "a null"+    TString NoContext  -> "a string with no context"+    TString HasContext -> "a string"+    TList              -> "a list"+    TSet               -> "an attr set"+    TClosure           -> "a function"+    TPath              -> "a path"+    TBuiltin           -> "a builtin function" -instance Show (NThunk m) where-    show (NThunk _ (Value v)) = show v-    show (NThunk _ _) = "<thunk>" -data ValueFrame m-    = ForcingThunk-    | ConcerningValue (NValue m)-    | Comparison (NValue m) (NValue m)-    | Addition (NValue m) (NValue m)-    | Multiplication (NValue m) (NValue m)-    | Division (NValue m) (NValue m)-    | Coercion ValueType ValueType-    | CoercionToJsonNF (NValueNF m)-    | CoercionFromJson A.Value-    | ExpectationNF ValueType (NValueNF m)-    | Expectation ValueType (NValue m)-    deriving (Show, Typeable)+showValueType :: (MonadThunk t m (NValue t f m), Comonad f)+  => NValue t f m+  -> m Text+showValueType (Pure t) = showValueType =<< force t+showValueType (Free (NValue' (extract -> v))) =+  pure $ describeValue $ valueType v -instance Typeable m => Exception (ValueFrame m) +-- * @ValueFrame@++data ValueFrame t f m+  = ForcingThunk t+  | ConcerningValue (NValue t f m)+  | Comparison (NValue t f m) (NValue t f m)+  | Addition (NValue t f m) (NValue t f m)+  | Multiplication (NValue t f m) (NValue t f m)+  | Division (NValue t f m) (NValue t f m)+  | Coercion ValueType ValueType+  | CoercionToJson (NValue t f m)+  | CoercionFromJson Aeson.Value+  | Expectation ValueType (NValue t f m)+ deriving Typeable++deriving instance (NVConstraint f, Show t) => Show (ValueFrame t f m)+++-- * @MonadDataContext@++type MonadDataContext f (m :: Type -> Type)+  = (Comonad f, Applicative f, Traversable f, Monad m)++-- * @MonadDataErrorContext@++type MonadDataErrorContext t f m+  = (Show t, Typeable t, Typeable m, Typeable f, MonadDataContext f m, MonadFail m)++instance MonadDataErrorContext t f m => Exception (ValueFrame t f m)+++-- * @instance Eq NValue'@++instance (Eq a, Comonad f) => Eq (NValue' t f m a) where+    (==) (NValue' (extract -> x)) (NValue' (extract -> y)) = x == y++-- * @instance Eq1 NValue'@++-- TH derivable works only after MonadDataContext+instance Comonad f => Eq1 (NValue' t f m) where+  liftEq eq (NValue' (extract -> x)) (NValue' (extract -> y)) = liftEq eq x y+++-- * @NValueF@ traversals, getter & setters++-- | Make traversals for Nix traversable structures. $(makeTraversals ''NValueF)-$(makeLenses ''Provenance)-$(makeLenses ''NThunk)-$(makeLenses ''NValue) -alterF :: (Eq k, Hashable k, Functor f)-       => (Maybe v -> f (Maybe v)) -> k -> HashMap k v -> f (HashMap k v)-alterF f k m = f (M.lookup k m) <&> \case-    Nothing -> M.delete k m-    Just v  -> M.insert k v m+-- | Make lenses for the Nix values+$(makeLenses ''NValue') -hashAt :: VarName -> Lens' (AttrSet v) (Maybe v)-hashAt = flip alterF -key :: Applicative f => VarName -> LensLike' f (NValue m) (Maybe (NThunk m))-key k = baseValue._NVSetF._1.hashAt k+-- | Lens-generated getter-setter function for a traversable NValue' key-val structures.+--   Nix value analogue of the @Data-Aeson-Lens@:@key :: AsValue t => Text -> Traversal' t Value@.+key+  :: (Traversable f, Applicative g)+  => VarName+  -> LensLike' g (NValue' t f m a) (Maybe a)+key k = nValue . traverse . _NVSetF . _2 . hashAt k
+ src/Nix/Value/Equal.hs view
@@ -0,0 +1,209 @@+{-# language AllowAmbiguousTypes #-}+{-# language ConstraintKinds #-}+{-# language TypeFamilies #-}++{-# options_ghc -Wno-missing-pattern-synonym-signatures #-}++module Nix.Value.Equal where++import           Nix.Prelude             hiding ( Comparison )+import           Control.Comonad                ( Comonad(extract))+import           Control.Monad.Free             ( Free(Pure,Free) )+import           Control.Monad.Trans.Except     ( throwE )+import           Data.Semialign                 ( Align+                                                , Semialign(align)+                                                )+import qualified Data.HashMap.Lazy             as HashMap.Lazy+import           Data.These                     ( These(These) )+import           Nix.Atoms+import           Nix.Frames+import           Nix.String+import           Nix.Thunk+import           Nix.Value+import           Nix.Expr.Types                 ( AttrSet )++checkComparable+  :: ( Framed e m+     , MonadDataErrorContext t f m+     )+  => NValue t f m+  -> NValue t f m+  -> m ()+checkComparable x y =+  case (x, y) of+    (NVConstant (NInt   _), NVConstant (NInt   _)) -> stub+    (NVConstant (NInt   _), NVConstant (NFloat _)) -> stub+    (NVConstant (NFloat _), NVConstant (NInt   _)) -> stub+    (NVConstant (NFloat _), NVConstant (NFloat _)) -> stub+    (NVStr       _        , NVStr       _        ) -> stub+    (NVPath      _        , NVPath      _        ) -> stub+    _                                              -> throwError $ Comparison x y++-- | Checks whether two containers are equal, using the given item equality+--   predicate. If there are any item slots that don't match between the two+--   containers, the result will be @False@.+alignEqM+  :: (Align f, Traversable f, Monad m)+  => (a -> b -> m Bool)+  -> f a+  -> f b+  -> m Bool+alignEqM eq fa fb =+  fmap+    (isRight @() @())+    $ runExceptT $+      traverse_+        (guard <=< lift . uncurry eq)+        =<< traverse+            (\case+              These a b -> pure (a, b)+              _         -> throwE mempty+            )+            (Data.Semialign.align fa fb)++alignEq :: (Align f, Traversable f) => (a -> b -> Bool) -> f a -> f b -> Bool+alignEq eq fa fb =+  runIdentity $ alignEqM ((Identity .) . eq) fa fb++isDerivationM+  :: Monad m+  => ( t+     -> m (Maybe NixString)+     )+  -> AttrSet t+  -> m Bool+isDerivationM f m =+  maybe+    False+    -- (2019-03-18):+    -- We should probably really make sure the context is empty here+    -- but the C++ implementation ignores it.+    ((==) "derivation" . ignoreContext)+    . join <$> traverse f (HashMap.Lazy.lookup "type" m)+++isDerivation+  :: Monad m+  => ( t+     -> Maybe NixString+     )+  -> AttrSet t+  -> Bool+isDerivation f = runIdentity . isDerivationM (Identity . f)++valueFEqM+  :: Monad n+  => (  AttrSet a+     -> AttrSet a+     -> n Bool+     )+  -> (  a+     -> a+     -> n Bool+     )+  -> NValueF p m a+  -> NValueF p m a+  -> n Bool+valueFEqM attrsEq eq =+  curry $+    \case+      (NVConstantF (NFloat x), NVConstantF (NInt   y)) -> pure $             x == fromInteger y+      (NVConstantF (NInt   x), NVConstantF (NFloat y)) -> pure $ fromInteger x == y+      (NVConstantF lc        , NVConstantF rc        ) -> pure $            lc == rc+      (NVStrF      ls        , NVStrF      rs        ) -> pure $  (\ i -> i ls == i rs) ignoreContext+      (NVListF     ls        , NVListF     rs        ) ->          alignEqM eq ls rs+      (NVSetF      _      lm , NVSetF      _      rm ) ->          attrsEq lm rm+      (NVPathF     lp        , NVPathF     rp        ) ->             pure $ lp == rp+      _                                                -> pure False++valueFEq+  :: (AttrSet a -> AttrSet a -> Bool)+  -> (a -> a -> Bool)+  -> NValueF p m a+  -> NValueF p m a+  -> Bool+valueFEq attrsEq eq x y =+  runIdentity $+    valueFEqM+      ((Identity .) . attrsEq)+      ((Identity .) . eq)+      x+      y++compareAttrSetsM+  :: Monad m+  => (t -> m (Maybe NixString))+  -> (t -> t -> m Bool)+  -> AttrSet t+  -> AttrSet t+  -> m Bool+compareAttrSetsM f eq lm rm =+  bool+    compareAttrs+    (fromMaybe compareAttrs equalOutPaths)+    =<< areDerivations+ where+  areDerivations = on (liftA2 (&&)) (isDerivationM f              ) lm rm+  equalOutPaths  = on (liftA2   eq) (HashMap.Lazy.lookup "outPath") lm rm+  compareAttrs   =     alignEqM eq                                  lm rm++compareAttrSets+  :: (t -> Maybe NixString)+  -> (t -> t -> Bool)+  -> AttrSet t+  -> AttrSet t+  -> Bool+compareAttrSets f eq lm rm =+  runIdentity $ compareAttrSetsM (Identity . f) ((Identity .) . eq) lm rm++valueEqM+  :: forall t f m+   . (MonadThunk t m (NValue t f m), NVConstraint f)+  => NValue t f m+  -> NValue t f m+  -> m Bool+valueEqM (  Pure x) (  Pure y) = thunkEqM x y+valueEqM (  Pure x) y@(Free _) = thunkEqM x =<< thunk (pure y)+valueEqM x@(Free _) (  Pure y) = (`thunkEqM` y) =<< thunk (pure x)+valueEqM (Free (NValue' (extract -> x))) (Free (NValue' (extract -> y))) =+  valueFEqM+    (compareAttrSetsM findNVStr valueEqM)+    valueEqM+    x+    y+ where+  findNVStr :: NValue t f m -> m (Maybe NixString)+  findNVStr =+    free+      (pure .+        (\case+          NVStr s -> pure s+          _       -> mempty+        ) <=< force+      )+      (pure .+        \case+          NVStr' s -> pure s+          _        -> mempty+      )++-- This function has mutual recursion with `valueEqM`, and this function so far is not used across the project,+-- but that one is.+thunkEqM :: (MonadThunk t m (NValue t f m), NVConstraint f) => t -> t -> m Bool+thunkEqM lt rt =+  do+    lv <- force lt+    rv <- force rt++    let+      unsafePtrEq =+        bool+          (valueEqM lv rv)+          (pure True)+          $ on (==) thunkId lt rt++    case (lv, rv) of+      (NVClosure _ _, NVClosure _ _) -> unsafePtrEq+      (NVList _     , NVList _     ) -> unsafePtrEq+      (NVSet _ _    , NVSet _ _    ) -> unsafePtrEq+      _                              -> valueEqM lv rv
+ src/Nix/Value/Monad.hs view
@@ -0,0 +1,20 @@+module Nix.Value.Monad where++-- * @MonadValue@ - a main implementation class++class MonadValue v m where+  -- | Wrap value into a thunk.+  defer :: m v -> m v+  -- | Force the evaluation of the value.+  demand :: v -> m v+  -- | If 'v' is a thunk, 'inform' allows us to modify the action to be+  --   performed by the thunk, perhaps by enriching it with scope info, for+  --   example.+  inform :: v -> m v+++-- * @MonadValueF@ - a Kleisli-able customization class++class MonadValueF v m where+  demandF :: (v -> m r) -> v -> m r+  informF :: (m v -> m v) -> v -> m v
+ src/Nix/Var.hs view
@@ -0,0 +1,35 @@+{-# language AllowAmbiguousTypes #-}+{-# language ConstraintKinds #-}++{-# options_ghc -Wno-orphans #-}+{-# options_ghc -Wno-unused-top-binds #-}++module Nix.Var ()+where++import           Nix.Prelude+import           Control.Monad.Ref+import           Data.GADT.Compare  ( GEq(..) )+import           Data.STRef         ( STRef )+import           Type.Reflection    ( (:~:)(Refl) )++import           Unsafe.Coerce      ( unsafeCoerce )++eqVar :: GEq (Ref m) => Ref m a -> Ref m a -> Bool+eqVar a b = isJust $ geq a b++--TODO: Upstream GEq instances+-- Upstream thread: https://github.com/haskellari/some/pull/34+instance GEq IORef where+  geq = gEqual++instance GEq (STRef s) where+  geq = gEqual++-- | Simply a helper function+gEqual :: Eq a => a -> b -> Maybe c+gEqual a b =+  bool+    Nothing+    (pure $ unsafeCoerce Refl)+    (a == unsafeCoerce b)
src/Nix/XML.hs view
@@ -1,54 +1,110 @@-{-# LANGUAGE LambdaCase #-}--module Nix.XML where+module Nix.XML+  ( toXML )+where -import           Data.Fix-import qualified Data.HashMap.Lazy as M-import           Data.List-import           Data.Ord-import qualified Data.Text as Text+import           Nix.Prelude+import qualified Data.HashMap.Lazy             as M import           Nix.Atoms import           Nix.Expr.Types+import           Nix.String import           Nix.Value-import           Text.XML.Light+import           Text.XML.Light                 ( Element(Element)+                                                , Attr(Attr)+                                                , Content(Elem)+                                                , unqual+                                                , ppElement+                                                ) -toXML :: Functor m => NValueNF m -> String-toXML = (.) ((++ "\n") .-             ("<?xml version='1.0' encoding='utf-8'?>\n" ++) .-             ppElement .-             (\e -> Element (unqual "expr") [] [Elem e] Nothing))-        $ cata-        $ \case-    NVConstantF a -> case a of-        NInt n   -> mkElem "int" "value" (show n)-        NFloat f -> mkElem "float" "value" (show f)-        NBool b  -> mkElem "bool" "value" (if b then "true" else "false")-        NNull    -> Element (unqual "null") [] [] Nothing+toXML :: forall t f m . MonadDataContext f m => NValue t f m -> NixString+toXML = runWithStringContext . fmap pp . iterNValueByDiscardWith cyc phi+ where+  cyc = pure $ mkEVal "string" "<expr>" -    NVStrF t _ -> mkElem "string" "value" (Text.unpack t)-    NVListF l  -> Element (unqual "list") [] (Elem <$> l) Nothing+  pp :: Element -> Text+  pp e =+    heading+    <> fromString+        (ppElement $+          mkE+            "expr"+            (one $ Elem e)+        )+    <> "\n"+   where+    heading = "<?xml version='1.0' encoding='utf-8'?>\n" -    NVSetF s _ -> Element (unqual "attrs") []-        (map (\(k, v) -> Elem (Element (unqual "attr")-                                      [Attr (unqual "name") (Text.unpack k)]-                                      [Elem v] Nothing))-             (sortBy (comparing fst) $ M.toList s)) Nothing+  phi :: NValue' t f m (WithStringContext Element) -> WithStringContext Element+  phi = \case+    NVConstant' a ->+      pure $+        case a of+          NURI   t -> mkEVal "string" t+          NInt   n -> mkEVal "int"    $ show n+          NFloat f -> mkEVal "float"  $ show f+          NBool  b -> mkEVal "bool"   $ if b then "true" else "false"+          NNull    -> mkE    "null"     mempty -    NVClosureF p _  -> Element (unqual "function") [] (paramsXML p) Nothing-    NVPathF fp -> mkElem "path" "value" fp-    NVBuiltinF name _ -> mkElem "function" "name" name+    NVStr' str ->+      mkEVal "string" <$> extractNixString str+    NVList' l ->+      mkE "list" . fmap Elem <$> sequenceA l -mkElem :: String -> String -> String -> Element-mkElem n a v = Element (unqual n) [Attr (unqual a) v] [] Nothing+    NVSet' _ s ->+      mkE+        "attrs"+        . fmap+            mkElem'+            . sortWith fst . M.toList+        <$> sequenceA s+     where+      mkElem' :: (VarName, Element) -> Content+      mkElem' (k, v) =+        Elem $+          Element+            (unqual "attr")+            (one $ Attr (unqual "name") $ toString k)+            (one $ Elem v)+            Nothing +    NVClosure' p _ ->+      pure $+        mkE+          "function"+          (paramsXML p)+    NVPath' fp        -> pure $ mkEVal "path" $ fromString $ coerce fp+    NVBuiltin' name _ -> pure $ mkEName "function" name++mkE :: Text -> [Content] -> Element+mkE (toString -> n) c =+  Element+    (unqual n)+    mempty+    c+    Nothing++mkElem :: Text -> Text -> Text -> Element+mkElem (toString -> n) (toString -> a) (toString -> v) =+  Element+    (unqual n)+    (one $ Attr (unqual a) v)+    mempty+    Nothing++mkEVal :: Text -> Text -> Element+mkEVal = (`mkElem` "value")++mkEName :: Text -> VarName -> Element+mkEName x (coerce -> y) = (`mkElem` "name") x y+ paramsXML :: Params r -> [Content]-paramsXML (Param name) =-    [Elem $ mkElem "varpat" "name" (Text.unpack name)]-paramsXML (ParamSet s b mname) =-    [Elem $ Element (unqual "attrspat") (battr ++ nattr) (paramSetXML s) Nothing]-  where-    battr = [ Attr (unqual "ellipsis") "1" | b ]-    nattr = maybe [] ((:[]) . Attr (unqual "name") . Text.unpack) mname+paramsXML (Param name) = one $ Elem $ mkEName "varpat" name+paramsXML (ParamSet mname variadic pset) =+  one $ Elem $ Element (unqual "attrspat") (battr <> nattr) (paramSetXML pset) Nothing+ where+  battr =+    one (Attr (unqual "ellipsis") "1") `whenTrue` (variadic == Variadic)+  nattr =+    (one . Attr (unqual "name") . toString) `whenJust` mname  paramSetXML :: ParamSet r -> [Content]-paramSetXML = map (\(k,_) -> Elem $ mkElem "attr" "name" (Text.unpack k))+paramSetXML = fmap (Elem . mkEName "attr" . fst)
tests/EvalTests.hs view
@@ -1,132 +1,206 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE UndecidableInstances #-}+{-# language QuasiQuotes #-}+{-# language TemplateHaskell #-} -{-# OPTIONS_GHC -Wno-missing-signatures -Wno-orphans #-}+{-# options_ghc -Wno-missing-signatures #-} -module EvalTests (tests, genEvalCompareTests) where +module EvalTests+  ( tests+  , genEvalCompareTests+  ) where++import           Nix.Prelude import           Control.Monad.Catch-import           Control.Monad (when)-import           Control.Monad.IO.Class-import qualified Data.HashMap.Lazy as M-import           Data.Maybe (isJust)-import           Data.String.Interpolate.IsString-import           Data.Text (Text)+import           Data.List ((\\))+import qualified Data.Set as S import           Data.Time+import           NeatInterpolation (text) import           Nix+import           Nix.Standard+import           Nix.Value.Equal import qualified System.Directory as D-import           System.Environment-import           System.FilePath import           Test.Tasty import           Test.Tasty.HUnit import           Test.Tasty.TH import           TestCommon  case_basic_sum =-    constantEqualText "2" "1 + 1"+  constantEqualText+    "2"+    "1 + 1"  case_basic_div =-    constantEqualText "3" "builtins.div 6 2"+  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_zero_div =+  traverse_ assertNixEvalThrows+    [ "builtins.div 1 0"+    , "builtins.div 1.0 0"+    , "builtins.div 1 0.0"+    , "builtins.div 1.0 0.0"+    ] +case_bit_ops =+  traverse_ (uncurry constantEqualText)+    [ ("0", "builtins.bitAnd 1 0")+    , ("1", "builtins.bitOr 1 1")+    , ("3", "builtins.bitXor 1 2")+    ]+ case_basic_function =-    constantEqualText "2" "(a: a) 2"+  constantEqualText+    "2"+    "(a: a) 2"  case_set_attr =-    constantEqualText "2" "{ a = 2; }.a"+  constantEqualText+    "2"+    "{ a = 2; }.a"  case_function_set_arg =-    constantEqualText "2" "({ a }: 2) { a = 1; }"+  constantEqualText+    "2"+    "({ a }: 2) { a = 1; }"  case_function_set_two_arg =-    constantEqualText "2" "({ a, b ? 3 }: b - a) { a = 1; }"+  constantEqualText+    "2"+    "({ a, b ? 3 }: b - a) { a = 1; }"  case_function_set_two_arg_default_scope =-    constantEqualText "2" "({ x ? 1, y ? x * 3 }: y - x) {}"+  constantEqualText+    "2"+    "({ x ? 1, y ? x * 3 }: y - x) {}"  case_function_default_env =-    constantEqualText "2" "let default = 2; in ({ a ? default }: a) {}"+  constantEqualText+    "2"+    "let default = 2; in ({ a ? default }: a) {}"  case_function_definition_uses_environment =-    constantEqualText "3" "let f = (let a=1; in x: x+a); in f 2"+  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"+  -- 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"+  -- 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 =-    constantEqualText "false" "({a ? 2}@attrs: attrs ? a) {}"+  constantEqualText+    "false"+    "({a ? 2}@attrs: attrs ? a) {}"  case_function_arg_shadowing =-    constantEqualText "6" "(y: y: x: x: x + y) 1 2 3 4"+  constantEqualText+    "6"+    "(y: y: x: x: x + y) 1 2 3 4"  case_function_recursive_args =-    constantEqualText "2" "({ x ? 1, y ? x * 3}: y - x) {}"+  constantEqualText+    "2"+    "({ x ? 1, y ? x * 3}: y - x) {}"  case_function_recursive_sets =-    constantEqualText "[ [ 6 4 100 ] 4 ]" [i|-        let x = rec {+  constantEqualText+    "[ [ 6 4 100 ] 4 ]"+    [text|+      let x = rec { -          y = 2;-          z = { w = 4; };-          v = rec {-            u = 6;-            t = [ u z.w s ];-          };+        y = 2;+        z = { w = 4; };+        v = rec {+          u = 6;+          t = [ u z.w s ];+        }; -        }; s = 100; in [ x.v.t x.z.w ]+      }; s = 100; in [ x.v.t x.z.w ]     |]  case_nested_with =-    constantEqualText "2" "with { x = 1; }; with { x = 2; }; x"+  constantEqualText+    "2"+    "with { x = 1; }; with { x = 2; }; x" +case_with_strictness =+  constantEqualText+    "5"+    "let x = with x; with { a = 5; }; a; in x"+ case_match_failure_null =-    constantEqualText "null" "builtins.match \"ab\" \"abc\""+  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\""+  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\""+  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\""+  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\""+  assertNixEvalThrows+    "builtins.findFile [{ path=\"./tests/files\"; prefix=\"\"; }] \"not_found.nix\""  case_find_file_failure_invalid_arg_1 =-    assertNixEvalThrows "builtins.findFile 1 \"files\""+  assertNixEvalThrows+    "builtins.findFile 1 \"files\""  case_find_file_failure_invalid_arg_2 =-    assertNixEvalThrows "builtins.findFile [{ path=\"./tests/files\"; prefix=\"\"; }] 2"+  assertNixEvalThrows+    "builtins.findFile [{ path=\"./tests/files\"; prefix=\"\"; }] 2"  case_find_file_failure_invalid_arg_no_path =-    assertNixEvalThrows "builtins.findFile [{ prefix=\"\"; }] \"files\""+  assertNixEvalThrows+    "builtins.findFile [{ prefix=\"\"; }] \"files\"" +case_infinite_recursion =+  assertNixEvalThrows+    "let foo = a: bar a; bar = a: foo a; in foo 3"++case_nested_let =+  constantEqualText+    "3"+    "let a = 3; x.x = 2; in a"++case_nested_nested_let =+  constantEqualText+    "3"+    "let a = 3; x.x = let b = a; in b; c = x.x; in c"+ case_inherit_in_rec_set =-    constantEqualText "1" "let x = 1; in (rec { inherit x; }).x"+  constantEqualText+    "1"+    "let x = 1; in (rec { inherit x; }).x"  case_lang_version =-    constantEqualText "5" "builtins.langVersion"+  constantEqualText+    "5"+    "builtins.langVersion"  case_rec_set_attr_path_simpl =-    constantEqualText "123" [i|+  constantEqualText+    "123"+    [text|       let x = rec {         foo.number = 123;         foo.function = y: foo.number;@@ -134,7 +208,9 @@     |]  case_inherit_from_set_has_no_scope =-    constantEqualText' "false" [i|+  constantEqualText'+    "false"+    [text|       (builtins.tryEval (         let x = 1;             y = { z = 2; };@@ -142,203 +218,451 @@       )).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 ]+-- github/orblivion (2018-08-05): Adding these failing tests so we fix this feature+--+-- case_overrides =+--     constantEqualText' "2" [text|+--       let+--+--         overrides = { a = 2; };+--+--       in (rec {+--         __overrides = overrides;+--         x = a;+--         a = 1;+--       }.__overrides.a) --     |] --- 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_inherit_overrides =+--     constantEqualText' "2" [text|+--       let+--+--         __overrides = { a = 2; };+--+--       in (rec {+--         inherit __overrides;+--         x = a;+--         a = 1;+--       }.__overrides.a) --     |] +case_unsafegetattrpos =+  traverse_ (uncurry constantEqualText)+    [ ( "[ 5 14 ]"+      , [text|+          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 ]+          |]+      )+    , ( "[ 5 14 ]"+      , [text|+          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 ]+        |]+      )+    , ( "[ 6 7 ]"+      , [text|+          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 ]+          |]+      )+    , ( "[ 7 7 ]"+      , [text|+        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+    --+    -- , ( "[ 7 13 ]"+    --   , [text|+    --       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 ]+    --       |]+    --   )++    -- , ( "[ 7 13 ]"+    --   , [text|+    --       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|[-  {-    foobar = "foobar";-    foo = "foo";-    bar = "bar";-  }-  {-    foobar = "foo + bar";-    foo = "foo + ";-    bar = "bar";-  }-]|] [i|-    let-      fix = f: let x = f x; in x;-      extends = f: rattrs: self:-        let super = rattrs self; in super // f self super;-      f = self: { foo = "foo";-                  bar = "bar";-                  foobar = self.foo + self.bar; };-      g = self: super: { foo = super.foo + " + "; };-    in [ (fix f) (fix (extends g f)) ]-|]+  constantEqualText+    [text|+      [+        {+          foobar = "foobar";+          foo = "foo";+          bar = "bar";+        }+        {+          foobar = "foo + bar";+          foo = "foo + ";+          bar = "bar";+        }+      ]+    |]+    [text|+      let+        fix = f: let x = f x; in x;+        extends = f: rattrs: self:+          let super = rattrs self; in super // f self super;+        f = self: { foo = "foo";+                    bar = "bar";+                    foobar = self.foo + self.bar; };+        g = self: super: { foo = super.foo + " + "; };+      in [ (fix f) (fix (extends g f)) ]+    |]  case_fixed_points_and_fold =-    constantEqualText [i|[ {} {} ]|] [i|-let-  extends = f: rattrs: self:-    let super = rattrs self; in super // f self super;-  flip = f: a: b: f b a;-  toFixFold = builtins.foldl' (flip extends) (self: {}) ([(self: super: {})]);-  toFix = extends (self: super: {}) (self: {});-  fix = f: let x = f x; in x;-in [ (fix toFixFold) (fix toFix) ]-|]+  constantEqualText+    [text|+      [ {} {} ]+    |]+    [text|+      let+        extends = f: rattrs: self:+          let super = rattrs self; in super // f self super;+        flip = f: a: b: f b a;+        toFixFold = builtins.foldl' (flip extends) (self: {}) ([(self: super: {})]);+        toFix = extends (self: super: {}) (self: {});+        fix = f: let x = f x; in x;+      in [ (fix toFixFold) (fix toFix) ]+    |]  case_fixed_points_attrsets =-    constantEqualText "{ x = { y = { z = 100; }; z = { y = 100; }; }; }" [i|+  constantEqualText+    "{ x = { y = { z = 100; }; z = { y = 100; }; }; }"+    [text|       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     |] +case_function_equals =+  traverse_ (uncurry constantEqualText)+    [ -- ( "true"+      -- , "{f = x: x;} == {f = x: x;}"+      -- )+      -- ( "true"+      -- , "[(x: x)] == [(x: x)]"+      -- )+      ( "false"+      , "(let a = (x: x); in a == a)"+      )+    , ( "true"+      , "(let a = {f = x: x;}; in a == a)"+      )+    , ( "true"+      , "(let a = [(x: x)]; in a == a)"+      )+    , ( "false"+      , "builtins.pathExists \"/var/empty/invalid-directory\""+      )+    ]++case_directory_pathexists =+  constantEqualText+    "false"+    "builtins.pathExists \"/var/empty/invalid-directory\""+ -- jww (2018-05-02): This constantly changes!--- case_placeholder =---   constantEqualText---       "\"/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9\""---       "builtins.placeholder \"out\""+case_placeholder =+  constantEqualText+    "\"/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9\""+    "builtins.placeholder \"out\"" ------------------------+case_rec_path_attr =+  constantEqualText+    "10"+    "let src = 10; x = rec { passthru.src = src; }; in x.passthru.src" +case_mapattrs_builtin =+  constantEqualText'+    "{ a = \"afoo\"; b = \"bbar\"; }"+    [text|+      (builtins.mapAttrs (x: y: x + y) {+        a = "foo";+        b = "bar";+      })+    |]++-- Regression test for #373+case_regression_373 :: Assertion+case_regression_373 =+  traverse_ (uncurry sameFreeVars)+    [ ( "{ inherit a; }"+      , one "a"+      )+    , ("rec {inherit a; }"+      , one "a"+      )+    , ( "let inherit a; in { }"+      , one "a"+      )+    ]++case_bound_vars :: Assertion+case_bound_vars =+  traverse_ noFreeVars+    [ "a: a"+    , "{b}: b"+    , "let c = 5; d = c; in d"+    , "rec { e = 5; f = e; }"+    ]+  where+    noFreeVars = flip sameFreeVars mempty+++case_expression_split =+  constantEqualText+    "[ \"\" [ \"a\" ] \"c\" ]"+    "(x: builtins.deepSeq x x) (builtins.split \"(a)b\" \"abc\")"++case_empty_string_equal_null_is_false =+  constantEqualText+    "false"+    "\"\" == null"++case_null_equal_empty_string_is_false =+  constantEqualText+    "false"+    "null == \"\""++case_empty_string_not_equal_null_is_true =+  constantEqualText+    "true"+    "\"\" != null"++case_null_equal_not_empty_string_is_true =+  constantEqualText+    "true"+    "null != \"\""++case_list_nested_bottom_diverges =+  assertNixEvalThrows+    "let nested = [(let x = x; in x)]; in nested == nested"++case_attrset_nested_bottom_diverges =+  assertNixEvalThrows+    "let nested = { y = (let x = x; in x); }; in nested == nested"++case_list_list_nested_bottom_equal =+  constantEqualText+    "true"+    "let nested = [[(let x = x; in x)]]; in nested == nested"++case_list_attrset_nested_bottom_equal =+  constantEqualText+    "true"+    "let nested = [{ y = (let x = x; in x); }]; in nested == nested"++case_list_function_nested_bottom_equal =+  constantEqualText+    "true"+    "let nested = [(_: let x = x; in x)]; in nested == nested"++case_attrset_list_nested_bottom_equal =+  constantEqualText+    "true"+    "let nested = { y = [(let x = x; in x)];}; in nested == nested"++case_attrset_attrset_nested_bottom_equal =+  constantEqualText+    "true"+    "let nested = { y = { y = (let x = x; in x); }; }; in nested == nested"++case_attrset_function_nested_bottom_equal =+  constantEqualText+    "true"+    "let nested = { y = _: (let x = x; in x); }; in nested == nested"++case_if_follow_by_with = +  constantEqualText+    "1"+    "let x = { a = true; b = 2; }; in if with x; a then 1 else 2"++-- Regression test for #527++case_add_string_thunk_left =+  constantEqualText+    [text|+      "cygwin"+    |]+    [text|+      builtins.head ["cyg"] + "win"+    |]++case_add_string_thunk_right =+  constantEqualText+    [text|+      "cygwin"+    |]+    [text|+      "cyg" + builtins.head ["win"]+    |]++case_add_int_thunk_left =+  constantEqualText+    "3"+    "builtins.head [1] + 2"++case_add_int_thunk_right =+  constantEqualText+    "3"+    "1 + builtins.head [2]"++case_concat_thunk_left =+  constantEqualText+    "[1 2 3]"+    "builtins.tail [0 1 2] ++ [3]"++case_concat_thunk_rigth =+  constantEqualText+    "[1 2 3]"+    "[1] ++ builtins.tail [1 2 3]"++---------------------------------------------------------------------------------+ tests :: TestTree tests = $testGroupGenerator -genEvalCompareTests = do-    files <- filter ((==".nix") . takeExtension) <$> D.listDirectory testDir-    return $ testGroup "Eval comparison tests" $ map mkTestCase files-  where-    testDir = "tests/eval-compare"-    mkTestCase f = testCase f $ assertEvalFileMatchesNix (testDir </> f)+genEvalCompareTests :: IO TestTree+genEvalCompareTests =+  do+    files <- coerce D.listDirectory testDir -instance (Show r, Show (NValueF m r), Eq r) => Eq (NValueF m r) where-    NVConstantF x == NVConstantF y = x == y-    NVStrF x _ == NVStrF y _ = x == y-    NVListF x == NVListF y = and (zipWith (==) x y)-    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+    let+      unmaskedFiles :: [Path]+      unmaskedFiles = filter ((== ".nix") . takeExtension) files +      testFiles :: [Path]+      testFiles = unmaskedFiles \\ maskedFiles++    pure $ testGroup "Eval comparison tests" $ fmap (mkTestCase testDir) testFiles+  where+    mkTestCase :: Path -> Path -> TestTree+    mkTestCase dir f = testCase (coerce f :: TestName) $ assertEvalFileMatchesNix $ dir </> f+ constantEqual :: NExprLoc -> NExprLoc -> Assertion-constantEqual a b = do-    time <- liftIO getCurrentTime+constantEqual expected actual =+  do+    time <- getCurrentTime     let opts = defaultOptions time     -- putStrLn =<< lint (stripAnnotation a)-    a' <- runLazyM opts $ normalForm =<< nixEvalExprLoc Nothing a-    -- putStrLn =<< lint (stripAnnotation b)-    b' <- runLazyM opts $ normalForm =<< nixEvalExprLoc Nothing b-    assertEqual "" a' b'+    (eq, expectedNF, actualNF) <-+      runWithBasicEffectsIO opts $+        do+          expectedNF <- getNormForm expected+          actualNF <- getNormForm actual+          eq <- valueEqM expectedNF actualNF+          pure (eq, expectedNF, actualNF)+    let+      message =+        "Inequal normal forms:\n"+        <> "Expected: " <> printNix expectedNF <> "\n"+        <>  "Actual:   " <> printNix actualNF+    assertBool (toString message) eq+ where+  getNormForm = normalForm <=< nixEvalExprLoc mempty  constantEqualText' :: Text -> Text -> Assertion-constantEqualText' a b = do-  let Success a' = parseNixTextLoc a-      Success b' = parseNixTextLoc b-  constantEqual a' b'+constantEqualText' expected actual =+  do+    let (Right expected', Right actual') = both parseNixTextLoc (expected, actual)+    constantEqual expected' actual'  constantEqualText :: Text -> Text -> Assertion-constantEqualText a b = do-  constantEqualText' a b-  mres <- liftIO $ lookupEnv "MATCHING_TESTS"-  when (isJust mres) $-      assertEvalMatchesNix b+constantEqualText expected actual =+  do+    constantEqualText' expected actual+    mres <- liftIO $ on (<|>) lookupEnv "ALL_TESTS" "MATCHING_TESTS"+    whenJust (const $ assertEvalTextMatchesNix actual) mres  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+assertNixEvalThrows a =+  do+    time <- getCurrentTime+    let+      opts = defaultOptions time+      Right a' = parseNixTextLoc a+    errored <-+      catch+        (False <$+          runWithBasicEffectsIO+            opts+            (normalForm =<< nixEvalExprLoc mempty a')+        )+        (\(_ :: NixException) -> pure True)+    when (not errored) $ assertFailure "Did not catch nix exception"++sameFreeVars :: Text -> [VarName] -> Assertion+sameFreeVars a xs =+  do+    let+      Right a' = parseNixText a+      free' = getFreeVars a'+    assertEqual mempty (S.fromList xs) free'++maskedFiles :: [Path]+maskedFiles = mempty++testDir :: Path+testDir = "tests/eval-compare"
tests/Main.hs view
@@ -1,86 +1,95 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}+{-# language QuasiQuotes #-}  module Main where -import           Control.DeepSeq+import           Nix.Prelude+import           Relude (force)+import           Relude.Unsafe (read) import qualified Control.Exception as Exc-import           Control.Applicative ((<|>))-import           Control.Monad-import           Control.Monad.IO.Class+import           GHC.Err (errorWithoutStackTrace) import           Data.Fix-import           Data.List (isInfixOf)-import           Data.Maybe-import           Data.String.Interpolate.IsString-import           Data.Text (unpack)+import           Data.List (isSuffixOf, lookup)+import qualified Data.String as String import           Data.Time import qualified EvalTests+import           NeatInterpolation (text) import qualified Nix-import           Nix.Exec import           Nix.Expr.Types+import           Nix.String import           Nix.Options import           Nix.Parser+import           Nix.Standard import           Nix.Value import qualified NixLanguageTests import qualified ParserTests import qualified PrettyTests import qualified ReduceExprTests--- import qualified PrettyParseTests+import qualified PrettyParseTests import           System.Directory-import           System.Environment-import           System.FilePath.Glob-import           System.Posix.Files-import           System.Process+import           System.Environment (setEnv)+import           System.FilePath.Glob (compile, globDir1)+import           System.PosixCompat.Files import           Test.Tasty import           Test.Tasty.HUnit -cabalCorrectlyGenerated :: Assertion-cabalCorrectlyGenerated = do-  output <- readCreateProcess (shell "hpack") ""-  when ("modified manually" `isInfixOf` output) $-    errorWithoutStackTrace-      "Edit package.yaml and re-generate hnix.cabal by running \"hpack\""- ensureLangTestsPresent :: Assertion ensureLangTestsPresent = do   exist <- fileExist "data/nix/tests/local.mk"-  unless exist $-    errorWithoutStackTrace $ unlines+  when (not exist) $+    errorWithoutStackTrace $ String.unlines       [ "Directory data/nix does not have any files."       , "Did you forget to run"-          ++ " \"git submodule update --init --recursive\"?" ]+          <> " \"git submodule update --init --recursive\"?" ]  ensureNixpkgsCanParse :: Assertion ensureNixpkgsCanParse =   consider "default.nix" (parseNixFile "default.nix") $ \case-    Fix (NAbs (ParamSet params _ _) _) -> do-      let rev    = getString "rev" params-          sha256 = getString "sha256" params-      consider "fetchTarball expression" (pure $ parseNixTextLoc [i|+    Fix (NAbs (ParamSet _ _ pset) _) -> do+      let rev    = getString "rev" pset+          sha256 = getString "sha256" pset+      consider "fetchTarball expression" (pure $ parseNixTextLoc [text|         builtins.fetchTarball {-          url    = "https://github.com/NixOS/nixpkgs/archive/#{rev}.tar.gz";-          sha256 = "#{sha256}";+          url    = "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz";+          sha256 = "${sha256}";         }|]) $ \expr -> do-        NVStr dir _ <- do-            time <- liftIO getCurrentTime-            runLazyM (defaultOptions time) $ Nix.nixEvalExprLoc Nothing expr-        files <- globDir1 (compile "**/*.nix") (unpack dir)-        forM_ files $ \file ->-          -- Parse and deepseq the resulting expression tree, to ensure the-          -- parser is fully executed.-          consider file (parseNixFileLoc file) $ Exc.evaluate . force-    v -> error $ "Unexpected parse from default.nix: " ++ show v+        NVStr ns <- do+          time <- getCurrentTime+          runWithBasicEffectsIO (defaultOptions time) $+            Nix.nixEvalExprLoc mempty expr+        let dir = toString $ ignoreContext ns+        exists <- fileExist dir+        when (not exists) $+          errorWithoutStackTrace $+            "Directory " <> show dir <> " does not exist"+        files <- globDir1 (compile "**/*.nix") dir+        handlePresence+          (errorWithoutStackTrace $+            "Directory " <> show dir <> " does not have any files")+          (traverse_+            (\ path ->+              let notEndsIn suffix = not $ isSuffixOf suffix path in+              when+                (on (&&) notEndsIn "azure-cli/default.nix" "os-specific/linux/udisks/2-default.nix")+                $ -- Parse and deepseq the resulting expression tree, to ensure the+                  -- parser is fully executed.+                  mempty <$ consider (coerce path) (parseNixFileLoc (coerce path)) $ Exc.evaluate . force+            )+          )+          files+    v -> fail $ "Unexpected parse from default.nix: " <> show v  where-  getExpr   k m = let Just (Just r) = lookup k m in r+  getExpr   k m =+    let Just r = join $ lookup k m in+    r   getString k m =-      let Fix (NStr (DoubleQuoted [Plain str])) = getExpr k m in str+    let Fix (NStr (DoubleQuoted [Plain str])) = getExpr k m in+    str -  consider path action k = action >>= \case-    Failure err -> errorWithoutStackTrace $-      "Parsing " ++ path ++ " failed: " ++ show err-    Success expr -> k expr+  consider path action k =+    either+      (\ err -> errorWithoutStackTrace $ "Parsing " <> coerce @Path path <> " failed: " <> show err)+      k+      =<< action  main :: IO () main = do@@ -88,24 +97,21 @@   evalComparisonTests <- EvalTests.genEvalCompareTests   let allOrLookup var = lookupEnv "ALL_TESTS" <|> lookupEnv var   nixpkgsTestsEnv     <- allOrLookup "NIXPKGS_TESTS"-  -- prettyTestsEnv      <- lookupEnv "PRETTY_TESTS"-  hpackTestsEnv       <- allOrLookup "HPACK_TESTS"+  prettyTestsEnv      <- lookupEnv "PRETTY_TESTS"    pwd <- getCurrentDirectory-  setEnv "NIX_REMOTE" ("local?root=" ++ pwd ++ "/")+  setEnv "NIX_REMOTE" $ pwd <> "/real-store"+  setEnv "NIX_DATA_DIR" $ pwd <> "/data"    defaultMain $ testGroup "hnix" $-    [ testCase "hnix.cabal correctly generated" cabalCorrectlyGenerated-      | isJust hpackTestsEnv ] ++     [ ParserTests.tests     , EvalTests.tests     , PrettyTests.tests-    , ReduceExprTests.tests] ++-    -- [ PrettyParseTests.tests-    --     (fromIntegral (read (fromMaybe "0" prettyTestsEnv) :: Int)) ] ++-    [ evalComparisonTests ] ++-    [ testCase "Nix language tests present" ensureLangTestsPresent-    , nixLanguageTests ] +++    , ReduceExprTests.tests+    , PrettyParseTests.tests $ fromIntegral $ read @Int $ fromMaybe "0" prettyTestsEnv+    , evalComparisonTests+    , testCase "Nix language tests present" ensureLangTestsPresent+    , nixLanguageTests ] <>     [ testCase "Nixpkgs parses without errors" ensureNixpkgsCanParse-      | isJust nixpkgsTestsEnv ]-+      | isJust nixpkgsTestsEnv+    ]
tests/NixLanguageTests.hs view
@@ -1,20 +1,15 @@-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}- module NixLanguageTests (genTests) where -import           Control.Arrow ((&&&))+import           Nix.Prelude import           Control.Exception-import           Control.Monad-import           Control.Monad.IO.Class+import           GHC.Err                        ( errorWithoutStackTrace ) import           Control.Monad.ST-import           Data.List (delete, sort)-import           Data.List.Split (splitOn)-import           Data.Map (Map)-import qualified Data.Map as Map-import qualified Data.Text as Text-import qualified Data.Text.IO as Text+import           Data.List                      ( delete )+import           Data.List.Split                ( splitOn )+import qualified Data.Map                      as Map+import qualified Data.Set                      as Set+import qualified Data.String                   as String+import qualified Data.Text                     as Text import           Data.Time import           GHC.Exts import           Nix.Lint@@ -22,12 +17,13 @@ import           Nix.Options.Parser import           Nix.Parser import           Nix.Pretty-import           Nix.Utils+import           Nix.String import           Nix.XML-import qualified Options.Applicative as Opts-import           System.Environment-import           System.FilePath-import           System.FilePath.Glob (compile, globDir1)+import qualified Options.Applicative           as Opts+import           System.Environment             ( setEnv )+import           System.FilePath.Glob           ( compile+                                                , globDir1+                                                ) import           Test.Tasty import           Test.Tasty.HUnit import           TestCommon@@ -53,107 +49,187 @@ -}  groupBy :: Ord k => (v -> k) -> [v] -> Map k [v]-groupBy key = Map.fromListWith (++) . map (key &&& pure)+groupBy key = Map.fromListWith (<>) . fmap (key &&& pure) +-- | New tests, which have never yet passed.  Once any of these is passing,+-- please remove it from this list.  Do not add tests to this list if they have+-- previously passed.+newFailingTests :: Set String+newFailingTests = Set.fromList+  [ "eval-okay-fromTOML"+  , "eval-okay-zipAttrsWith"+  , "eval-okay-tojson"+  , "eval-okay-search-path"+  , "eval-okay-sort"+  , "eval-okay-path-antiquotation"+  , "eval-okay-getattrpos-functionargs"+  , "eval-okay-attrs6"+  ]++-- | Upstream tests that test cases that HNix disaded as a misfeature that is used so rarely+-- that it more effective to fix it & lint it out of existance.+deprecatedRareNixQuirkTests :: Set String+deprecatedRareNixQuirkTests = Set.fromList+  [ -- A rare quirk of Nix that is proper to fix&enforce then to support (see git commit history)+    "eval-okay-strings-as-attrs-names"+    -- Nix upstream removed this test altogether+  , "eval-okay-hash"+  ]+ genTests :: IO TestTree-genTests = do-  testFiles <- sort-        -- jww (2018-05-07): Temporarily disable this test until #128 is fixed.-      . filter ((/= "eval-okay-path") . takeBaseName)-      . filter ((/= ".xml") . takeExtension)-      <$> globDir1 (compile "*-*-*.*") "data/nix/tests/lang"-  let testsByName = groupBy (takeFileName . dropExtensions) testFiles-  let testsByType = groupBy testType (Map.toList testsByName)-  let testGroups  = map mkTestGroup (Map.toList testsByType)-  return $ localOption (mkTimeout 2000000)-         $ testGroup "Nix (upstream) language tests" testGroups-  where-    testType (fullpath, _files) =-        take 2 $ splitOn "-" $ takeFileName fullpath-    mkTestGroup (kind, tests) =-        testGroup (unwords kind) $ map (mkTestCase kind) tests-    mkTestCase kind (basename, files) =-        testCase (takeFileName basename) $ do+genTests =+  do+    testFiles <- getTestFiles+    let+      testsGroupedByName :: Map Path [Path]+      testsGroupedByName = groupBy (takeFileName . dropExtensions) testFiles++      testsGroupedByTypeThenName :: Map [String] [(Path, [Path])]+      testsGroupedByTypeThenName = groupBy testType $ Map.toList testsGroupedByName++      testTree :: [TestTree]+      testTree = mkTestGroup <$> Map.toList testsGroupedByTypeThenName++    pure $+      localOption+        (mkTimeout 2000000)+        $ testGroup+            "Nix (upstream) language tests"+            testTree+ where++  getTestFiles :: IO [Path]+  getTestFiles = sortTestFiles <$> collectTestFiles+   where+    collectTestFiles :: IO [Path]+    collectTestFiles = coerce (globDir1 (compile "*-*-*.*") nixTestDir)++    sortTestFiles :: [Path] -> [Path]+    sortTestFiles =+      sort+        -- Disabling the not yet done tests cases.+        . filter withoutDisabledTests+        . filter withoutXml+     where+      withoutDisabledTests :: Path -> Bool+      withoutDisabledTests = (`Set.notMember` (newFailingTests `Set.union` deprecatedRareNixQuirkTests)) . takeBaseName++      withoutXml :: Path -> Bool+      withoutXml = (/= ".xml") . takeExtension++  testType :: (Path, b) -> [String]+  testType (fullpath, _files) = coerce (take 2 . splitOn "-") $ takeFileName fullpath++  mkTestGroup :: ([String], [(Path, [Path])]) -> TestTree+  mkTestGroup (tType, tests) =+    testGroup (String.unwords tType) $ mkTestCase <$> tests+   where+    mkTestCase :: (Path, [Path]) -> TestTree+    mkTestCase (basename, files) =+      testCase+        (coerce $ takeFileName basename)+        $ do             time <- liftIO getCurrentTime             let opts = defaultOptions time-            case kind of-                ["parse", "okay"] -> assertParse opts $ the files-                ["parse", "fail"] -> assertParseFail opts $ the files-                ["eval", "okay"]  -> assertEval opts files-                ["eval", "fail"]  -> assertEvalFail $ the files-                _ -> error $ "Unexpected: " ++ show kind+            case tType of+              ["parse", "okay"] -> assertParse opts $ the files+              ["parse", "fail"] -> assertParseFail opts $ the files+              ["eval" , "okay"] -> assertEval opts files+              ["eval" , "fail"] -> assertEvalFail $ the files+              _                 -> fail $ "Unexpected: " <> show tType -assertParse :: Options -> FilePath -> Assertion-assertParse _opts file = parseNixFileLoc file >>= \case-  Success _expr -> return () -- pure $! runST $ void $ lint opts expr-  Failure err  ->-      assertFailure $ "Failed to parse " ++ file ++ ":\n" ++ show err -assertParseFail :: Options -> FilePath -> Assertion-assertParseFail opts file = do-    eres <- parseNixFileLoc file-    catch (case eres of-               Success expr -> do-                   _ <- pure $! runST $ void $ lint opts expr-                   assertFailure $ "Unexpected success parsing `"-                       ++ file ++ ":\nParsed value: " ++ show expr-               Failure _ -> return ()) $ \(_ :: SomeException) ->-        return ()+assertParse :: Options -> Path -> Assertion+assertParse _opts file =+  either+    (\ err -> assertFailure $ "Failed to parse " <> coerce file <> ":\n" <> show err)+    (const stub)  -- pure $! runST $ void $ lint opts expr+    =<< parseNixFileLoc file -assertLangOk :: Options -> FilePath -> Assertion-assertLangOk opts file = do-  actual <- printNix <$> hnixEvalFile opts (file ++ ".nix")-  expected <- Text.readFile $ file ++ ".exp"-  assertEqual "" expected $ Text.pack (actual ++ "\n")+assertParseFail :: Options -> Path -> Assertion+assertParseFail opts file =+  (`catch` \(_ :: SomeException) -> stub) $+    either+      (const stub)+      (\ expr ->+        do+          _ <- pure $! runST $ void $ lint opts expr+          assertFailure $ "Unexpected success parsing `" <> coerce file <> ":\nParsed value: " <> show expr+      )+      =<< parseNixFileLoc file -assertLangOkXml :: Options -> FilePath -> Assertion-assertLangOkXml opts file = do-  actual <- toXML <$> hnixEvalFile opts (file ++ ".nix")-  expected <- Text.readFile $ file ++ ".exp.xml"-  assertEqual "" expected $ Text.pack actual+assertLangOk :: Options -> Path -> Assertion+assertLangOk opts fileBaseName =+  do+    actual   <- printNix <$> hnixEvalFile opts (addNixExt fileBaseName)+    expected <- read fileBaseName ".exp"+    assertEqual mempty expected (actual <> "\n") -assertEval :: Options -> [FilePath] -> Assertion-assertEval _opts files = do+assertLangOkXml :: Options -> Path -> Assertion+assertLangOkXml opts fileBaseName =+  do+    actual <- ignoreContext . toXML <$> hnixEvalFile opts (addNixExt fileBaseName)+    expected <- read fileBaseName ".exp.xml"+    assertEqual mempty expected actual++assertEval :: Options -> [Path] -> Assertion+assertEval _opts files =+  do     time <- liftIO getCurrentTime     let opts = defaultOptions time-    case delete ".nix" $ sort $ map takeExtensions files of-        [] -> () <$ hnixEvalFile opts (name ++ ".nix")-        [".exp"] -> assertLangOk opts name-        [".exp.xml"] -> assertLangOkXml opts name-        [".exp.disabled"] -> return ()-        [".exp-disabled"] -> return ()-        [".exp", ".flags"] -> do-            liftIO $ unsetEnv "NIX_PATH"-            flags <- Text.readFile (name ++ ".flags")-            let flags' | Text.last flags == '\n' = Text.init flags-                       | otherwise = flags-            case Opts.execParserPure Opts.defaultPrefs (nixOptionsInfo time)-                     (fixup (map Text.unpack (Text.splitOn " " flags'))) of-                Opts.Failure err -> errorWithoutStackTrace $-                    "Error parsing flags from " ++ name ++ ".flags: "-                        ++ show err-                Opts.Success opts' ->-                    assertLangOk-                        (opts' { include = include opts' ++-                                   [ "nix=../../../../data/nix/corepkgs"-                                   , "lang/dir4"-                                   , "lang/dir5" ] })-                        name-                Opts.CompletionInvoked _ -> error "unused"-        _ -> assertFailure $ "Unknown test type " ++ show files-  where-    name = "data/nix/tests/lang/"-        ++ the (map (takeFileName . dropExtensions) files)+    case delete ".nix" $ sort $ fromString @Text . takeExtensions <$> files of+      []                  -> void $ hnixEvalFile opts $ addNixExt name+      [".exp"          ]  -> assertLangOk    opts name+      [".exp.xml"      ]  -> assertLangOkXml opts name+      [".exp.disabled" ]  -> stub+      [".exp-disabled" ]  -> stub+      [".exp", ".flags"]  ->+        do+          liftIO $ setEnv "NIX_PATH" "lang/dir4:lang/dir5"+          flags <- read name ".flags"+          let+            flags' :: Text+            flags' =+              bool+                id+                Text.init+                (Text.last flags == '\n')+                flags+          case runParserGetResult time flags' of+            Opts.Failure           err   -> errorWithoutStackTrace $ "Error parsing flags from " <> coerce name <> ".flags: " <> show err+            Opts.CompletionInvoked _     -> fail "unused"+            Opts.Success           opts' -> assertLangOk opts' name+      _ -> assertFailure $ "Unknown test type " <> show files+ where+  runParserGetResult :: UTCTime -> Text -> Opts.ParserResult Options+  runParserGetResult time flags' =+    Opts.execParserPure+      Opts.defaultPrefs+      (nixOptionsInfo time)+      (fmap toString $ fixup $ Text.splitOn " " flags') -    fixup ("--arg":x:y:rest) = "--arg":(x ++ "=" ++ y):fixup rest-    fixup ("--argstr":x:y:rest) = "--argstr":(x ++ "=" ++ y):fixup rest-    fixup (x:rest) = x:fixup rest-    fixup [] = []+  name :: Path+  name = coerce nixTestDir <> the (takeFileName . dropExtensions <$> files) -assertEvalFail :: FilePath -> Assertion-assertEvalFail file = catch ?? (\(_ :: SomeException) -> return ()) $ do-  time <- liftIO getCurrentTime-  evalResult <- printNix <$> hnixEvalFile (defaultOptions time) file-  evalResult `seq` assertFailure $-      file ++ " should not evaluate.\nThe evaluation result was `"-           ++ evalResult ++ "`."+  fixup :: [Text] -> [Text]+  fixup ("--arg"    : x : y : rest) = "--arg"    : (x <> "=" <> y) : fixup rest+  fixup ("--argstr" : x : y : rest) = "--argstr" : (x <> "=" <> y) : fixup rest+  fixup (x                  : rest) =                          x  : fixup rest+  fixup []                          = mempty++assertEvalFail :: Path -> Assertion+assertEvalFail file =+  (`catch` (\(_ :: SomeException) -> stub)) $+  do+    time       <- liftIO getCurrentTime+    evalResult <- printNix <$> hnixEvalFile (defaultOptions time) file+    evalResult `seq` assertFailure $ "File: ''" <> coerce file <> "'' should not evaluate.\nThe evaluation result was `" <> toString evalResult <> "`."++nixTestDir :: FilePath+nixTestDir = "data/nix/tests/lang/"++addNixExt :: Path -> Path+addNixExt path = addExtension path ".nix"++read :: Path -> String -> IO Text+read path ext = readFile $ addExtension path ext
tests/ParserTests.hs view
@@ -1,399 +1,826 @@-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes #-}--{-# OPTIONS_GHC -fno-warn-name-shadowing #-}-{-# OPTIONS_GHC -Wno-missing-signatures -Wno-orphans #-}--module ParserTests (tests) where--import Data.Fix-import Data.List.NonEmpty (NonEmpty(..))-import Data.Semigroup-import Data.String.Interpolate.IsString-import Data.Text (Text, unpack, pack)-import Nix.Atoms-import Nix.Expr-import Nix.Parser-import Nix.Pretty-import Test.Tasty-import Test.Tasty.HUnit-import Test.Tasty.TH-import Text.PrettyPrint.ANSI.Leijen hiding ((<$>), (<>))--case_constant_int = assertParseText "234" $ mkInt 234--case_constant_bool = do-  assertParseText "true" $ mkBool True-  assertParseText "false" $ mkBool False--case_constant_bool_respects_attributes = do-  assertParseText "true-foo"  $ mkSym "true-foo"-  assertParseText "false-bar" $ mkSym "false-bar"--case_constant_path = do-  assertParseText "./." $ mkPath False "./."-  assertParseText "./+-_/cdef/09ad+-" $ mkPath False "./+-_/cdef/09ad+-"-  assertParseText "/abc" $ mkPath False "/abc"-  assertParseText "../abc" $ mkPath False "../abc"-  assertParseText "<abc>" $ mkPath True "abc"-  assertParseText "<../cdef>" $ mkPath True "../cdef"-  assertParseText "a//b" $ mkOper2 NUpdate (mkSym "a") (mkSym "b")-  assertParseText "rec+def/cdef" $ mkPath False "rec+def/cdef"-  assertParseText "a/b//c/def//<g> < def/d" $ mkOper2 NLt-    (mkOper2 NUpdate (mkPath False "a/b") $ mkOper2 NUpdate-      (mkPath False "c/def") (mkPath True "g"))-    (mkPath False "def/d")-  assertParseText "a'b/c" $ Fix $ NBinary NApp (mkSym "a'b") (mkPath False "/c")-  assertParseText "a/b" $ mkPath False "a/b"-  assertParseText "4/2" $ mkPath False "4/2"-  assertParseFail "."-  assertParseFail ".."-  assertParseFail "/"-  assertParseFail "a/"-  assertParseFail "a/def/"-  assertParseFail "~"-  assertParseFail "~/"-  assertParseText "~/a" $ mkPath False "~/a"-  assertParseText "~/a/b" $ mkPath False "~/a/b"--case_constant_uri = do-  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"-  assertParseFail ".:adasd"-  assertParseFail "+:acdcd"--case_simple_set = do-  assertParseText "{ a = 23; b = 4; }" $ Fix $ NSet-    [ 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) nullPos-    , Inherit Nothing (StaticKey <$> ["a", "b"]) nullPos-    ]-  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")) (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) nullPos-  , NamedVar (mkSelector "b") (mkSym "a") nullPos-  ]--case_set_complex_keynames = do-  assertParseText "{ \"\" = null; }" $ Fix $ NSet-    [ NamedVar (DynamicKey (Plain (DoubleQuoted [])) :| []) mkNull nullPos ]-  assertParseText "{ a.b = 3; a.c = 4; }" $ Fix $ NSet-    [ 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) nullPos ]-  assertParseText "{ \"a${let a = \"b\"; in a}c\".e = 4; }" $ Fix $ NSet-    [ NamedVar (DynamicKey (Plain str) :| [StaticKey "e"]) (mkInt 4) nullPos ]- where-  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-  [ Inherit (Just $ Fix $ NSet [NamedVar (mkSelector "a") (mkInt 3) nullPos]) [] nullPos-  ]--case_inherit_selector = do-  assertParseText "{ inherit \"a\"; }" $ Fix $ NSet-    [Inherit Nothing [DynamicKey (Plain (DoubleQuoted [Plain "a"]))] nullPos]-  assertParseFail "{ inherit a.x; }"--case_int_list = assertParseText "[1 2 3]" $ Fix $ NList-  [ mkInt i | i <- [1,2,3] ]--case_int_null_list = assertParseText "[1 2 3 null 4]" $ Fix (NList (map (Fix . NConstant) [NInt 1, NInt 2, NInt 3, NNull, NInt 4]))--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) 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))-    ]-  assertParseFail "[if true then null else null]"-  assertParseFail "[a ? b]"-  assertParseFail "[a : a]"-  assertParseFail "[${\"test\")]"--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") (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:"--case_lambda_pattern = do-  assertParseText "{b, c ? 1}: b" $-    Fix $ NAbs (fixed args Nothing) (mkSym "b")-  assertParseText "{ b ? x: x  }: b" $-    Fix $ NAbs (fixed args2 Nothing) (mkSym "b")-  assertParseText "a@{b,c ? 1}: b" $-    Fix $ NAbs (fixed args (Just "a")) (mkSym "b")-  assertParseText "{b,c?1}@a: c" $-    Fix $ NAbs (fixed args (Just "a")) (mkSym "c")-  assertParseText "{b,c?1,...}@a: c" $-    Fix $ NAbs (variadic vargs (Just "a")) (mkSym "c")-  assertParseText "{...}: 1" $-    Fix $ NAbs (variadic mempty Nothing) (mkInt 1)-  assertParseFail "a@b: a"-  assertParseFail "{a}@{b}: a"- where-  fixed args = ParamSet args False-  variadic args = ParamSet args True-  args = [("b", Nothing), ("c", Just $ mkInt 1)]-  vargs = [("b", Nothing), ("c", Just $ mkInt 1)]-  args2 = [("b", Just lam)]-  lam = Fix $ NAbs (Param "x") (mkSym "x")--case_lambda_app_int = assertParseText "(a: a) 3" $ Fix (NBinary NApp lam int) where-  int = mkInt 3-  lam = Fix (NAbs (Param "a") asym)-  asym = mkSym "a"--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) 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) nullPos]--case_nested_let = do-  assertParseText "let a = 4; in let b = 5; in a" $ Fix $ NLet-    [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 nullPos-    , Inherit (Just $ mkSym "b") [StaticKey "c"] nullPos ]-    (mkSym "c")-  assertParseFail "let inherit (b) c in c"--case_if = do-  assertParseText "if true then true else false" $-      Fix $ NIf (mkBool True) (mkBool True) (mkBool False)-  assertParseFail "if true then false"-  assertParseFail "else"-  assertParseFail "if true then false else"-  assertParseFail "if true then false else false else"-  assertParseFail "1 + 2 then"--case_identifier_special_chars = do-  assertParseText "_a" $ mkSym "_a"-  assertParseText "a_b" $ mkSym "a_b"-  assertParseText "a'b" $ mkSym "a'b"-  assertParseText "a''b" $ mkSym "a''b"-  assertParseText "a-b" $ mkSym "a-b"-  assertParseText "a--b" $ mkSym "a--b"-  assertParseText "a12a" $ mkSym "a12a"-  assertParseFail ".a"-  assertParseFail "'a"--case_identifier_keyword_prefix = do-  assertParseText "true-name" $ mkSym "true-name"-  assertParseText "trueName" $ mkSym "trueName"-  assertParseText "null-name" $ mkSym "null-name"-  assertParseText "nullName" $ mkSym "nullName"-  assertParseText "[ null-name ]" $ mkList [ mkSym "null-name" ]--makeTextParseTest str = assertParseText ("\"" <> str <> "\"") $ mkStr str--case_simple_string = mapM_ makeTextParseTest ["abcdef", "a", "A", "   a a  ", ""]--case_string_dollar = mapM_ makeTextParseTest ["a$b", "a$$b", "$cdef", "gh$i"]--case_string_escape = do-  assertParseText "\"\\$\\n\\t\\r\\\\\"" $ mkStr "$\n\t\r\\"-  assertParseText "\" \\\" \\' \"" $ mkStr " \" ' "--case_string_antiquote = do-  assertParseText "\"abc${  if true then \"def\" else \"abc\"  } g\"" $-    Fix $ NStr $ DoubleQuoted-      [ Plain "abc"-      , Antiquoted $ Fix $ NIf (mkBool True) (mkStr "def") (mkStr "abc")-      , Plain " g"-      ]-  assertParseText "\"\\${a}\"" $ mkStr "${a}"-  assertParseFail "\"a"-  assertParseFail "${true}"-  assertParseFail "\"${true\""--case_select = do-  assertParseText "a .  e .di. f" $ Fix $ NSelect (mkSym "a")-    (StaticKey "e" :| [StaticKey "di", StaticKey "f"])-    Nothing-  assertParseText "a.e . d    or null" $ Fix $ NSelect (mkSym "a")-    (StaticKey "e" :| [StaticKey "d"])-    (Just mkNull)-  assertParseText "{}.\"\"or null" $ Fix $ NSelect (Fix (NSet []))-    (DynamicKey (Plain (DoubleQuoted [])) :| []) (Just mkNull)-  assertParseText "{ a = [1]; }.a or [2] ++ [3]" $ Fix $ NBinary NConcat-      (Fix (NSelect-                (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))]))--case_select_path = do-  assertParseText "f ./." $ Fix $ NBinary NApp (mkSym "f") (mkPath False "./.")-  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 (DoubleQuoted [])) :| []) Nothing)-    (mkPath False "./def")- where select = Fix $ NSelect (mkSym "f") (mkSelector "b") Nothing--case_fun_app = do-  assertParseText "f a b" $ Fix $ NBinary NApp (Fix $ NBinary NApp (mkSym "f") (mkSym "a")) (mkSym "b")-  assertParseText "f a.x or null" $ Fix $ NBinary NApp (mkSym "f") $ Fix $-    NSelect (mkSym "a") (mkSelector "x") (Just mkNull)-  assertParseFail "f if true then null else null"--case_indented_string = do-  assertParseText "''a''" $ mkIndentedStr 0 "a"-  assertParseText "''\n  foo\n  bar''" $ mkIndentedStr 2 "foo\nbar"-  assertParseText "''        ''" $ mkIndentedStr 0 ""-  assertParseText "'''''''" $ mkIndentedStr 0 "''"-  assertParseText "''   ${null}\n   a${null}''" $ Fix $ NStr $ Indented 3-    [ Antiquoted mkNull-    , Plain "\na"-    , Antiquoted mkNull-    ]-  assertParseFail "'''''"-  assertParseFail "''   '"--case_indented_string_escape = assertParseText-  "'' ''\\n ''\\t ''\\\\ ''${ \\ \\n ' ''' ''" $-  mkIndentedStr 1 "\n \t \\ ${ \\ \\n ' '' "--case_operator_fun_app = do-  assertParseText "a ++ b" $ mkOper2 NConcat (mkSym "a") (mkSym "b")-  assertParseText "a ++ f b" $ mkOper2 NConcat (mkSym "a") $ Fix $ NBinary NApp-    (mkSym "f") (mkSym "b")--case_operators = do-  assertParseText "1 + 2 - 3" $ mkOper2 NMinus-    (mkOper2 NPlus (mkInt 1) (mkInt 2)) (mkInt 3)-  assertParseFail "1 + if true then 1 else 2"-  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) 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")) $-    mkSym "c"-  assertParseText "foo<bar" $ mkOper2 NLt (mkSym "foo") (mkSym "bar")-  assertParseFail "+ 3"-  assertParseFail "foo +"--case_comments = do-  Success expected <- parseNixFile "data/let.nix"-  assertParseFile "let-comments-multiline.nix" expected-  assertParseFile "let-comments.nix" expected--case_select_or_precedence =-    assertParsePrint [i|let-  matchDef = def:   matcher:-                      v:   let-                             case = builtins.head (builtins.attrNames v);-                           in (matcher.case or def case) (v.case);-in null|] [i|let-  matchDef = def:-    matcher:-      v:-        let-          case = builtins.head (builtins.attrNames v);-        in (matcher.case or def) case (v.case);-in null|]--case_select_or_precedence2 =-    assertParsePrint [i|let-  matchDef = def:   matcher:-                      v:   let-                             case = builtins.head (builtins.attrNames v);-                           in (matcher.case or null.foo) (v.case);-in null|] [i|let-  matchDef = def:-    matcher:-      v:-        let-          case = builtins.head (builtins.attrNames v);-        in (matcher.case or null).foo (v.case);-in null|]--tests :: TestTree-tests = $testGroupGenerator------------------------------------------------------------------------------------assertParseText :: Text -> NExpr -> Assertion-assertParseText str expected = case parseNixText str of-  Success actual ->-      assertEqual ("When parsing " ++ unpack str)-          (stripPositionInfo expected) (stripPositionInfo actual)-  Failure err    ->-      assertFailure $ "Unexpected error parsing `" ++ unpack str ++ "':\n" ++ show err--assertParseFile :: FilePath -> NExpr -> Assertion-assertParseFile file expected = do-  res <- parseNixFile $ "data/" ++ file-  case res of-    Success actual -> assertEqual ("Parsing data file " ++ file)-          (stripPositionInfo expected) (stripPositionInfo actual)-    Failure err    ->-        assertFailure $ "Unexpected error parsing data file `"-            ++ file ++ "':\n" ++ show err--assertParseFail :: Text -> Assertion-assertParseFail str = case parseNixText str of-  Failure _ -> return ()-  Success r ->-      assertFailure $ "Unexpected success parsing `"-          ++ unpack str ++ ":\nParsed value: " ++ show r---- assertRoundTrip :: Text -> Assertion--- assertRoundTrip src = assertParsePrint src src--assertParsePrint :: Text -> Text -> Assertion-assertParsePrint src expect =-  let Success expr = parseNixTextLoc src-      result = displayS-             . renderPretty 0.4 80-             . prettyNix-             . stripAnnotation-             $ expr-  in assertEqual "" expect (pack (result ""))+{-# language QuasiQuotes #-}+{-# language TemplateHaskell #-}+{-# language RankNTypes #-}+{-# language ExtendedDefaultRules #-}++{-# options_ghc -fno-warn-name-shadowing #-}+{-# options_ghc -Wno-missing-signatures #-}+{-# options_ghc -Wno-type-defaults #-}+++module ParserTests (tests) where++import Nix.Prelude hiding (($<))+import Data.Fix+import NeatInterpolation (text)+import Nix.Atoms+import Nix.Expr+import Nix.Parser+import Nix.Pretty+import Prettyprinter+import Prettyprinter.Render.Text+import Test.Tasty+import Test.Tasty.HUnit+import Test.Tasty.TH+import Prettyprinter.Render.String (renderString)+import Prettyprinter.Util (reflow)++default (NixLang)++-- * Tests+++-- ** Literals++case_constant_int =+  checks+    ( mkInt 234+    , "234"+    )++case_constant_bool =+  checks+    ( mkBool True+    , "true"+    )+    ( mkBool False+    , "false"+    )++case_constant_bool_respects_attributes =+  invariantVals+    "true-foo"+    "false-bar"++case_constant_path_invariants =+  knownAs (staysInvariantUnder (mkRelPath . toString))+    "./."+    "./+-_/cdef/09ad+-"+    "/abc"+    "../abc"+    "~/a"+    "~/a/b"+    "a/b"+    "4/2"+    "rec+def/cdef"++case_constant_path =+  checks+    ( var "a'b" @@ mkRelPath "/c"+    , "a'b/c"+    )+    ( mkRelPath "a/b" $// mkRelPath "c/def" $// mkEnvPath "g" $<  mkRelPath "def/d"+    , "a/b//c/def//<g> < def/d"+    )+    ( mkEnvPath "abc"+    , "<abc>"+    )+    ( mkEnvPath "../cdef"+    , "<../cdef>"+    )+    ( var "a" $// var "b"+    , "a//b"+    )++case_constant_path_syntax_mistakes =+  mistakes+    "."+    ".."+    "/"+    "a/"+    "a/def/"+    "~"+    "~/"++case_constant_uri =+  knownAs (staysInvariantUnder mkStr)+    "a:a"+    "http://foo.bar"+    "a+de+.adA+-:%%%ads%5asdk&/"+    "rec+def:c"+    "f.foo:bar"+++case_constant_uri_syntax_mistakes =+  mistakes+    "http://foo${\"bar\"}"+    ":bcdef"+    "a%20:asda"+    ".:adasd"+    "+:acdcd"+++-- *** Special chars in vals++case_identifier_special_chars =+  invariantVals+    "_a"+    "a_b"+    "a'b"+    "a''b"+    "a-b"+    "a--b"+    "a12a"++case_identifier_special_chars_syntax_mistakes =+  mistakes+    ".a"+    "'a"++-- ** Sets++-- *** Non-recursive sets++case_simple_set =+  checks+    ( mkNonRecSet+        [ "a" $= mkInt 23+        , "b" $= mkInt  4+        ]+    , "{ a = 23; b = 4; }"+    )++case_simple_set_syntax_mistakes =+  mistakes+    "{ a = 23 }"++case_set_complex_keynames =+  checks+    ( mkNonRecSet $+        one (NamedVar (one (DynamicKey (Plain (DoubleQuoted mempty)))) mkNull nullPos)+    , "{ \"\" = null; }"+    )+    ( mkNonRecSet+        [ NamedVar (StaticKey "a" :| one (StaticKey "b")) (mkInt 3) nullPos+        , NamedVar (StaticKey "a" :| one (StaticKey "c")) (mkInt 4) nullPos+        ]+    , "{ a.b = 3; a.c = 4; }"+    )+    ( mkNonRecSet $+        one (NamedVar (one (DynamicKey (Antiquoted letExpr))) (mkInt 4) nullPos)+    , "{ ${let a = \"b\"; in a} = 4; }"+    )+    ( mkNonRecSet $+        one (NamedVar (DynamicKey (Plain str) :| one (StaticKey "e")) (mkInt 4) nullPos)+    , "{ \"a${let a = \"b\"; in a}c\".e = 4; }"+    )+ where+  letExpr = mkLets (one ("a" $= mkStr "b")) (var "a")+  str = DoubleQuoted [Plain "a", Antiquoted letExpr, Plain "c"]+++-- *** Recursivity in sets++case_set_rec =+  checks+    ( mkRecSet+        [ "a" $= mkInt 3+        , "b" $= var "a"+        ]+    , "rec { a = 3; b = a; }"+    )+++-- *** Inheritance++case_set_inherit =+  checks+    ( mkNonRecSet+        [ "e" $= mkInt 3+        , inherit ["a", "b"]+        ]+    , "{ e = 3; inherit a b; }"+    )+    ( mkNonRecSet $ one $ inherit mempty+    , "{ inherit; }"+    )++case_set_scoped_inherit =+  checks+    ( mkNonRecSet $+        (\ x -> [x, "e" $= mkInt 4, x]) $+          inheritFrom (var "a") ["b", "c"]+    , "{ inherit (a) b c; e = 4; inherit(a)b c; }"+    )++case_set_inherit_direct =+  checks+    ( mkNonRecSet $ one (inheritFrom (mkNonRecSet $ one ("a" $= mkInt 3)) mempty)+    , "{ inherit ({a = 3;}); }"+    )++case_inherit_selector_syntax_mistakes =+  mistakes+    "{ inherit a.x; }"+    -- A rare quirk of Nix that is proper to fix then to support (see git commit history)+    -- (old parser test result was):+    -- mkNonRecSet [inherit [DynamicKey (Plain (DoubleQuoted [Plain "a"]))]],+    "{ inherit \"a\"; }"+++-- ** Lists++case_int_list =+  checks+    ( mkList $ mkInt <$> [1,2,3]+    , "[1 2 3]"+    )++case_int_null_list =+  checks+    ( mkList (mkConst <$> [NInt 1, NInt 2, NInt 3, NNull, NInt 4])+    , "[1 2 3 null 4]"+    )++case_mixed_list =+  checks+    ( mkList+        [ mkNonRecSet (one $ "a" $= mkInt 3) @. "a"+        , mkIf (mkBool True) mkNull (mkBool False)+        , mkNull+        , mkBool False+        , mkInt 4+        , emptyList+        , (@.<|>) (var "c") "d" mkNull+        ]+    , "[{a = 3;}.a (if true then null else false) null false 4 [] c.d or null]"+    )++case_mixed_list_syntax_mistakes =+  mistakes+    "[if true then null else null]"+    "[a ? b]"+    "[a : a]"+    "[${\"test\")]"+++-- ** Lambdas++case_simple_lambda =+  checks+    ( mkFunction (Param "a") (var "a")+    , "a: a"+    )++case_lambda_or_uri =+  checks+    ( mkFunction (Param "a") $ var "b"+    , "a :b"+    )+    ( var "a" @@ mkStr "c:def"+    , "a c:def"+    )+    ( mkStr "c:def:" @@ var "c"+    , "c:def: c"+    )+    ( mkFunction (Param "a") emptySet+    , "a:{}"+    )+    ( mkFunction (Param "a") $ mkList $ one $ var "a"+    , "a:[a]"+    )++case_lambda_or_uri_syntax_mistakes =+  mistakes+    "def:"++case_lambda_pattern =+  checks+    ( mkFunction (mkParamSet args) $ var "b"+    , "{b, c ? 1}: b"+    -- Fix (NAbs (ParamSet [("b",Nothing),("c",Just (Fix (NConstant (NInt 1))))] False Nothing) (Fix (NSym "b")))+    )+    ( mkFunction (mkParamSet args2) $ var "b"+    , "{ b ? x: x  }: b"+    )+    ( mkFunction (mkNamedParamSet "a" args) $ var "b"+    , "a@{b,c ? 1}: b"+    )+    ( mkFunction (mkNamedParamSet "a" args) $ var "c"+    , "{b,c?1}@a: c"+    )+    ( mkFunction (mkNamedVariadicParamSet "a" vargs) $ var "c"+    , "{b,c?1,...}@a: c"+    )+    ( mkFunction (mkVariadicParamSet mempty) $ mkInt 1+    , "{...}: 1"+    )+ where+  args  = [("b", Nothing), ("c", pure $ mkInt 1)]+  vargs = [("b", Nothing), ("c", pure $ mkInt 1)]+  args2 = one ("b", pure lam)+  lam = mkFunction (Param "x") $ var "x"++case_lambda_pattern_syntax_mistakes =+  mistakes+    "a@b: a"+    "{a}@{b}: a"++case_lambda_app_int =+  checks+    ( mkFunction (Param "a") (var "a") @@ mkInt 3+    , "(a: a) 3"+    )+++-- ** Let++case_simple_let =+  checks+    ( mkLets (one $ "a" $= mkInt 4) $ var "a"+    , "let a = 4; in a"+    )++case_simple_let_syntax_mistakes =+  mistakes+    "let a = 4 in a"++case_let_body =+  checks+    ( mkRecSet (one $ "body" $= mkInt 1) @. "body"+    , "let { body = 1; }"+    )++case_nested_let =+  checks+    ( mkLets (one $ "a" $= mkInt 4) $+        mkLets (one $ "b" $= mkInt 5) $ var "a"+    , "let a = 4; in let b = 5; in a"+    )++case_nested_let_syntax_mistakes =+  mistakes+    "let a = 4; let b = 3; in b"++case_let_scoped_inherit =+  checks+    ( mkLets+        [ "a" $= mkNull+        , inheritFrom (var "b") $ one "c"+        ]+        $ var "c"+    , "let a = null; inherit (b) c; in c"+    )++case_let_scoped_inherit_syntax_mistakes =+  mistakes+    "let inherit (b) c in c"+++-- ** If++case_if =+  checks+    ( mkIf (mkBool True) (mkBool True) (mkBool False)+    , "if true then true else false"+    )++case_if_syntax_mistakes =+  mistakes+    "if true then false"+    "else"+    "if true then false else"+    "if true then false else false else"+    "1 + 2 then"++-- ** If follow by with++case_if_follow_by_with = checks +  (+    mkLets (one $ "x" $= mkNonRecSet ["a" $= mkBool True, "b" $= mkInt 2 ]) +      $ mkIf (mkWith (mkSym "x") (mkSym "a")) (mkInt 1) (mkInt 2)+    , "let x = { a = true; b = 2; }; in if with x; a then 1 else 2"+  )++-- ** Literal expressions in vals++case_identifier_keyword_prefix_invariants =+  invariantVals+    "true-name"+    "trueName"+    "null-name"+    "nullName"++case_identifier_keyword_prefix =+  checks+    ( mkList $ one $ var "null-name"+    , "[ null-name ]"+    )+++-- ** Strings++invariantString str =+  checks+    ( mkStr str+    , "\"" <> str <> "\""+    )++case_simple_string =+  knownAs invariantString+    "abcdef"+    "a"+    "A"+    "   a a  "+    ""++case_string_dollar =+  knownAs invariantString+    "a$b"+    "a$$b"+    "$cdef"+    "gh$i"++case_string_escape =+  checks+    ( mkStr "$\n\t\r\\"+    , "\"\\$\\n\\t\\r\\\\\""+    )+    ( mkStr " \" ' "+    , "\" \\\" \\' \""+    )++case_string_antiquote =+  checks+    ( Fix $ NStr $ DoubleQuoted+        [ Plain "abc"+        , Antiquoted $ mkIf (mkBool True) (mkStr "def") (mkStr "abc")+        , Plain " g"+        ]+    , "\"abc${  if true then \"def\" else \"abc\"  } g\""+    )+    ( mkStr "${a}"+    , "\"\\${a}\""+    )++case_string_antiquote_syntax_mistakes =+  mistakes+    "\"a"+    "${true}"+    "\"${true\""+++-- *** Indented string++case_indented_string =+  checks+    ( mkIndentedStr 0 "a"+    , "''a''"+    )+    ( mkIndentedStr 2 "foo\nbar"+    , "''\n  foo\n  bar''"+    )+    ( mkIndentedStr 0 mempty+    , "''        ''"+    )+    ( mkIndentedStr 0 "''"+    , "'''''''"+    )+    ( Fix $ NStr $ Indented 3+        [ Antiquoted mkNull+        , Plain "\na"+        , Antiquoted mkNull+        ]+    , "''   ${null}\n   a${null}''"+    )++case_indented_string_syntax_mistakes =+  mistakes+    "'''''"+    "''   '"++case_indented_string_escape =+  checks+    ( mkIndentedStr 1 "\n \t \\ ${ \\ \\n ' '' "+    , "'' ''\\n ''\\t ''\\\\ ''${ \\ \\n ' ''' ''"+    )++-- ** Selection++case_select =+  checks+    ( Fix $ NSelect Nothing (var "a") (StaticKey "e" :| [StaticKey "di", StaticKey "f"])+    , "a .  e .di. f"+    )+    ( Fix $ NSelect (pure mkNull) (var "a")+        (StaticKey "e" :| one (StaticKey "d"))+    , "a.e . d    or null"+    )+    ( Fix $ NSelect (pure mkNull) emptySet+        (one $ DynamicKey (Plain $ DoubleQuoted mempty))+    , "{}.\"\"or null"+    )+    ( Fix $ NBinary NConcat+        ((@.<|>)+          (mkNonRecSet $+            one $+              NamedVar+                (mkSelector "a")+                (mkList $ one $ mkInt 1)+                nullPos+          )+          "a"+          (mkList $ one $ mkInt 2)+        )+        (mkList $ one $ mkInt 3)+    , "{ a = [1]; }.a or [2] ++ [3]"+    )++case_select_path =+  checks+    ( var "f" @@ mkRelPath "./."+    , "f ./."+    )+    ( var "f" @. "b" @@ mkRelPath "../a"+    , "f.b ../a"+    )+    ( emptySet @@ mkRelPath "./def"+    , "{}./def"+    )+    ( Fix (NSelect Nothing emptySet $ one $ DynamicKey $ Plain $ DoubleQuoted mempty) @@ mkRelPath "./def"+    , "{}.\"\"./def"+    )++case_select_keyword =+  checks+    ( mkNonRecSet $ one $ "false" $= mkStr "foo"+    , "{ false = \"foo\"; }"+    )++case_select_or_precedence =+    assertParsePrint+      [text|+        let+          matchDef = def:   matcher:+                              v:   let+                                    case = builtins.head (builtins.attrNames v);+                                  in (matcher.case or def case) (v.case);+        in null+      |]+      [text|+         let+          matchDef = def:+            matcher:+              v:+                let+                  case = builtins.head (builtins.attrNames v);+                in (matcher.case or def) case (v.case);+        in null+      |]++case_select_or_precedence2 =+    assertParsePrint+      [text|+        let+          matchDef = def:   matcher:+                              v:   let+                                    case = builtins.head (builtins.attrNames v);+                                  in (matcher.case or null.foo) (v.case);+        in null+      |]+      [text|+        let+          matchDef = def:+            matcher:+              v:+                let+                  case = builtins.head (builtins.attrNames v);+                in (matcher.case or null).foo (v.case);+        in null+      |]++-- ** Function application++case_fun_app =+  checks+    ( var "f" @@ var "a" @@ var "b"+    , "f a b"+    )+    ( var "f" @@ (@.<|>) (var "a") "x" mkNull+    , "f a.x or null"+    )++case_fun_app_syntax_mistakes =+  mistakes+   "f if true then null else null"+++-- ** Operators++case_operator_fun_app =+  checks+    ( var "a" $++ var "b"+    , "a ++ b"+    )+    ( var "a" $++ var "f" @@ var "b"+    , "a ++ f b"+    )++case_operators =+  checks+    ( mkInt 1 $+ mkInt 2 $- mkInt 3+    , "1 + 2 - 3"+    )+    ( mkInt 1 $+ mkIf (mkBool True) (mkInt 2) (mkInt 3)+    , "1 + (if true then 2 else 3)"+    )+    ( mkNonRecSet (one $ "a" $= mkInt 3) $// mkRecSet (one $ "b" $= mkInt 4)+    , "{ a = 3; } // rec { b = 4; }"+    )+    ( mkNeg $ mkNeg $ var "a"+    , "--a"+    )+    ( var "a" $- var "b" $- var "c"+    , "a - b - c"+    )+    ( var "foo" $< var "bar"+    , "foo<bar"+    )++case_operators_syntax_mistakes =+  mistakes+    "+ 3"+    "foo +"+    "1 + if true then 1 else 2"+++-- ** Comments++case_comments =+  do+    Right expected <- parseNixFile "data/let.nix"+    assertParseFile "let-comments-multiline.nix" expected+    assertParseFile "let-comments.nix" expected+++-- ** Location++case_simpleLoc =+  let+    mkSPos = on (NSourcePos "<string>") (coerce . mkPos)+    mkSpan = on SrcSpan (uncurry mkSPos)+  in+    assertParseTextLoc [text|let+    foo = bar+         baz "qux";+    in foo+    |]+    (NLetAnn+      (mkSpan (1, 1) (4, 7))+      (one $+        NamedVar+          (one $ StaticKey "foo")+          (NAppAnn+            (mkSpan (2, 7) (3, 15))+            (NAppAnn+              (mkSpan (2, 7) (3, 9))+              (NSymAnn (mkSpan (2, 7) (2, 10)) "bar")+              (NSymAnn (mkSpan (3, 6) (3, 9 )) "baz")+            )+            (NStrAnn (mkSpan (3, 10) (3, 15)) $ DoubleQuoted $ one $ Plain "qux")+          )+          (mkSPos 2 1)+      )+      (NSymAnn (mkSpan (4, 4) (4, 7)) "foo")+    )+++tests :: TestTree+tests = $testGroupGenerator++---------------------------------------------------------------------------------++-- * Helpers++var = mkSym++invariantVal = staysInvariantUnder var++staysInvariantUnder :: (NixLang -> ExpectedHask) -> NixLang -> Assertion+staysInvariantUnder f v =+  (<=>) (f v) v++type NixLang = Text+type ExpectedHask = NExpr++(<=>) :: ExpectedHask -> NixLang -> Assertion+(<=>) = assertParseText++throwParseError :: forall ann . Text -> Text -> Doc ann -> Assertion+throwParseError entity expr err =+  assertFailure $+    renderString $+      layoutSmart Prettyprinter.defaultLayoutOptions $+        nest 2 $+          vsep+            [ mempty+            , "Unexpected fail parsing " <> reflow entity <> ":"+            , nest 2 $ vsep+              [ "Expression:"+              , reflow expr+              , "Error: " <> nest 2 err+              ]+            ]++assertParseText :: ExpectedHask -> NixLang -> Assertion+assertParseText expected str =+  either+    (throwParseError "expression" str)+    (assertEqual+      ("When parsing " <> toString str)+      (stripPositionInfo expected)+      . stripPositionInfo+    )+    (parseNixText str)++assertParseTextLoc :: NixLang -> NExprLoc -> Assertion+assertParseTextLoc str expected =+  either+    (throwParseError "expression" str)+    (assertEqual+      ("When parsing " <> toString str)+      expected+    )+    (parseNixTextLoc str)++assertParseFile :: Path -> NExpr -> Assertion+assertParseFile file expected =+  do+    res <- parseNixFile $ "data/" <> file+    either+      (throwParseError "data file" $ coerce fromString file)+      (assertEqual+        ("Parsing data file " <> coerce file)+        (stripPositionInfo expected)+        . stripPositionInfo+      )+      res++assertParseFail :: NixLang -> Assertion+assertParseFail str =+  either+    (const stub)+    (\ r ->+      assertFailure $ toString $ "\nUnexpected success parsing string ''" <> str <> "'':\n''Parsed value: ''" <> show r <> "''."+    )+    (parseNixText str)++-- assertRoundTrip :: Text -> Assertion+-- assertRoundTrip src = assertParsePrint src src++assertParsePrint :: Text -> Text -> Assertion+assertParsePrint src expect =+  let+    Right expr = parseNixTextLoc src+    result =+      renderStrict+      . layoutPretty defaultLayoutOptions+      . prettyNix+      . stripAnnotation $+        expr+  in+  assertEqual mempty expect result+++-----++-- | This class constructs functions that accept variacic number of argumets.+-- Every argument is an assertion.+-- So now the new assertions can be added just by adding it to a block of according assertions.+class VariadicAssertions t where+  checkListPairs' :: ((ExpectedHask, NixLang) -> Assertion) -> [(ExpectedHask, NixLang)] -> t++instance VariadicAssertions (IO a) where+  checkListPairs' f acc =+    do+      traverse_ f acc+      pure $ error "never would be reached, cuz `I'm lazy`."++instance (VariadicAssertions a) => VariadicAssertions ((ExpectedHask, NixLang) -> a) where+  checkListPairs' f acc x = checkListPairs' f (acc <> one x)++checks :: (VariadicAssertions a) => a+checks = checkListPairs' (uncurry assertParseText) mempty+++class VariadicArgs t where+  checkList' :: (NixLang -> Assertion) -> [NixLang] -> t++instance VariadicArgs (IO a) where+  checkList' f acc =+    do+      traverse_ f acc+      pure $ error "never would be reached, cuz `I'm lazy`."++instance (VariadicArgs a) => VariadicArgs (NixLang -> a) where+  checkList' f acc x = checkList' f (acc <> one x)++knownAs :: (VariadicArgs a) => (NixLang -> Assertion) -> a+knownAs f = checkList' f mempty++mistakes :: (VariadicArgs a) => a+mistakes = knownAs assertParseFail++invariantVals :: (VariadicArgs a) => a+invariantVals = knownAs invariantVal+
tests/PrettyParseTests.hs view
@@ -1,145 +1,174 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MonoLocalBinds #-}-{-# LANGUAGE NoMonomorphismRestriction #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE UndecidableInstances #-}+{-# language DataKinds #-}+{-# language MonoLocalBinds #-}+{-# language NoMonomorphismRestriction #-} -{-# OPTIONS -Wno-orphans#-} -module PrettyParseTests  where +module PrettyParseTests where++import           Nix.Prelude 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.String                   as String import           Hedgehog-import qualified Hedgehog.Gen as Gen-import qualified Hedgehog.Range as Range+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           Prettyprinter import           Test.Tasty 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+import qualified Text.Show.Pretty              as PS  asciiString :: MonadGen m => m String asciiString = Gen.list (Range.linear 1 15) Gen.lower  asciiText :: Gen Text-asciiText = pack <$> asciiString+asciiText = fromString <$> asciiString +asciiVarName :: Gen VarName+asciiVarName = coerce <$> asciiText+ -- Might want to replace this instance with a constant value-genPos :: Gen Pos-genPos = mkPos <$> Gen.int (Range.linear 1 256)+genNPos :: Gen NPos+genNPos = fmap coerce $ mkPos <$> Gen.int (Range.linear 1 256) -genSourcePos :: Gen SourcePos-genSourcePos = SourcePos <$> asciiString <*> genPos <*> genPos+genNSourcePos :: Gen NSourcePos+genNSourcePos =+  join (liftA3+      NSourcePos+      (fmap coerce asciiString)+    )+    genNPos  genKeyName :: Gen (NKeyName NExpr)-genKeyName = Gen.choice [ DynamicKey <$> genAntiquoted genString-                        , StaticKey <$> asciiText ]+genKeyName =+  Gen.choice [DynamicKey <$> genAntiquoted genString, StaticKey <$> asciiVarName]  genAntiquoted :: Gen a -> Gen (Antiquoted a NExpr)-genAntiquoted gen = Gen.choice-  [ Plain <$> gen-  , pure EscapedNewline-  , Antiquoted <$> genExpr-  ]+genAntiquoted gen =+  Gen.choice [Plain <$> gen, pure EscapedNewline, Antiquoted <$> genExpr]  genBinding :: Gen (Binding NExpr) genBinding = Gen.choice-  [ NamedVar <$> genAttrPath <*> genExpr <*> genSourcePos-  , Inherit <$> Gen.maybe genExpr-            <*> Gen.list (Range.linear 0 5) genKeyName-            <*> genSourcePos+  [ liftA3 NamedVar+      genAttrPath+      genExpr+      genNSourcePos+  , liftA3 Inherit+      (Gen.maybe genExpr)+      (Gen.list (Range.linear 0 5) asciiVarName)+      genNSourcePos   ]  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)+  [ DoubleQuoted <$> genLines+  , liftA2 Indented+      (Gen.int $ Range.linear 0 10)+      genLines   ]+ where+  genLines =+    Gen.list+      (Range.linear 0 5)+      (genAntiquoted asciiText)  genAttrPath :: Gen (NAttrPath NExpr)-genAttrPath = (NE.:|) <$> genKeyName-                      <*> Gen.list (Range.linear 0 4) genKeyName+genAttrPath =+  liftA2 (:|)+    genKeyName+    $ Gen.list (Range.linear 0 4) genKeyName  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]+  [ Param <$> asciiVarName+  , liftA3 (mkGeneralParamSet . pure)+      (Gen.choice [stub, asciiText])+      (Gen.list (Range.linear 0 10) $+        liftA2 (,)+          asciiText+          (Gen.maybe genExpr)+      )+      Gen.bool   ] + genAtom :: Gen NAtom genAtom = Gen.choice-  [ NInt   <$> Gen.integral (Range.linear 0 1000)-  , NFloat <$> Gen.float (Range.linearFrac 0.0 1000.0)+  [ NInt   <$> Gen.integral (Range.linear     0   1000  )+  , NFloat <$> Gen.float    (Range.linearFrac 0.0 1000.0)   , NBool  <$> Gen.bool-  , pure NNull ]+  , 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. 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)-          ]+genExpr =+  Gen.sized genCurbed  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+  genCurbed (coerce -> n) =+    Fix <$>+      bool+        small+        big+        (n >= 2)+   where +    genConstant    = NConstant                         <$> genAtom+    genStr         = NStr                              <$> genString+    genSym         = NSym                              <$> asciiVarName+    genLiteralPath = NLiteralPath . ("./" <>) . coerce <$> asciiString+    genEnvPath     = NEnvPath . coerce                 <$> asciiString++    small = Gen.choice [genConstant, genStr, genSym, genLiteralPath, genEnvPath]++    big =+      let+          sizeDivBy i = Size $ n `div` i+          resizeDivBy i = Gen.resize (sizeDivBy i)+      in+      Gen.frequency+        [ (1 , genConstant)+        , (1 , genSym)+        , (2 , genUnary)+        , (5 , genList)+        , (20, genSet)+        , (10, genRecSet)+        , (1 , resizeDivBy 2 genAssert)+        , (4 , resizeDivBy 3 genIf)+        , (2 , resizeDivBy 3 genBinary)+        , (3 , resizeDivBy 3 genSelect)+        , (20, resizeDivBy 2 genAbs)+        , (2 , resizeDivBy 2 genHasAttr)+        , (10, resizeDivBy 2 genLet)+        , (10, resizeDivBy 2 genWith)+        ]+     where+      genList        = NList                             <$> fairList genExpr+      genSet         = NSet mempty                       <$> fairList genBinding+      genRecSet      = NSet Recursive                    <$> fairList genBinding+      genUnary       = liftA2 NUnary   Gen.enumBounded       genExpr+      genBinary      = join (liftA3 NBinary  Gen.enumBounded) genExpr+      genSelect      = liftA3 NSelect  (Gen.maybe genExpr)   genExpr     genAttrPath+      genHasAttr     = liftA2 NHasAttr genExpr               genAttrPath+      genAbs         = liftA2 NAbs     genParams             genExpr+      genLet         = liftA2 NLet     (fairList genBinding) genExpr+      genIf          = join (liftA3 NIf      genExpr) genExpr+      genWith        = join (liftA2 NWith) genExpr+      genAssert      = join (liftA2 NAssert) 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 = Gen.sized $ \s -> do-  k <- Gen.int (Range.linear 0 (unSize s))+  k <- Gen.int $ Range.linear 0 $ unSize s   -- Use max here to avoid dividing by zero when there is the empty list   Gen.resize (Size (unSize s `div` max 1 k)) $ Gen.list (Range.singleton k) g @@ -147,87 +176,103 @@ equivUpToNormalization x y = normalize x == normalize y  normalize :: NExpr -> NExpr-normalize = cata $ \case-  NConstant (NInt n)   | n < 0 -> Fix (NUnary NNeg (Fix (NConstant (NInt (negate n)))))-  NConstant (NFloat n) | n < 0 -> Fix (NUnary NNeg (Fix (NConstant (NFloat (negate n)))))+normalize = foldFix $ \case+  NConstant (NInt n) | n < 0 ->+    mkNeg $ mkInt $ negate n+  NConstant (NFloat n) | n < 0 ->+    mkNeg $ mkFloat $ negate n -  NSet binds      -> Fix (NSet (map normBinding binds))-  NRecSet binds   -> Fix (NRecSet (map normBinding binds))-  NLet binds r    -> Fix (NLet (map normBinding binds) r)+  NSet recur binds ->+    mkSet recur $ normBinding <$> binds+  NLet binds  r ->+    mkLets (normBinding <$> binds) r -  NAbs params r   -> Fix (NAbs (normParams params) r)+  NAbs params r ->+    mkFunction (normParams params) r -  r               -> Fix r+  r             -> Fix r   where-  normBinding (NamedVar path r pos) = NamedVar (NE.map normKey path) r pos-  normBinding (Inherit mr names pos) = Inherit mr (map normKey names) pos+  normBinding (NamedVar path r     pos) = NamedVar (normKey <$> path) r pos+  normBinding (Inherit  mr   names pos) = Inherit mr names pos    normKey (DynamicKey quoted) = DynamicKey (normAntiquotedString quoted)-  normKey (StaticKey name) = StaticKey name+  normKey (StaticKey  name  ) = StaticKey name -  normAntiquotedString :: Antiquoted (NString NExpr) NExpr-                       -> Antiquoted (NString NExpr) NExpr-  normAntiquotedString (Plain (DoubleQuoted [EscapedNewline])) =-      EscapedNewline+  normAntiquotedString+    :: Antiquoted (NString NExpr) NExpr+    -> Antiquoted (NString NExpr) NExpr+  normAntiquotedString (Plain (DoubleQuoted [EscapedNewline])) = EscapedNewline   normAntiquotedString (Plain (DoubleQuoted strs)) =-      let strs' = map normAntiquotedText strs-      in if strs == strs'-         then Plain (DoubleQuoted strs)-         else normAntiquotedString (Plain (DoubleQuoted strs'))+    bool normAntiquotedString id (strs == strs')+      (Plain $ DoubleQuoted strs')+    where+     strs' = normAntiquotedText <$> strs   normAntiquotedString r = r -  normAntiquotedText :: Antiquoted Text NExpr -> Antiquoted Text NExpr-  normAntiquotedText (Plain "\n")   = EscapedNewline+  normAntiquotedText+    :: Antiquoted Text NExpr+    -> Antiquoted Text NExpr+  normAntiquotedText (Plain "\n"  ) = EscapedNewline   normAntiquotedText (Plain "''\n") = EscapedNewline-  normAntiquotedText r = r+  normAntiquotedText r              = r -  normParams (ParamSet binds var (Just "")) = ParamSet binds var Nothing-  normParams r = r+  normParams (ParamSet (Just "") variadic pset) = ParamSet Nothing variadic pset+  normParams r                              = r  -- | Test that parse . pretty == id up to attribute position information. prop_prettyparse :: Monad m => NExpr -> PropertyT m ()-prop_prettyparse p = do-  let prog = show (pretty p)-  case parse (pack prog) of-    Failure s -> do-        footnote $ show $-            text "Parse failed:" </> text (show s)-              P.<$> P.indent 2 (pretty p)-        discard-    Success v-        | equivUpToNormalization p v -> success-        | otherwise -> do-          let pp = normalise prog-              pv = normalise (show (pretty v))-          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 "========================================"+prop_prettyparse p =+  either+    (\ s -> do+      footnote $ show $ vsep+        -- Remove :: Text type annotation after String -> Text migration.+        [fillSep ["Parse failed:", pretty (show s :: Text)], indent 2 $ prettyNix p]+      discard+    )+    (\ v ->+      bool+        (do+          let+            pp = normalise prog+            pv = normalise $ show $ prettyNix v++          footnote $+            show $+              vsep+                [ "----------------------------------------"+                , vsep ["Expr before:"      , indent 2 $ pretty $ PS.ppShow p]+                , "----------------------------------------"+                , vsep ["Expr after:"       , indent 2 $ pretty $ PS.ppShow v]+                , "----------------------------------------"+                , vsep ["Pretty before:"    , indent 2 $ pretty prog]+                , "----------------------------------------"+                , vsep ["Pretty after:"     , indent 2 $ prettyNix v]+                , "----------------------------------------"+                , vsep ["Normalised before:", indent 2 $ pretty pp]+                , "----------------------------------------"+                , vsep ["Normalised after:" , indent 2 $ pretty pv]+                , "========================================"+                , vsep ["Normalised diff:"  , pretty $ ppDiff $ ldiff pp pv]+                , "========================================"+                ]           assert (pp == pv)-  where-    pretty = prettyNix-    parse  = parseNixText+        )+        success+        (equivUpToNormalization p v)+    )+    (parse $ fromString prog)+ where+  prog = show $ prettyNix p -    normalise = unlines . map (reverse . dropWhile isSpace . reverse) . lines+  parse     = parseNixText -    diff :: String -> String -> [Diff [String]]-    diff s1 s2 = getDiff (map (:[]) (lines s1)) (map (:[]) (lines s2))+  normalise s = String.unlines $ reverse . dropWhile isSpace . reverse <$> String.lines s +  ldiff :: String -> String -> [Diff [String]]+  ldiff s1 s2 = getDiff (one <$> String.lines s1) (one <$> String.lines s2)+ tests :: TestLimit -> TestTree-tests n = testProperty "Pretty/Parse Property" $ withTests n $ property $ do-    x <- forAll genExpr-    prop_prettyparse x+tests n =+  testProperty "Pretty/Parse Property" $+    withTests n $ property $ prop_prettyparse =<< forAll genExpr
tests/PrettyTests.hs view
@@ -1,37 +1,58 @@-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE OverloadedStrings #-}-module PrettyTests (tests) where+{-# language TemplateHaskell #-} -import Test.Tasty-import Test.Tasty.HUnit-import Test.Tasty.TH+module PrettyTests  ( tests ) where -import Nix.Expr-import Nix.Pretty+import           Nix.Prelude+import           Test.Tasty+import           Test.Tasty.HUnit+import           Test.Tasty.TH +import           Nix.Expr+import           Nix.Pretty+ case_indented_antiquotation :: Assertion-case_indented_antiquotation = do-    assertPretty (mkIndentedStr 0 "echo $foo") "''echo $foo''"-    assertPretty (mkIndentedStr 0 "echo ${foo}") "''echo ''${foo}''"+case_indented_antiquotation =+  do+    assertPretty+      (mkIndentedStr 0 "echo $foo")+      "''echo $foo''"+    assertPretty+      (mkIndentedStr 0 "echo ${foo}")+      "''echo ''${foo}''"  case_string_antiquotation :: Assertion-case_string_antiquotation = do-    assertPretty (mkStr "echo $foo") "\"echo \\$foo\""-    assertPretty (mkStr "echo ${foo}") "\"echo \\${foo}\""+case_string_antiquotation =+  do+    assertPretty+      (mkStr "echo $foo")+      "\"echo $foo\""+    assertPretty+      (mkStr "echo ${foo}")+      "\"echo \\${foo}\""  case_function_params :: Assertion case_function_params =-    assertPretty (mkFunction (mkParamset [] True) (mkInt 3)) "{ ... }:\n  3"+  assertPretty+    (mkFunction (mkVariadicParamSet mempty) (mkInt 3))+    "{ ... }:\n  3"  case_paths :: Assertion-case_paths = do-    assertPretty (mkPath False "~/test.nix") "~/test.nix"-    assertPretty (mkPath False "/test.nix") "/test.nix"-    assertPretty (mkPath False "./test.nix") "./test.nix"+case_paths =+  do+    assertPretty+      (mkPath False "~/test.nix")+      "~/test.nix"+    assertPretty+      (mkPath False "/test.nix")+      "/test.nix"+    assertPretty+      (mkPath False "./test.nix")+      "./test.nix"  tests :: TestTree tests = $testGroupGenerator ----------------------------------------------------------------------------------assertPretty :: NExpr -> String -> Assertion-assertPretty e s = assertEqual ("When pretty-printing " ++ show e) s . show $ prettyNix e+---------------------------------------------------------------------------------+assertPretty :: NExpr -> Text -> Assertion+assertPretty e s =+  assertEqual ("When pretty-printing " <> show e) s . show $ prettyNix e
tests/ReduceExprTests.hs view
@@ -1,56 +1,60 @@-{-# LANGUAGE OverloadedStrings #-}-{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# 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)+import           Nix.Prelude+import           Test.Tasty+import           Test.Tasty.HUnit +import           Nix.Expr.Types+import           Nix.Expr.Types.Annotated+import           Nix.Parser+import           Nix.Reduce                     ( reduceExpr )+import           Nix.Expr.Shorthands + 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 -    ]+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+assertSucc =+  either+    (assertFailure . show)+    pure -cmpReduceResult :: Result NExprLoc -> NExpr -> Assertion +cmpReduceResult :: Result NExprLoc -> NExpr -> Assertion cmpReduceResult r e = do-    r <- assertSucc r-    r <- stripAnnotation <$> reduceExpr Nothing r-    r @?= e+  r <- assertSucc r+  r <- stripAnnotation <$> reduceExpr mempty r+  r @?= e  shouldntReduce :: Result NExprLoc -> Assertion shouldntReduce r = do-    r <- assertSucc r-    rReduced <- reduceExpr Nothing r-    r @?= rReduced+  r        <- assertSucc r+  rReduced <- reduceExpr mempty r+  r @?= rReduced  selectBasic :: Result NExprLoc selectBasic = parseNixTextLoc "{b=2;a=42;}.a"  selectBasicExpect :: NExpr-selectBasicExpect = Fix . NConstant $ NInt 42+selectBasicExpect = mkInt 42  selectNested :: Result NExprLoc selectNested = parseNixTextLoc "{a={b=2;a=42;};b={a=2;};}.a.a"  selectNestedExpect :: NExpr-selectNestedExpect = Fix . NConstant $ NInt 42+selectNestedExpect = mkInt 42  selectIncorrectAttrPath :: Result NExprLoc selectIncorrectAttrPath = parseNixTextLoc "{a=42;}.b"
tests/TestCommon.hs view
@@ -1,67 +1,82 @@-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE TypeApplications #-}- module TestCommon where -import Control.Monad.Catch-import Control.Monad.IO.Class-import Data.Text (Text, unpack)-import Data.Time-import Nix-import System.Environment-import System.IO-import System.Posix.Files-import System.Posix.Temp-import System.Process-import Test.Tasty.HUnit+import           Nix.Prelude+import           GHC.Err                        ( errorWithoutStackTrace )+import           Control.Monad.Catch+import           Data.Time+import           Data.Text.IO as Text+import           Nix+import           Nix.Standard+import           System.Environment+import           System.IO+import           System.PosixCompat.Files+import           System.PosixCompat.Temp+import           System.Process+import           Test.Tasty.HUnit -hnixEvalFile :: Options -> FilePath -> IO (NValueNF (Lazy IO))-hnixEvalFile opts file = do-  parseResult <- parseNixFileLoc file-  case parseResult of-    Failure err        ->-        error $ "Parsing failed for file `" ++ file ++ "`.\n" ++ show err-    Success expr -> do-        setEnv "TEST_VAR" "foo"-        runLazyM opts $-            catch (evaluateExpression (Just file) nixEvalExprLoc-                                      normalForm expr) $ \case-                NixException frames ->+hnixEvalFile :: Options -> Path -> IO StdVal+hnixEvalFile opts file =+  do+    parseResult <- parseNixFileLoc file+    either+      (\ err -> fail $ "Parsing failed for file `" <> coerce file <> "`.\n" <> show err)+      (\ expr ->+        do+          setEnv "TEST_VAR" "foo"+          runWithBasicEffects opts $+            evaluateExpression (pure $ coerce file) nixEvalExprLoc normalForm expr+              `catch`+                \case+                  NixException frames ->                     errorWithoutStackTrace . show-                        =<< renderFrames @(NThunk (Lazy IO)) frames+                      =<< renderFrames+                          @StdVal+                          @StdThun+                          frames+      )+      parseResult -hnixEvalText :: Options -> Text -> IO (NValueNF (Lazy IO))-hnixEvalText opts src = case parseNixText src of-    Failure err        ->-        error $ "Parsing failed for expressien `"-            ++ unpack src ++ "`.\n" ++ show err-    Success expr ->-        runLazyM opts $ normalForm =<< nixEvalExpr Nothing expr+nixEvalFile :: Path -> IO Text+nixEvalFile (coerce -> fp) = fromString <$> readProcess "nix-instantiate" ["--eval", "--strict", fp] mempty+hnixEvalText :: Options -> Text -> IO StdVal+hnixEvalText opts src =+  either+    (\ err -> fail $ toString $ "Parsing failed for expression `" <> src <> "`.\n" <> show err)+    (runWithBasicEffects opts . (normalForm <=< nixEvalExpr mempty))+    $ parseNixText src -nixEvalString :: String -> IO String-nixEvalString expr = do-  (fp,h) <- mkstemp "nix-test-eval"-  hPutStr h expr-  hClose h-  res <- nixEvalFile fp-  removeLink fp-  return res+nixEvalText :: Text -> IO Text+nixEvalText expr =+  do+    (fp, h) <- mkstemp "nix-test-eval"+    Text.hPutStr h expr+    hClose h+    res <- nixEvalFile $ coerce fp+    removeLink fp+    pure res -nixEvalFile :: FilePath -> IO String-nixEvalFile fp = readProcess "nix-instantiate" ["--eval", "--strict", fp] ""+assertEvalMatchesNix+  :: ( Options+    -> Text -> IO (NValue t (StdCited StandardIO) StandardIO)+    )+  -> (Text -> IO Text)+  -> Text+  -> IO ()+assertEvalMatchesNix evalHNix evalNix fp =+  do+    time    <- liftIO getCurrentTime+    hnixVal <- (<> "\n") . printNix <$> evalHNix (defaultOptions time) fp+    nixVal  <- evalNix fp+    assertEqual (toString fp) nixVal hnixVal -assertEvalFileMatchesNix :: FilePath -> Assertion-assertEvalFileMatchesNix fp = do-  time <- liftIO getCurrentTime-  hnixVal <- (++"\n") . printNix <$> hnixEvalFile (defaultOptions time) fp-  nixVal <- nixEvalFile fp-  assertEqual fp nixVal hnixVal+-- | Compares @HNix@ & @Nix@ return results.+assertEvalFileMatchesNix :: Path -> Assertion+assertEvalFileMatchesNix fp =+  assertEvalMatchesNix+    (\ o -> hnixEvalFile o . coerce . toString)+    (nixEvalFile . coerce . toString)+    $ fromString $ coerce fp -assertEvalMatchesNix :: Text -> Assertion-assertEvalMatchesNix expr = do-  time <- liftIO getCurrentTime-  hnixVal <- (++"\n") . printNix <$> hnixEvalText (defaultOptions time) expr-  nixVal <- nixEvalString expr'-  assertEqual expr' nixVal hnixVal- where-  expr' = unpack expr+assertEvalTextMatchesNix :: Text -> Assertion+assertEvalTextMatchesNix =+  assertEvalMatchesNix hnixEvalText nixEvalText
+ tests/eval-compare/builtins.appendContext.nix view
@@ -0,0 +1,30 @@+let+  drv = derivation {+    name = "fail";+    builder = "/bin/false";+    system = "x86_64-linux";+    outputs = [ "out" "foo" ];+  };++  path = "${./builtins.appendContext.nix}";++  desired-context = {+    "${builtins.unsafeDiscardStringContext path}" = {+      path = true;+    };+    "${builtins.unsafeDiscardStringContext drv.drvPath}" = {+      outputs = [ "foo" "out" ];+      allOutputs = true;+    };+  };++  # TODO: Remove builtins.attrValues here once store hash is correct.+  legit-context = builtins.attrValues (builtins.getContext "${path}${drv.outPath}${drv.foo.outPath}${drv.drvPath}");++  constructed-context = builtins.attrValues (builtins.getContext (builtins.appendContext "" desired-context));+# jww (2019-03-17): This is not working just yet+# in [ (builtins.appendContext "foo" {})+#      (legit-context == constructed-context)+#      constructed-context+#    ]+in true
+ tests/eval-compare/builtins.eq-bottom-00.nix view
@@ -0,0 +1,25 @@+let++  plain = (let x = x; in x);+  nested_list = [(let x = x; in x)];+  nested_attrset = { y = (let x = x; in x); };+  nested_list_list = [[(let x = x; in x)]];+  nested_list_attrset = [{ y = (let x = x; in x); }];+  nested_list_function = [(_: let x = x; in x)];+  nested_attrset_list = { y = [(let x = x; in x)]; };+  nested_attrset_attrset = { y = { y = (let x = x; in x); }; };+  nested_attrset_function = { y = (_: let x = x; in x); };++  tests = [+    # (plain == plain) # Diverges+    # (nested_list == nested_list) # Diverges+    # (nested_attrset == nested_attrset) # Diverges+    (nested_list_list == nested_list_list)+    (nested_list_attrset == nested_list_attrset)+    (nested_list_function == nested_list_function)+    (nested_attrset_attrset == nested_attrset_attrset)+    (nested_attrset_list == nested_attrset_list)+    (nested_attrset_function == nested_attrset_function)+  ];++in tests
+ tests/eval-compare/builtins.fetchurl-01.nix view
@@ -0,0 +1,5 @@+with builtins;++let a = fetchurl "https://haskell.org";++in [ a (hasContext a) ]
+ tests/eval-compare/builtins.fromJSON-01.nix view
@@ -0,0 +1,63 @@+with builtins;++let simpleJSON = "{\"foo\": \"39\", \"bar\": 472}";+    screwyJSON = "{\"4275\": \"Please do not fail.\"}";+    crazyJSON = "     {+    \"response\": {+        \"success\": 1,+        \"current_time\": 1362339098,+        \"prices\": {+            \"35\": {+                \"11\": {+                    \"0\": {+                        \"current\": {+                            \"currency\": \"keys\",+                            \"value\": 39,+                            \"value_high\": 41,+                            \"date\": 1357515306+                        },+                        \"previous\": {+                            \"currency\": \"keys\",+                            \"value\": 37,+                            \"value_high\": 39+                        }+                    }+                },+                \"3\": {+                    \"0\": {+                        \"current\": {+                            \"currency\": \"metal\",+                            \"value\": 0.33,+                            \"value_high\": 0.66+                        }+                    }+                }+            },+            \"5002\": {+                \"6\": {+                    \"0\": {+                        \"current\": {+                            \"currency\": \"usd\",+                            \"value\": 0.39,+                            \"value_high\": 0.42,+                            \"date\": 1358090106+                        }+                    }+                }+            },+            \"5022\": {+                \"6\": {+                    \"1\": {+                        \"current\": {+                            \"currency\": \"metal\",+                            \"value\": 1.33,+                            \"value_high\": 1.55,+                            \"date\": 1357515175+                        }+                    }+                }+            }+        }+    }+}";+in [(fromJSON simpleJSON) (fromJSON screwyJSON) (fromJSON crazyJSON)]
+ tests/eval-compare/builtins.getContext.nix view
@@ -0,0 +1,7 @@+with builtins;++[ (getContext "foo")+  (attrValues (getContext (toFile "foo" "foo contents")))+  # TODO: Re-enable this once output hash is correct.+  # (getContext (toFile "foo" "foo contents"))+]
+ tests/eval-compare/builtins.lessThan-01.nix view
@@ -0,0 +1,44 @@+with builtins;++let numTestPrecisionA = 4.000000000000000000001;+    numTestPrecisionB = 4;+    numTest3 = -4.1;+    numTest4 = -4;+    numTestZeroA = 0;+    numTestZeroB = -0;+    numTestMaxBoundA = 999999999999999999;+    numTestMaxBoundB = 999999999999999998;+    numTestMinBoundA = -999999999999999999;+    numTestMinBoundB = -999999999999999998;+    stringTest1 = "abcd";+    stringTest2 = "abce";+    stringTestBase1 = "foo" + "/" + stringTest1;+    stringTestBase2 = "foo" + "/" + stringTest2;+    stringTestJSONA = toJSON stringTest1;+    stringTestJSONB = toJSON stringTest2;+    stringTestToFileA = toFile "stringTest1" stringTest1;+    stringTestToFileB = toFile "stringTest2" stringTest2;+in [(lessThan numTestPrecisionA numTestPrecisionB)+    (lessThan numTestPrecisionB numTestPrecisionA)+    (lessThan numTest3 numTest4)+    (lessThan numTest4 numTest3)+    (lessThan numTestZeroA numTestZeroB)+    (lessThan numTestZeroB numTestZeroA)+    (lessThan numTestMaxBoundA numTestMaxBoundB)+    (lessThan numTestMaxBoundB numTestMaxBoundA)+    (lessThan numTestMinBoundA numTestMinBoundB)+    (lessThan numTestMinBoundB numTestMinBoundA)+    (lessThan stringTest1 stringTest2)+    (lessThan stringTest2 stringTest1)+    (lessThan stringTestJSONA stringTestJSONB)+    (lessThan stringTestJSONB stringTestJSONA)+    (lessThan stringTest1 stringTestJSONB)+    (lessThan stringTestJSONB stringTest1)+    (lessThan stringTest2 stringTestJSONA)+    (lessThan stringTestJSONA stringTest2)+    (lessThan stringTest1 stringTestToFileB)+    (lessThan stringTestToFileB stringTest1)+    (lessThan stringTestToFileA stringTest2)+    (lessThan stringTest1 (baseNameOf stringTestBase1))+    (lessThan stringTest2 (baseNameOf stringTestBase2))+  ]
+ tests/eval-compare/builtins.mapAttrs-01.nix view
@@ -0,0 +1,20 @@+with builtins;++let fooset = { foo = 123; bar = 456; };+    lolset = { "foo/bar" = "lol"; "bar/baz" = "wat";};+    emptyset = {};+in [ (all (x: hasContext(x)) (attrValues (mapAttrs (key: value: key) fooset)))+     (all (x: hasContext(x)) (attrValues (mapAttrs (key: value: key) lolset)))+     (all (x: hasContext(x)) (attrValues (mapAttrs (key: value: key) emptyset)))+     (all (x: hasContext(x)) (attrValues (mapAttrs (key: value: key + toString value) fooset)))+     (all (x: hasContext(x)) (attrValues (mapAttrs (key: value: key + toString value) lolset)))+     (all (x: hasContext(x)) (attrValues (mapAttrs (key: value: key + toString value) emptyset)))+     (all (x: hasContext(x)) (attrValues (mapAttrs (key: value: key + toJSON value) fooset)))+     (all (x: hasContext(x)) (attrValues (mapAttrs (key: value: key + toJSON value) lolset)))+     (all (x: hasContext(x)) (attrValues (mapAttrs (key: value: key + toJSON value) emptyset)))+     (all (x: hasContext(x)) (attrValues (mapAttrs (key: value: key + toJSON (toString value)) fooset)))+     (all (x: hasContext(x)) (attrValues (mapAttrs (key: value: key + toJSON (toString value)) lolset)))+     (all (x: hasContext(x)) (attrValues (mapAttrs (key: value: key + toJSON (toString value)) emptyset)))+     (all (x: hasContext(x)) (attrValues (mapAttrs (key: value: key + value) lolset)))+     (all (x: hasContext(x)) (attrValues (mapAttrs (key: value: key + value) emptyset)))+  ]
+ tests/eval-compare/builtins.pathExists.nix view
@@ -0,0 +1,1 @@+builtins.pathExists "/var/empty/invalid-directory"
+ tests/eval-compare/builtins.replaceStrings-01.nix view
@@ -0,0 +1,18 @@+with builtins;++let a1 = toFile "foo" "foo contents"; # /nix/store/pqwdc5m06lxl8gmzcd26ifwsdhq9fj7k-foo+    a2 = toFile "bar" "bar contents"; # /nix/store/4q6kxj1ym13yfp1bcdrzrwa1la6dqgp5-bar+    b = dirOf a1;+    c = substring 3 1 b;+    d = replaceStrings ["b"] [c] "abc";+    e = replaceStrings ["k"] [c] "abc";+    f = replaceStrings ["y"] [c] (dirOf a2);+    g = replaceStrings ["s"] [c] (dirOf a2);+    h = replaceStrings ["y"] ["z"] "abc";+in [ b c d e f g h     # TODO Add a1 here when we have correct store hashing working+     (hasContext d)+     (hasContext e)+     (hasContext f)+     (hasContext g)+     (hasContext h)+   ]
+ tests/eval-compare/builtins.string.store.nix view
@@ -0,0 +1,1 @@+"${builtins.storeDir}"
+ tests/eval-compare/builtins.toJSON.nix view
@@ -0,0 +1,8 @@+with builtins;++let f = toFile "foo" "foo contents"; # /nix/store/pqwdc5m06lxl8gmzcd26ifwsdhq9fj7k-foo+    objA = { a = 15; b = substring 1 3 (dirOf f); };+    objB = { a = 42; b = "hello"; };+in [ (hasContext (toJSON objA))+     (hasContext (toJSON objB))+   ]
+ tests/eval-compare/current-system.nix view
@@ -0,0 +1,1 @@+builtins.hasContext builtins.currentSystem
+ tests/eval-compare/ellipsis.nix view
@@ -0,0 +1,3 @@+let x = 1;+    f = { ... }: x;+in f { x = 2; }
+ tests/eval-compare/paths-01.nix view
@@ -0,0 +1,1 @@+baseNameOf foo/bar
+ tests/eval-compare/placeholder.nix view
@@ -0,0 +1,1 @@+builtins.placeholder "foo"
+ tests/files/attrs.nix view
@@ -0,0 +1,12 @@+rec {++  y = 2;+  z = { w = 4; };+  v = rec {+    u = 6;+    t = [ u z.w s.q ];+  };+  s = { r = import ./goodbye.nix; q = 10; };+  p = import ./hello.nix;++}
+ tests/files/callLibs.nix view
@@ -0,0 +1,3 @@+let callLibs = file: import file { lib = self; };+    trivial = callLibs ./trivial.nix;+in trivial
+ tests/files/eighty.nix view
@@ -0,0 +1,1 @@+80
+ tests/files/file.nix view
@@ -0,0 +1,1 @@+({ x ? 1, y ? x * 3 }: import ./file2.nix { a = y; }) {}
+ tests/files/file2.nix view
@@ -0,0 +1,1 @@+{ a }: a + 100
+ tests/files/findFile.nix view
+ tests/files/force.nix view
@@ -0,0 +1,1 @@+let f = { a = 1; b = import ./hello.nix; }; in f.a
+ tests/files/goodbye.nix view
@@ -0,0 +1,1 @@+"Goodbye, world!"
+ tests/files/hello.nix view
@@ -0,0 +1,1 @@+"Hello, world!"
+ tests/files/hello2.nix view
@@ -0,0 +1,15 @@+let x = { z = x: import ./eighty.nix + 20 + x; w = 123; };+            allPackages = self:+              super:+                let+                  res = import ./eighty.nix {+                    inherit lib nixpkgsFun noSysDirs+                            config;+                  } null self;+                in res;+    y = "Hello";+    z = "Goodbye";+    f = x: if x == 0 then x * 2 else x + 2;+    w = x.z 5 + f 3 - 15;+in assert w == 1;+   if x.z 2 == 100 then y else 3
+ tests/files/if-then.nix view
@@ -0,0 +1,6 @@+# [ ({ a = 1; b = 2; } // { c = 1; d = 2; })+#   ([1 2 3] ++ [4.0 5.0 6.0])+#   (x: y: x + y)+# ]++({ x, y ? x + 1 }: x + x)
+ tests/files/lint.nix view
@@ -0,0 +1,1 @@+{ x, y }: let z = x + y; in [ z (y + 2) ]
+ tests/files/loop.nix view
@@ -0,0 +1,144 @@+(with builtins;+{ localSystem ? builtins.intersectAttrs {+     system = null;+     platform = null;+   } args+   , system ? null+   , platform ? null+   , crossSystem ? null+   , config ? {}+   , overlays ? []+   , ... }@args:+  ({ localSystem+   , crossSystem ? null+   , config ? null+   , overlays ? null+   , stdenvStages ? { lib, localSystem, crossSystem, config, overlays }@args:+     let+       inherit (+         rec {+           stageFun = step:+             last:+               { shell ? "/bin/bash"+               , overrides ? (self: super: {})+               , allowedRequisites ? null }:+                 let+                   name = "bootstrap-stage${toString step}";+                   thisStdenv = (let+                     fix' = f: let x = f x // { __unfix__ = null; }; in x;+                     makeExtensible = rattrs: fix' rattrs // { extend = null; };+                     lib = makeExtensible (self:+                         let callLibs = file: import file { lib = self; };+                         in with self; {+                           customisation =+                             callLibs <nixpkgs/lib/customisation.nix>;+                           trivial =+                             callLibs <nixpkgs/lib/trivial.nix>;+                           inherit (customisation) makeOverridable;+                           inherit (trivial) functionArgs setFunctionArgs;+                         });+                   in lib.makeOverridable ({ name ? null+                                           , preHook ? null+                                           , initialPath+                                           , shell+                                           , allowedRequisites ? null+                                           , overrides ? (self: super: {})+                                           , config+                                           , buildPlatform+                                           , hostPlatform+                                           , targetPlatform }:+                     let+                       defaultBuildInputs = [];+                       stdenv = derivation+                         ({ allowedRequisites =+                              allowedRequisites +++                              defaultBuildInputs;+                          } // {+                         inherit name;+                         inherit (buildPlatform) system;+                         builder = shell;+                       }) // {+                         inherit overrides;+                       };+                     in stdenv)) {+                     name = "${name}-stdenv-darwin";+                     inherit config shell;+                     allowedRequisites = if allowedRequisites == null+                       then null else allowedRequisites ++ [];+                     buildPlatform = localSystem;+                     hostPlatform = localSystem;+                     targetPlatform = localSystem;+                     initialPath = [];+                     overrides = self: super: (overrides self super) // { fetchurl = null; };+                   };+                 in {+                   inherit config overlays;+                   stdenv = thisStdenv;+                 };+           stage0 = stageFun 0 null {+             overrides = self: super: super;+           };+           stage1 = prevStage:+             with prevStage;+             stageFun 1 prevStage {+               allowedRequisites = [+                 (pkgs.darwin.Libsystem) # THUNK FORCE STARTS HERE+               ];+               overrides = sefl: super: {};+             };+           stagesDarwin = [ ({  }: stage0) stage1 ];+         }) stagesDarwin;+     in stagesDarwin }@args:+    let+      lib = let+        fix' = f: let x = f x // { __unfix__ = null; }; in x;+        makeExtensible = rattrs: fix' rattrs // { extend = null; };+        in makeExtensible (self:+            let callLibs = file: import file { lib = self; };+            in with self;+            {+              fixedPoints = callLibs <nixpkgs/lib/fixed-points.nix>;+              lists = callLibs <nixpkgs/lib/lists.nix>;+              inherit (fixedPoints) fix extends;+              inherit (lists) foldl' imap1;+            });++      allPackages = newArgs:+        ({ lib+         , nixpkgsFun+         , stdenv+         , allowCustomOverrides+         , noSysDirs ? null+         , config+         , overlays }:+          let+            allPackages = pkgs: super: {+              pkgs = pkgs;+              darwin = pkgs.darwin; # THUNK FORCE LOOPS: self-reference+            };+          in lib.fix (lib.foldl' (x: y: lib.extends y x) (self:+              {}) ([+              (self: super: { inherit stdenv; })+              allPackages+              (self: super: super.stdenv.overrides null super)+            ]))) ({ inherit lib nixpkgsFun; } // newArgs);++       withAllowCustomOverrides = lib.lists.imap1 (index: stageFun: prevStage:+           { allowCustomOverrides = index == 1; } // stageFun prevStage)+         (lib.lists.reverseList+          (stdenvStages {+             inherit lib localSystem crossSystem config overlays;+           }));++       go = n:+         if n == builtins.length withAllowCustomOverrides+         then {}+         else let+           succ = go (n + 1);+           in allPackages (builtins.elemAt withAllowCustomOverrides n succ);+     in go 0)++  (args // {+     inherit config overlays crossSystem;+     localSystem = { system = builtins.currentSystem; };+   })) {}
+ tests/files/test.nix view
@@ -0,0 +1,12 @@+let x = rec {++  y = 2;+  z = { w = 4; };+  v = rec {+    u = 6;+    t = [ u z.w s.q ];+  };+  s = { r = import ./goodbye.nix; q = 10; };+  p = import ./hello.nix;++}; o = 100; in [ x.v.t x.z.w x.p x.p ]
+ tests/files/with.nix view
@@ -0,0 +1,1 @@+with { x = 1; }; with { x = 2; }; y