2018-04-09 11:07:40 +02:00
|
|
|
{-# LANGUAGE BangPatterns #-}
|
2018-04-09 09:52:10 +02:00
|
|
|
{-# LANGUAGE ConstraintKinds #-}
|
2018-05-09 10:25:01 +02:00
|
|
|
{-# LANGUAGE CPP #-}
|
2018-04-09 11:07:40 +02:00
|
|
|
{-# LANGUAGE DeriveAnyClass #-}
|
|
|
|
{-# LANGUAGE DeriveDataTypeable #-}
|
|
|
|
{-# LANGUAGE DeriveGeneric #-}
|
|
|
|
{-# LANGUAGE DeriveTraversable #-}
|
2018-04-09 09:52:10 +02:00
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
2018-04-07 21:02:50 +02:00
|
|
|
{-# LANGUAGE FlexibleInstances #-}
|
2018-05-06 09:40:08 +02:00
|
|
|
{-# LANGUAGE FunctionalDependencies #-}
|
2018-04-08 00:34:54 +02:00
|
|
|
{-# LANGUAGE GADTs #-}
|
2018-04-07 21:02:50 +02:00
|
|
|
{-# LANGUAGE LambdaCase #-}
|
2018-04-09 11:07:40 +02:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2018-05-06 09:40:08 +02:00
|
|
|
{-# LANGUAGE RankNTypes #-}
|
2018-04-09 11:07:40 +02:00
|
|
|
{-# LANGUAGE StandaloneDeriving #-}
|
2018-04-07 21:02:50 +02:00
|
|
|
{-# LANGUAGE TemplateHaskell #-}
|
2018-04-08 00:34:54 +02:00
|
|
|
{-# LANGUAGE TypeApplications #-}
|
2018-04-09 11:07:40 +02:00
|
|
|
{-# LANGUAGE TypeFamilies #-}
|
|
|
|
|
|
|
|
{-# OPTIONS_GHC -Wno-orphans #-}
|
2018-05-06 09:40:08 +02:00
|
|
|
{-# OPTIONS_GHC -Wno-missing-signatures #-}
|
2018-04-09 09:52:10 +02:00
|
|
|
|
2020-07-03 01:35:30 +02:00
|
|
|
-- | The Nix expression type and supporting types.
|
|
|
|
--
|
|
|
|
-- For a brief introduction of the Nix expression language, see
|
|
|
|
-- <https://nixos.org/nix/manual/#ch-expression-language>.
|
2018-04-07 21:02:50 +02:00
|
|
|
module Nix.Expr.Types where
|
|
|
|
|
2018-05-11 21:15:18 +02:00
|
|
|
#ifdef MIN_VERSION_serialise
|
2019-03-17 22:47:38 +01:00
|
|
|
import Codec.Serialise ( Serialise )
|
|
|
|
import qualified Codec.Serialise as Ser
|
2018-05-09 01:40:56 +02:00
|
|
|
#endif
|
2018-05-06 09:40:08 +02:00
|
|
|
import Control.Applicative
|
2018-04-09 11:07:40 +02:00
|
|
|
import Control.DeepSeq
|
2018-05-06 09:40:08 +02:00
|
|
|
import Control.Monad
|
2018-04-17 21:58:56 +02:00
|
|
|
import Data.Aeson
|
2018-04-17 23:06:59 +02:00
|
|
|
import Data.Aeson.TH
|
2019-03-17 22:47:38 +01:00
|
|
|
import Data.Binary ( Binary )
|
|
|
|
import qualified Data.Binary as Bin
|
2018-04-09 11:07:40 +02:00
|
|
|
import Data.Data
|
|
|
|
import Data.Eq.Deriving
|
|
|
|
import Data.Fix
|
|
|
|
import Data.Functor.Classes
|
2018-04-17 20:33:20 +02:00
|
|
|
import Data.Hashable
|
2018-04-17 22:50:40 +02:00
|
|
|
import Data.Hashable.Lifted
|
2019-03-17 22:47:38 +01:00
|
|
|
import Data.List ( inits
|
|
|
|
, tails
|
|
|
|
)
|
|
|
|
import Data.List.NonEmpty ( NonEmpty(..) )
|
|
|
|
import qualified Data.List.NonEmpty as NE
|
|
|
|
import Data.Maybe ( fromMaybe )
|
2018-04-17 21:53:41 +02:00
|
|
|
import Data.Ord.Deriving
|
2019-03-17 22:47:38 +01:00
|
|
|
import Data.Text ( Text
|
|
|
|
, pack
|
|
|
|
, unpack
|
|
|
|
)
|
2018-04-09 11:07:40 +02:00
|
|
|
import Data.Traversable
|
|
|
|
import GHC.Exts
|
|
|
|
import GHC.Generics
|
|
|
|
import Language.Haskell.TH.Syntax
|
2018-05-06 09:40:08 +02:00
|
|
|
import Lens.Family2
|
|
|
|
import Lens.Family2.TH
|
2018-04-09 11:07:40 +02:00
|
|
|
import Nix.Atoms
|
|
|
|
import Nix.Utils
|
2018-04-11 03:57:17 +02:00
|
|
|
import Text.Megaparsec.Pos
|
2018-04-17 21:53:41 +02:00
|
|
|
import Text.Read.Deriving
|
2018-04-12 02:59:42 +02:00
|
|
|
import Text.Show.Deriving
|
2019-03-17 22:47:38 +01:00
|
|
|
import Type.Reflection ( eqTypeRep )
|
|
|
|
import qualified Type.Reflection as Reflection
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
type VarName = Text
|
|
|
|
|
2019-03-12 15:21:24 +01:00
|
|
|
hashAt :: VarName -> Lens' (AttrSet v) (Maybe v)
|
|
|
|
hashAt = flip alterF
|
|
|
|
|
2018-05-09 01:40:56 +02:00
|
|
|
-- unfortunate orphans
|
|
|
|
instance Hashable1 NonEmpty
|
|
|
|
|
2018-04-07 21:02:50 +02:00
|
|
|
-- | 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
|
2018-04-11 07:52:30 +02:00
|
|
|
= NConstant !NAtom
|
2020-07-03 01:35:30 +02:00
|
|
|
-- ^ Constants: ints, floats, bools, URIs, and null.
|
2018-04-11 07:52:30 +02:00
|
|
|
| NStr !(NString r)
|
2018-04-07 21:02:50 +02:00
|
|
|
-- ^ A string, with interpolated expressions.
|
2018-04-11 07:52:30 +02:00
|
|
|
| NSym !VarName
|
2018-04-07 21:02:50 +02:00
|
|
|
-- ^ A variable. For example, in the expression @f a@, @f@ is represented
|
|
|
|
-- as @NSym "f"@ and @a@ as @NSym "a"@.
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > NSym "x" ~ x
|
2018-04-11 07:52:30 +02:00
|
|
|
| NList ![r]
|
2018-04-07 21:02:50 +02:00
|
|
|
-- ^ A list literal.
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > NList [x,y] ~ [ x y ]
|
2019-05-16 22:30:52 +02:00
|
|
|
| NSet !NRecordType ![Binding r]
|
|
|
|
-- ^ An attribute set literal
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > NSet NRecursive [NamedVar x y _] ~ rec { x = y; }
|
|
|
|
-- > NSet NNonRecursive [Inherit Nothing [x] _] ~ { inherit x; }
|
2018-04-11 07:52:30 +02:00
|
|
|
| NLiteralPath !FilePath
|
2018-04-07 21:02:50 +02:00
|
|
|
-- ^ 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.
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > NLiteralPath "/x" ~ /x
|
|
|
|
-- > NLiteralPath "x/y" ~ x/y
|
2018-04-11 07:52:30 +02:00
|
|
|
| NEnvPath !FilePath
|
2018-04-07 21:02:50 +02:00
|
|
|
-- ^ A path which refers to something in the Nix search path (the NIX_PATH
|
|
|
|
-- environment variable. For example, @<nixpkgs/pkgs>@.
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > NEnvPath "x" ~ <x>
|
2018-04-11 07:52:30 +02:00
|
|
|
| NUnary !NUnaryOp !r
|
2018-04-07 21:02:50 +02:00
|
|
|
-- ^ Application of a unary operator to an expression.
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > NUnary NNeg x ~ - x
|
|
|
|
-- > NUnary NNot x ~ ! x
|
2018-04-11 07:52:30 +02:00
|
|
|
| NBinary !NBinaryOp !r !r
|
2018-04-07 21:02:50 +02:00
|
|
|
-- ^ Application of a binary operator to two expressions.
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > NBinary NPlus x y ~ x + y
|
|
|
|
-- > NBinary NApp f x ~ f x
|
2018-04-11 07:52:30 +02:00
|
|
|
| NSelect !r !(NAttrPath r) !(Maybe r)
|
2018-04-10 02:12:16 +02:00
|
|
|
-- ^ Dot-reference into an attribute set, optionally providing an
|
|
|
|
-- alternative if the key doesn't exist.
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > NSelect s (x :| []) Nothing ~ s.x
|
|
|
|
-- > NSelect s (x :| []) (Just y) ~ s.x or y
|
2018-04-11 07:52:30 +02:00
|
|
|
| NHasAttr !r !(NAttrPath r)
|
2018-04-10 02:12:16 +02:00
|
|
|
-- ^ Ask if a set contains a given attribute path.
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > NHasAttr s (x :| []) ~ s ? x
|
2018-04-11 07:52:30 +02:00
|
|
|
| NAbs !(Params r) !r
|
2018-04-07 21:02:50 +02:00
|
|
|
-- ^ A function literal (lambda abstraction).
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > NAbs (Param "x") y ~ x: y
|
2018-04-19 08:42:13 +02:00
|
|
|
| NLet ![Binding r] !r
|
2018-04-07 21:02:50 +02:00
|
|
|
-- ^ Evaluate the second argument after introducing the bindings.
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > 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
|
2018-04-11 07:52:30 +02:00
|
|
|
| NIf !r !r !r
|
2018-04-07 21:02:50 +02:00
|
|
|
-- ^ If-then-else statement.
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > NIf x y z ~ if x then y else z
|
2018-04-11 07:52:30 +02:00
|
|
|
| NWith !r !r
|
2018-04-07 21:02:50 +02:00
|
|
|
-- ^ Evaluate an attribute set, bring its bindings into scope, and
|
|
|
|
-- evaluate the second argument.
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > NWith x y ~ with x; y
|
2018-04-11 07:52:30 +02:00
|
|
|
| NAssert !r !r
|
2020-07-03 01:35:30 +02:00
|
|
|
-- ^ Assert that the first returns @true@ before evaluating the second.
|
|
|
|
--
|
|
|
|
-- > NAssert x y ~ assert x; y
|
2018-11-18 00:20:59 +01:00
|
|
|
| NSynHole !VarName
|
2020-07-03 01:35:30 +02:00
|
|
|
-- ^ Syntactic hole.
|
|
|
|
--
|
|
|
|
-- See <https://github.com/haskell-nix/hnix/issues/197> for context.
|
|
|
|
--
|
|
|
|
-- > NSynHole "x" ~ ^x
|
2018-04-09 11:07:40 +02:00
|
|
|
deriving (Ord, Eq, Generic, Generic1, Typeable, Data, Functor,
|
2018-08-05 21:48:44 +02:00
|
|
|
Foldable, Traversable, Show, NFData, Hashable)
|
2018-05-09 01:40:56 +02:00
|
|
|
|
|
|
|
instance Hashable1 NExprF
|
|
|
|
|
|
|
|
instance NFData1 NExprF
|
|
|
|
|
2018-05-11 21:15:18 +02:00
|
|
|
#ifdef MIN_VERSION_serialise
|
2018-05-09 01:40:56 +02:00
|
|
|
instance Serialise r => Serialise (NExprF r)
|
|
|
|
#endif
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
-- | 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
|
|
|
|
|
2018-04-08 00:34:54 +02:00
|
|
|
instance Lift (Fix NExprF) where
|
2019-03-17 22:47:38 +01:00
|
|
|
lift = dataToExpQ $ \b ->
|
|
|
|
case Reflection.typeOf b `eqTypeRep` Reflection.typeRep @Text of
|
|
|
|
Just HRefl -> Just [| pack $(liftString $ unpack b) |]
|
|
|
|
Nothing -> Nothing
|
2018-04-08 00:34:54 +02:00
|
|
|
|
2018-04-07 21:02:50 +02:00
|
|
|
-- | The monomorphic expression type is a fixed point of the polymorphic one.
|
|
|
|
type NExpr = Fix NExprF
|
|
|
|
|
2018-05-11 21:15:18 +02:00
|
|
|
#ifdef MIN_VERSION_serialise
|
2018-04-12 05:19:59 +02:00
|
|
|
instance Serialise NExpr
|
2018-05-09 01:40:56 +02:00
|
|
|
#endif
|
2018-04-12 05:19:59 +02:00
|
|
|
|
2018-04-07 21:02:50 +02:00
|
|
|
-- | A single line of the bindings section of a let expression or of a set.
|
|
|
|
data Binding r
|
2018-05-09 10:25:01 +02:00
|
|
|
= NamedVar !(NAttrPath r) !r !SourcePos
|
2020-07-03 01:35:30 +02:00
|
|
|
-- ^ An explicit naming.
|
|
|
|
--
|
|
|
|
-- > NamedVar (StaticKey "x" :| [StaticKey "y"]) z SourcePos{} ~ x.y = z;
|
2018-05-09 10:25:01 +02:00
|
|
|
| Inherit !(Maybe r) ![NKeyName r] !SourcePos
|
2018-04-07 21:02:50 +02:00
|
|
|
-- ^ Using a name already in scope, such as @inherit x;@ which is shorthand
|
2018-05-09 10:25:01 +02:00
|
|
|
-- for @x = x;@ or @inherit (x) y;@ which means @y = x.y;@. The
|
2020-07-03 01:35:30 +02:00
|
|
|
-- @unsafeGetAttrPos@ for every name so inherited is the position of the
|
2018-05-09 10:25:01 +02:00
|
|
|
-- first name, whether that be the first argument to this constructor, or
|
|
|
|
-- the first member of the list in the second argument.
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > Inherit Nothing [StaticKey "x"] SourcePos{} ~ inherit x;
|
|
|
|
-- > Inherit (Just x) [] SourcePos{} ~ inherit (x);
|
2018-04-09 11:07:40 +02:00
|
|
|
deriving (Generic, Generic1, Typeable, Data, Ord, Eq, Functor,
|
2018-08-05 21:48:44 +02:00
|
|
|
Foldable, Traversable, Show, NFData, Hashable)
|
2018-05-09 01:40:56 +02:00
|
|
|
|
|
|
|
instance Hashable1 Binding
|
|
|
|
|
|
|
|
instance NFData1 Binding
|
|
|
|
|
2018-05-11 21:15:18 +02:00
|
|
|
#ifdef MIN_VERSION_serialise
|
2018-05-09 01:40:56 +02:00
|
|
|
instance Serialise r => Serialise (Binding r)
|
|
|
|
#endif
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
-- | @Params@ represents all the ways the formal parameters to a
|
|
|
|
-- function can be represented.
|
|
|
|
data Params r
|
2018-04-11 07:52:30 +02:00
|
|
|
= Param !VarName
|
2018-04-07 21:02:50 +02:00
|
|
|
-- ^ For functions with a single named argument, such as @x: x + 1@.
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > Param "x" ~ x
|
2018-04-11 07:52:30 +02:00
|
|
|
| ParamSet !(ParamSet r) !Bool !(Maybe VarName)
|
2018-04-07 21:02:50 +02:00
|
|
|
-- ^ 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.
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > ParamSet [("x",Nothing)] False Nothing ~ { x }
|
|
|
|
-- > ParamSet [("x",Just y)] True (Just "s") ~ s@{ x ? y, ... }
|
2018-04-09 11:07:40 +02:00
|
|
|
deriving (Ord, Eq, Generic, Generic1, Typeable, Data, Functor, Show,
|
2018-05-09 01:40:56 +02:00
|
|
|
Foldable, Traversable, NFData, Hashable)
|
|
|
|
|
|
|
|
instance Hashable1 Params
|
|
|
|
|
|
|
|
instance NFData1 Params
|
|
|
|
|
2018-05-11 21:15:18 +02:00
|
|
|
#ifdef MIN_VERSION_serialise
|
2018-05-09 01:40:56 +02:00
|
|
|
instance Serialise r => Serialise (Params r)
|
|
|
|
#endif
|
2018-04-07 21:02:50 +02:00
|
|
|
|
2018-04-10 20:58:08 +02:00
|
|
|
-- This uses an association list because nix XML serialization preserves the
|
|
|
|
-- order of the param set.
|
|
|
|
type ParamSet r = [(VarName, Maybe r)]
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
instance IsString (Params r) where
|
|
|
|
fromString = Param . fromString
|
|
|
|
|
|
|
|
-- | 'Antiquoted' represents an expression that is either
|
|
|
|
-- antiquoted (surrounded by ${...}) or plain (not antiquoted).
|
2020-07-03 01:35:30 +02:00
|
|
|
data Antiquoted (v :: *) (r :: *)
|
|
|
|
= 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
|
2018-04-17 21:53:41 +02:00
|
|
|
deriving (Ord, Eq, Generic, Generic1, Typeable, Data, Functor, Foldable,
|
2018-05-09 01:40:56 +02:00
|
|
|
Traversable, Show, Read, NFData, Hashable)
|
|
|
|
|
|
|
|
instance Hashable v => Hashable1 (Antiquoted v)
|
2018-04-17 22:50:40 +02:00
|
|
|
|
|
|
|
instance Hashable2 Antiquoted where
|
2019-03-17 22:47:38 +01:00
|
|
|
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
|
2018-05-09 01:40:56 +02:00
|
|
|
|
|
|
|
instance NFData v => NFData1 (Antiquoted v)
|
|
|
|
|
2018-05-11 21:15:18 +02:00
|
|
|
#ifdef MIN_VERSION_serialise
|
2018-05-09 01:40:56 +02:00
|
|
|
instance (Serialise v, Serialise r) => Serialise (Antiquoted v r)
|
|
|
|
#endif
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
-- | An 'NString' is a list of things that are either a plain string
|
|
|
|
-- or an antiquoted expression. After the antiquotes have been evaluated,
|
2019-08-04 22:45:02 +02:00
|
|
|
-- the final string is constructed by concatenating all the parts.
|
2018-04-07 21:02:50 +02:00
|
|
|
data NString r
|
2018-04-11 07:52:30 +02:00
|
|
|
= DoubleQuoted ![Antiquoted Text r]
|
2018-04-07 21:02:50 +02:00
|
|
|
-- ^ Strings wrapped with double-quotes (") can contain literal newline
|
|
|
|
-- characters, but the newlines are preserved and no indentation is stripped.
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > DoubleQuoted [Plain "x",Antiquoted y] ~ "x${y}"
|
2018-04-11 21:06:14 +02:00
|
|
|
| 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.
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > Indented 1 [Plain "x"] ~ '' x''
|
|
|
|
-- >
|
|
|
|
-- > Indented 0 [EscapedNewline] ~ ''''\n''
|
|
|
|
-- >
|
|
|
|
-- > Indented 0 [Plain "x\n ",Antiquoted y] ~ ''
|
|
|
|
-- > x
|
|
|
|
-- > ${y}''
|
2018-04-17 21:53:41 +02:00
|
|
|
deriving (Eq, Ord, Generic, Generic1, Typeable, Data, Functor, Foldable,
|
2018-05-09 01:40:56 +02:00
|
|
|
Traversable, Show, Read, NFData, Hashable)
|
|
|
|
|
|
|
|
instance Hashable1 NString
|
|
|
|
|
|
|
|
instance NFData1 NString
|
|
|
|
|
2018-05-11 21:15:18 +02:00
|
|
|
#ifdef MIN_VERSION_serialise
|
2018-05-09 01:40:56 +02:00
|
|
|
instance Serialise r => Serialise (NString r)
|
|
|
|
#endif
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
-- | For the the 'IsString' instance, we use a plain doublequoted string.
|
|
|
|
instance IsString (NString r) where
|
2019-03-17 22:47:38 +01:00
|
|
|
fromString "" = DoubleQuoted []
|
2018-04-07 21:02:50 +02:00
|
|
|
fromString string = DoubleQuoted [Plain $ pack string]
|
|
|
|
|
2018-04-10 01:11:31 +02:00
|
|
|
-- | A 'KeyName' is something that can appear on the left side of an
|
2018-04-07 21:02:50 +02:00
|
|
|
-- 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
|
2018-04-11 07:52:30 +02:00
|
|
|
= DynamicKey !(Antiquoted (NString r) r)
|
2020-07-03 01:35:30 +02:00
|
|
|
-- ^
|
|
|
|
-- > DynamicKey (Plain (DoubleQuoted [Plain "x"])) ~ "x"
|
|
|
|
-- > DynamicKey (Antiquoted x) ~ ${x}
|
|
|
|
-- > DynamicKey (Plain (DoubleQuoted [Antiquoted x])) ~ "${x}"
|
2018-05-09 10:25:01 +02:00
|
|
|
| StaticKey !VarName
|
2020-07-03 01:35:30 +02:00
|
|
|
-- ^
|
|
|
|
-- > StaticKey "x" ~ x
|
2018-08-05 21:48:44 +02:00
|
|
|
deriving (Eq, Ord, Generic, Typeable, Data, Show, Read, NFData, Hashable)
|
2018-05-09 01:40:56 +02:00
|
|
|
|
2018-05-11 21:15:18 +02:00
|
|
|
#ifdef MIN_VERSION_serialise
|
2018-05-09 01:40:56 +02:00
|
|
|
instance Serialise r => Serialise (NKeyName r)
|
2018-04-12 02:59:42 +02:00
|
|
|
|
|
|
|
instance Serialise Pos where
|
2019-03-17 22:47:38 +01:00
|
|
|
encode x = Ser.encode (unPos x)
|
|
|
|
decode = mkPos <$> Ser.decode
|
2018-04-12 02:59:42 +02:00
|
|
|
|
|
|
|
instance Serialise SourcePos where
|
2019-03-17 22:47:38 +01:00
|
|
|
encode (SourcePos f l c) = Ser.encode f <> Ser.encode l <> Ser.encode c
|
|
|
|
decode = SourcePos <$> Ser.decode <*> Ser.decode <*> Ser.decode
|
2018-05-09 01:40:56 +02:00
|
|
|
#endif
|
2018-04-09 11:07:40 +02:00
|
|
|
|
2018-04-17 20:33:20 +02:00
|
|
|
instance Hashable Pos where
|
2019-03-17 22:47:38 +01:00
|
|
|
hashWithSalt salt x = hashWithSalt salt (unPos x)
|
2018-04-17 20:33:20 +02:00
|
|
|
|
|
|
|
instance Hashable SourcePos where
|
2019-03-17 22:47:38 +01:00
|
|
|
hashWithSalt salt (SourcePos f l c) =
|
|
|
|
salt `hashWithSalt` f `hashWithSalt` l `hashWithSalt` c
|
2018-04-17 20:33:20 +02:00
|
|
|
|
2018-04-09 11:07:40 +02:00
|
|
|
instance Generic1 NKeyName where
|
2018-04-27 02:13:22 +02:00
|
|
|
type Rep1 NKeyName = NKeyName
|
2018-04-09 11:07:40 +02:00
|
|
|
from1 = id
|
|
|
|
to1 = id
|
2018-04-17 23:06:59 +02:00
|
|
|
|
2018-04-09 11:07:40 +02:00
|
|
|
instance NFData1 NKeyName where
|
2019-03-17 22:47:38 +01:00
|
|
|
liftRnf _ (StaticKey !_ ) = ()
|
|
|
|
liftRnf _ (DynamicKey (Plain !_) ) = ()
|
|
|
|
liftRnf _ (DynamicKey EscapedNewline) = ()
|
|
|
|
liftRnf k (DynamicKey (Antiquoted r)) = k r
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
-- | Most key names are just static text, so this instance is convenient.
|
|
|
|
instance IsString (NKeyName r) where
|
2018-05-09 10:25:01 +02:00
|
|
|
fromString = StaticKey . fromString
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
instance Eq1 NKeyName where
|
|
|
|
liftEq eq (DynamicKey a) (DynamicKey b) = liftEq2 (liftEq eq) eq a b
|
2019-03-17 22:47:38 +01:00
|
|
|
liftEq _ (StaticKey a) (StaticKey b) = a == b
|
|
|
|
liftEq _ _ _ = False
|
2018-04-07 21:02:50 +02:00
|
|
|
|
2020-09-13 17:46:25 +02:00
|
|
|
-- | @since 0.10.1
|
2020-09-12 22:30:38 +02:00
|
|
|
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
|
|
|
|
|
2018-04-17 22:50:40 +02:00
|
|
|
instance Hashable1 NKeyName where
|
|
|
|
liftHashWithSalt h salt (DynamicKey a) =
|
2019-03-17 22:47:38 +01:00
|
|
|
liftHashWithSalt2 (liftHashWithSalt h) h (salt `hashWithSalt` (0 :: Int)) a
|
2018-05-09 10:25:01 +02:00
|
|
|
liftHashWithSalt _ salt (StaticKey n) =
|
2019-03-17 22:47:38 +01:00
|
|
|
salt `hashWithSalt` (1 :: Int) `hashWithSalt` n
|
2018-04-17 22:50:40 +02:00
|
|
|
|
2018-04-07 21:02:50 +02:00
|
|
|
-- 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
|
2019-03-17 22:47:38 +01:00
|
|
|
DynamicKey a -> showsUnaryWith
|
|
|
|
(liftShowsPrec2 (liftShowsPrec sp sl) (liftShowList sp sl) sp sl)
|
|
|
|
"DynamicKey"
|
|
|
|
p
|
|
|
|
a
|
2018-05-09 10:25:01 +02:00
|
|
|
StaticKey t -> showsUnaryWith showsPrec "StaticKey" p t
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
-- 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
|
2019-03-17 22:47:38 +01:00
|
|
|
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)
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
-- | A selector (for example in a @let@ or an attribute set) is made up
|
|
|
|
-- of strung-together key names.
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > StaticKey "x" :| [DynamicKey (Antiquoted y)] ~ x.${y}
|
2018-04-17 21:46:41 +02:00
|
|
|
type NAttrPath r = NonEmpty (NKeyName r)
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
-- | There are two unary operations: logical not and integer negation.
|
2020-07-03 01:35:30 +02:00
|
|
|
data NUnaryOp
|
|
|
|
= NNeg -- ^ @-@
|
|
|
|
| NNot -- ^ @!@
|
2018-05-14 22:19:15 +02:00
|
|
|
deriving (Eq, Ord, Enum, Bounded, Generic, Typeable, Data, Show, Read,
|
|
|
|
NFData, Hashable)
|
2018-05-09 01:40:56 +02:00
|
|
|
|
2018-05-11 21:15:18 +02:00
|
|
|
#ifdef MIN_VERSION_serialise
|
2018-05-09 01:40:56 +02:00
|
|
|
instance Serialise NUnaryOp
|
|
|
|
#endif
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
-- | Binary operators expressible in the nix language.
|
|
|
|
data NBinaryOp
|
2020-07-03 01:35:30 +02:00
|
|
|
= 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 attribute sets (@//@)
|
|
|
|
| NPlus -- ^ Addition (@+@)
|
|
|
|
| NMinus -- ^ Subtraction (@-@)
|
|
|
|
| NMult -- ^ Multiplication (@*@)
|
|
|
|
| NDiv -- ^ Division (@/@)
|
|
|
|
| NConcat -- ^ List concatenation (@++@)
|
2018-04-10 01:11:31 +02:00
|
|
|
| NApp -- ^ Apply a function to an argument.
|
2020-07-03 01:35:30 +02:00
|
|
|
--
|
|
|
|
-- > NBinary NApp f x ~ f x
|
2018-05-14 22:19:15 +02:00
|
|
|
deriving (Eq, Ord, Enum, Bounded, Generic, Typeable, Data, Show, Read,
|
|
|
|
NFData, Hashable)
|
2018-05-09 01:40:56 +02:00
|
|
|
|
2018-05-11 21:15:18 +02:00
|
|
|
#ifdef MIN_VERSION_serialise
|
2018-05-09 01:40:56 +02:00
|
|
|
instance Serialise NBinaryOp
|
|
|
|
#endif
|
2018-04-07 21:02:50 +02:00
|
|
|
|
2020-07-03 01:35:30 +02:00
|
|
|
-- | 'NRecordType' distinguishes between recursive and non-recursive attribute
|
|
|
|
-- sets.
|
2019-05-16 22:30:52 +02:00
|
|
|
data NRecordType
|
2020-07-03 01:35:30 +02:00
|
|
|
= NNonRecursive -- ^ > { ... }
|
|
|
|
| NRecursive -- ^ > rec { ... }
|
2019-05-16 22:30:52 +02:00
|
|
|
deriving (Eq, Ord, Enum, Bounded, Generic, Typeable, Data, Show, Read,
|
|
|
|
NFData, Hashable)
|
|
|
|
|
|
|
|
#ifdef MIN_VERSION_serialise
|
|
|
|
instance Serialise NRecordType
|
|
|
|
#endif
|
|
|
|
|
2018-04-07 21:02:50 +02:00
|
|
|
-- | Get the name out of the parameter (there might be none).
|
|
|
|
paramName :: Params r -> Maybe VarName
|
2019-03-17 22:47:38 +01:00
|
|
|
paramName (Param n ) = Just n
|
2018-04-07 21:02:50 +02:00
|
|
|
paramName (ParamSet _ _ n) = n
|
|
|
|
|
|
|
|
$(deriveEq1 ''NExprF)
|
|
|
|
$(deriveEq1 ''NString)
|
|
|
|
$(deriveEq1 ''Binding)
|
|
|
|
$(deriveEq1 ''Params)
|
|
|
|
$(deriveEq1 ''Antiquoted)
|
|
|
|
$(deriveEq2 ''Antiquoted)
|
|
|
|
|
2020-09-12 22:30:38 +02:00
|
|
|
$(deriveOrd1 ''NExprF)
|
2018-04-17 21:53:41 +02:00
|
|
|
$(deriveOrd1 ''NString)
|
2020-09-12 22:30:38 +02:00
|
|
|
$(deriveOrd1 ''Binding)
|
2018-04-17 21:53:41 +02:00
|
|
|
$(deriveOrd1 ''Params)
|
|
|
|
$(deriveOrd1 ''Antiquoted)
|
|
|
|
$(deriveOrd2 ''Antiquoted)
|
|
|
|
|
|
|
|
$(deriveRead1 ''NString)
|
|
|
|
$(deriveRead1 ''Params)
|
|
|
|
$(deriveRead1 ''Antiquoted)
|
|
|
|
$(deriveRead2 ''Antiquoted)
|
|
|
|
|
2018-04-07 21:02:50 +02:00
|
|
|
$(deriveShow1 ''NExprF)
|
|
|
|
$(deriveShow1 ''NString)
|
|
|
|
$(deriveShow1 ''Params)
|
|
|
|
$(deriveShow1 ''Binding)
|
|
|
|
$(deriveShow1 ''Antiquoted)
|
|
|
|
$(deriveShow2 ''Antiquoted)
|
|
|
|
|
2020-07-03 01:35:30 +02:00
|
|
|
--x $(deriveJSON1 defaultOptions ''NExprF)
|
2018-04-17 23:06:59 +02:00
|
|
|
$(deriveJSON1 defaultOptions ''NString)
|
|
|
|
$(deriveJSON1 defaultOptions ''Params)
|
2020-07-03 01:35:30 +02:00
|
|
|
--x $(deriveJSON1 defaultOptions ''Binding)
|
2018-04-17 23:06:59 +02:00
|
|
|
$(deriveJSON1 defaultOptions ''Antiquoted)
|
|
|
|
$(deriveJSON2 defaultOptions ''Antiquoted)
|
|
|
|
|
2018-04-11 03:57:17 +02:00
|
|
|
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
|
2019-03-17 22:47:38 +01:00
|
|
|
put x = Bin.put (unPos x)
|
|
|
|
get = mkPos <$> Bin.get
|
2018-04-11 03:57:17 +02:00
|
|
|
instance Binary SourcePos
|
|
|
|
instance Binary a => Binary (NKeyName a)
|
|
|
|
instance Binary a => Binary (Params a)
|
|
|
|
instance Binary NAtom
|
|
|
|
instance Binary NUnaryOp
|
|
|
|
instance Binary NBinaryOp
|
2019-05-16 22:30:52 +02:00
|
|
|
instance Binary NRecordType
|
2018-04-11 03:57:17 +02:00
|
|
|
instance Binary a => Binary (NExprF a)
|
|
|
|
|
2018-04-17 21:58:56 +02:00
|
|
|
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
|
2019-03-17 22:47:38 +01:00
|
|
|
toJSON x = toJSON (unPos x)
|
2018-04-17 21:58:56 +02:00
|
|
|
instance ToJSON SourcePos
|
|
|
|
instance ToJSON a => ToJSON (NKeyName a)
|
|
|
|
instance ToJSON a => ToJSON (Params a)
|
|
|
|
instance ToJSON NAtom
|
|
|
|
instance ToJSON NUnaryOp
|
|
|
|
instance ToJSON NBinaryOp
|
2019-05-16 22:30:52 +02:00
|
|
|
instance ToJSON NRecordType
|
2018-04-17 21:58:56 +02:00
|
|
|
instance ToJSON a => ToJSON (NExprF a)
|
|
|
|
|
|
|
|
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
|
2019-03-17 22:47:38 +01:00
|
|
|
parseJSON = fmap mkPos . parseJSON
|
2018-04-17 21:58:56 +02:00
|
|
|
instance FromJSON SourcePos
|
|
|
|
instance FromJSON a => FromJSON (NKeyName a)
|
|
|
|
instance FromJSON a => FromJSON (Params a)
|
|
|
|
instance FromJSON NAtom
|
|
|
|
instance FromJSON NUnaryOp
|
|
|
|
instance FromJSON NBinaryOp
|
2019-05-16 22:30:52 +02:00
|
|
|
instance FromJSON NRecordType
|
2018-04-17 21:58:56 +02:00
|
|
|
instance FromJSON a => FromJSON (NExprF a)
|
|
|
|
|
2018-05-06 09:40:08 +02:00
|
|
|
$(makeTraversals ''NExprF)
|
|
|
|
$(makeTraversals ''Binding)
|
|
|
|
$(makeTraversals ''Params)
|
|
|
|
$(makeTraversals ''Antiquoted)
|
|
|
|
$(makeTraversals ''NString)
|
|
|
|
$(makeTraversals ''NKeyName)
|
|
|
|
$(makeTraversals ''NUnaryOp)
|
|
|
|
$(makeTraversals ''NBinaryOp)
|
|
|
|
|
2020-07-03 01:35:30 +02:00
|
|
|
--x $(makeLenses ''Fix)
|
2018-05-06 09:40:08 +02:00
|
|
|
|
|
|
|
class NExprAnn ann g | g -> ann where
|
|
|
|
fromNExpr :: g r -> (NExprF r, ann)
|
|
|
|
toNExpr :: (NExprF r, ann) -> g r
|
|
|
|
|
2019-03-17 22:47:38 +01:00
|
|
|
ekey
|
|
|
|
:: NExprAnn ann g
|
|
|
|
=> NonEmpty Text
|
|
|
|
-> SourcePos
|
|
|
|
-> Lens' (Fix g) (Maybe (Fix g))
|
2019-05-16 22:30:52 +02:00
|
|
|
ekey keys pos f e@(Fix x) | (NSet NNonRecursive xs, ann) <- fromNExpr x = case go xs of
|
2019-03-17 22:47:38 +01:00
|
|
|
((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
|
2019-05-16 22:30:52 +02:00
|
|
|
in Fix (toNExpr (NSet NNonRecursive (entry : xs), ann))
|
2019-03-17 22:47:38 +01:00
|
|
|
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)
|
2020-09-18 14:54:39 +02:00
|
|
|
pure (v, rest)
|
2018-05-06 09:40:08 +02:00
|
|
|
|
2018-05-09 10:25:01 +02:00
|
|
|
ekey _ _ f e = fromMaybe e <$> f Nothing
|
2018-05-06 09:40:08 +02:00
|
|
|
|
2018-04-07 21:02:50 +02:00
|
|
|
stripPositionInfo :: NExpr -> NExpr
|
|
|
|
stripPositionInfo = transport phi
|
2019-03-17 22:47:38 +01:00
|
|
|
where
|
2019-05-16 22:30:52 +02:00
|
|
|
phi (NSet recur binds) = NSet recur (map go binds)
|
2019-03-17 22:47:38 +01:00
|
|
|
phi (NLet binds body) = NLet (map go binds) body
|
|
|
|
phi x = x
|
2018-04-07 21:02:50 +02:00
|
|
|
|
2019-03-17 22:47:38 +01:00
|
|
|
go (NamedVar path r _pos) = NamedVar path r nullPos
|
|
|
|
go (Inherit ms names _pos) = Inherit ms names nullPos
|
2018-04-07 21:02:50 +02:00
|
|
|
|
2018-05-09 10:25:01 +02:00
|
|
|
nullPos :: SourcePos
|
|
|
|
nullPos = SourcePos "<string>" (mkPos 1) (mkPos 1)
|