The Megaparsec version of Parser.hs is at least compiling

This commit is contained in:
John Wiegley 2018-04-09 16:11:31 -07:00
parent b1fb73d363
commit 9beb9364e0
10 changed files with 175 additions and 244 deletions

View file

@ -248,7 +248,7 @@ unsafeGetAttrPos x y = force x $ \x' -> force y $ \y' -> case (x', y') of
Nothing ->
throwError $ "unsafeGetAttrPos: field '" ++ Text.unpack key
++ "' does not exist in attr set: " ++ show apos
Just delta -> return $ posFromDelta @m delta
Just delta -> return $ posFromSourcePos @m delta
(x, y) -> throwError $ "Invalid types for builtin.unsafeGetAttrPos: "
++ show (void x, void y)

View file

@ -208,7 +208,7 @@ evalBinds :: forall e v t m. MonadNixEval e v t m
=> Bool
-> Bool
-> [Binding (m v)]
-> m (AttrSet t, AttrSet Delta)
-> m (AttrSet t, AttrSet SourcePos)
evalBinds allowDynamic recursive =
buildResult . concat <=< mapM go . moveOverridesLast
where
@ -216,7 +216,7 @@ evalBinds allowDynamic recursive =
partition (\case NamedVar [StaticKey "__overrides" _] _ -> True
_ -> False)
go :: Binding (m v) -> m [([Text], Maybe Delta, m v)]
go :: Binding (m v) -> m [([Text], Maybe SourcePos, m v)]
go (NamedVar [StaticKey "__overrides" _] finalValue) =
finalValue >>= \v -> case wantVal v of
Just (o', p') ->
@ -226,7 +226,7 @@ evalBinds allowDynamic recursive =
++ show v
go (NamedVar pathExpr finalValue) = do
let go :: NAttrPath (m v) -> m ([Text], Maybe Delta, m v)
let go :: NAttrPath (m v) -> m ([Text], Maybe SourcePos, m v)
go = \case
[] -> pure ([], Nothing, finalValue)
h : t -> evalSetterKeyName allowDynamic h >>= \case
@ -257,8 +257,8 @@ evalBinds allowDynamic recursive =
++ show (void name)
Just v -> force v pure)
buildResult :: [([Text], Maybe Delta, m v)]
-> m (AttrSet t, AttrSet Delta)
buildResult :: [([Text], Maybe SourcePos, m v)]
-> m (AttrSet t, AttrSet SourcePos)
buildResult bindings = do
s <- foldM insert M.empty bindings
scope <- currentScopes @_ @t
@ -285,7 +285,7 @@ evalSelect aset attr =
where
extract v [] = return $ Right v
extract x (k:ks) =
case wantVal @_ @(AttrSet t, AttrSet Delta) x of
case wantVal @_ @(AttrSet t, AttrSet SourcePos) x of
Just (s, p) -> case M.lookup k s of
Just v -> force v $ extract ?? ks
Nothing -> return $ Left (ofVal (s, p), k:ks)
@ -299,20 +299,20 @@ evalSelector allowDynamic =
-- | Evaluate a component of an attribute path in a context where we are
-- *retrieving* a value
evalGetterKeyName :: MonadEval v m
=> Bool -> NKeyName (m v) -> m (Text, Maybe Delta)
=> Bool -> NKeyName (m v) -> m (Text, Maybe SourcePos)
evalGetterKeyName canBeDynamic
| canBeDynamic = evalKeyNameDynamicNotNull
| otherwise = evalKeyNameStatic
evalKeyNameStatic :: forall v m. MonadEval v m
=> NKeyName (m v) -> m (Text, Maybe Delta)
=> NKeyName (m v) -> m (Text, Maybe SourcePos)
evalKeyNameStatic = \case
StaticKey k p -> pure (k, p)
DynamicKey _ ->
evalError @v "dynamic attribute not allowed in this context"
evalKeyNameDynamicNotNull :: forall v m. MonadEval v m
=> NKeyName (m v) -> m (Text, Maybe Delta)
=> NKeyName (m v) -> m (Text, Maybe SourcePos)
evalKeyNameDynamicNotNull = evalKeyNameDynamicNullable >=> \case
(Nothing, _) ->
evalError @v "value is null while a string was expected"
@ -321,14 +321,15 @@ evalKeyNameDynamicNotNull = evalKeyNameDynamicNullable >=> \case
-- | Evaluate a component of an attribute path in a context where we are
-- *binding* a value
evalSetterKeyName :: MonadEval v m
=> Bool -> NKeyName (m v) -> m (Maybe Text, Maybe Delta)
=> Bool -> NKeyName (m v) -> m (Maybe Text, Maybe SourcePos)
evalSetterKeyName canBeDynamic
| canBeDynamic = evalKeyNameDynamicNullable
| otherwise = fmap (first Just) . evalKeyNameStatic
-- | Returns Nothing iff the key value is null
evalKeyNameDynamicNullable :: forall v m. MonadEval v m
=> NKeyName (m v) -> m (Maybe Text, Maybe Delta)
=> NKeyName (m v)
-> m (Maybe Text, Maybe SourcePos)
evalKeyNameDynamicNullable = \case
StaticKey k p -> pure (Just k, p)
DynamicKey k -> runAntiquoted (embedMText <=< assembleString) id k

View file

@ -90,7 +90,7 @@ instance ConvertValue (NValue m) [NThunk m] where
wantVal = \case NVList l -> Just l; _ -> Nothing
instance ConvertValue (NValue m)
(AttrSet (NThunk m), AttrSet Delta) where
(AttrSet (NThunk m), AttrSet SourcePos) where
ofVal (s, p) = NVSet s p
wantVal = \case NVSet s p -> Just (s, p); _ -> Nothing
@ -111,7 +111,7 @@ instance MonadExec e m => MonadEval (NValue m) m where
Compose (Ann (SrcSpan delta _) _):_ <-
asks (mapMaybe (either (const Nothing) Just)
. view @_ @Frames hasLens)
return $ posFromDelta delta
return $ posFromSourcePos delta
evalConstant = pure . NVConstant
evalString = pure . uncurry NVStr

View file

@ -13,7 +13,7 @@ import Data.Monoid
import Data.Text (Text)
import Nix.Atoms
import Nix.Expr.Types
import Nix.Utils
-- import Nix.Utils
-- | Make an integer literal expression.
mkInt :: Integer -> NExpr
@ -102,9 +102,6 @@ mkOper2 op a = Fix . NBinary op a
mkParamset :: [(Text, Maybe NExpr)] -> Bool -> Params NExpr
mkParamset params variadic = ParamSet (M.fromList params) variadic Nothing
mkApp :: NExpr -> NExpr -> NExpr
mkApp e = Fix . NApp e
mkRecSet :: [Binding NExpr] -> NExpr
mkRecSet = Fix . NRecSet
@ -129,6 +126,7 @@ mkIf e1 e2 = Fix . NIf e1 e2
mkFunction :: Params NExpr -> NExpr -> NExpr
mkFunction params = Fix . NAbs params
{-
mkDot :: NExpr -> Text -> NExpr
mkDot e key = mkDots e [key]
@ -140,6 +138,7 @@ mkDots (Fix (NSelect e keys' x)) keys =
-- 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
-}
-- | An `inherit` clause without an expression to pull from.
inherit :: [NKeyName e] -> Binding e
@ -195,10 +194,10 @@ recAttrsE pairs = Fix $ NRecSet (map (uncurry bindTo) pairs)
mkNot :: NExpr -> NExpr
mkNot = Fix . NUnary NNot
-- | Dot-reference into an attribute set.
(!.) :: NExpr -> Text -> NExpr
(!.) = mkDot
infixl 8 !.
-- -- | 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)
@ -225,7 +224,7 @@ e1 $++ e2 = mkBinop NConcat e1 e2
-- | Function application expression.
(@@) :: NExpr -> NExpr -> NExpr
(@@) = mkApp
f @@ arg = mkBinop NApp f arg
infixl 1 @@
-- | Lambda shorthand.
@ -233,3 +232,7 @@ infixl 1 @@
(==>) = mkFunction
infixr 1 ==>
(@.) :: NExpr -> Text -> NExpr
obj @. name = mkBinop NSelect obj (mkSym name)
infixl 2 @.

View file

@ -28,15 +28,15 @@ import Data.Data
import Data.Eq.Deriving
import Data.Fix
import Data.Functor.Classes
import qualified Data.HashMap.Strict.InsOrd as InsOrd
import Data.HashMap.Strict.InsOrd (InsOrdHashMap)
import qualified Data.HashMap.Strict.InsOrd as InsOrd
import Data.Text (Text, pack, unpack)
import Data.Traversable
import GHC.Exts
import GHC.Generics
import Language.Haskell.TH.Syntax
import Nix.Atoms
import Nix.Parser.Library (Delta(..))
import Nix.Parser.Library (SourcePos(..))
import Nix.Utils
import Text.Show.Deriving
import Type.Reflection (eqTypeRep)
@ -73,15 +73,8 @@ data NExprF 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).
| NApp r r
-- ^ Apply a function to an argument.
| NLet [Binding r] r
-- ^ Evaluate the second argument after introducing the bindings.
| NIf r r r
@ -170,7 +163,7 @@ instance IsString (NString r) where
fromString "" = DoubleQuoted []
fromString string = DoubleQuoted [Plain $ pack string]
-- | A 'KeyName' is something that can appear at the right side of an
-- | 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@.
--
@ -191,7 +184,7 @@ instance IsString (NString r) where
-- parser still considers it a 'DynamicKey' for simplicity.
data NKeyName r
= DynamicKey (Antiquoted (NString r) r)
| StaticKey VarName (Maybe Delta)
| StaticKey VarName (Maybe SourcePos)
deriving (Eq, Ord, Generic, Typeable, Data, Show, NFData)
instance Generic1 NKeyName where
@ -202,7 +195,6 @@ instance NFData1 NKeyName where
liftRnf _ (StaticKey !_ !_) = ()
liftRnf _ (DynamicKey (Plain !_)) = ()
liftRnf k (DynamicKey (Antiquoted r)) = k r
instance NFData Delta
-- | Most key names are just static text, so this instance is convenient.
instance IsString (NKeyName r) where
@ -248,21 +240,25 @@ data NUnaryOp = NNeg | NNot
-- | 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 (++)
= 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.
| NSelect -- ^ Dot-reference into an attribute set, optionally providing an
-- alternative if the key doesn't exist.
| NHasAttr -- ^ Ask if a set contains a given attribute path.
deriving (Eq, Ord, Generic, Typeable, Data, Show, NFData)
-- | Get the name out of the parameter (there might be none).
@ -290,7 +286,6 @@ stripPositionInfo = transport phi
phi (NSet binds) = NSet (map go binds)
phi (NRecSet binds) = NRecSet (map go binds)
phi (NLet binds body) = NLet (map go binds) body
phi (NSelect s attr alt) = NSelect s (map clear attr) alt
phi x = x
go (NamedVar path r) = NamedVar (map clear path) r
@ -311,5 +306,5 @@ type Convertible v t =
ConvertValue v Text,
ConvertValue v (Maybe Text), -- text or null
ConvertValue v [t],
ConvertValue v (AttrSet t, AttrSet Delta),
ConvertValue v (AttrSet t, AttrSet SourcePos),
ConvertValue v (AttrSet t))

View file

@ -16,7 +16,7 @@
--
module Nix.Expr.Types.Annotated
( module Nix.Expr.Types.Annotated
, Delta(..)
, SourcePos(..)
)where
import Control.DeepSeq
@ -28,12 +28,13 @@ import Data.Semigroup
import Data.Text (Text, pack)
import GHC.Generics
import Nix.Expr.Types
import Nix.Parser.Library (Delta(..))
import Nix.Parser.Library (SourcePos(..))
import Text.Show.Deriving
import Text.Megaparsec (unPos)
-- | A location in a source file
data SrcSpan = SrcSpan{ spanBegin :: Delta
, spanEnd :: Delta
data SrcSpan = SrcSpan{ spanBegin :: SourcePos
, spanEnd :: SourcePos
}
deriving (Ord, Eq, Generic, Typeable, Data, Show, NFData)
@ -72,10 +73,6 @@ pattern AnnE ann a = Fix (Compose (Ann ann a))
stripAnnotation :: Functor f => Fix (AnnF ann f) -> Fix f
stripAnnotation = ana (annotated . getCompose . unFix)
nApp :: NExprLoc -> NExprLoc -> NExprLoc
nApp e1@(AnnE s1 _) e2@(AnnE s2 _) = AnnE (s1 <> s2) (NApp e1 e2)
nApp _ _ = error "nApp: unexpected"
nUnary :: Ann SrcSpan NUnaryOp -> NExprLoc -> NExprLoc
nUnary (Ann s1 u) e1@(AnnE s2 _) = AnnE (s1 <> s2) (NUnary u e1)
nUnary _ _ = error "nUnary: unexpected"
@ -85,18 +82,6 @@ nBinary (Ann s1 b) e1@(AnnE s2 _) e2@(AnnE s3 _) =
AnnE (s1 <> s2 <> s3) (NBinary b e1 e2)
nBinary _ _ _ = error "nBinary: unexpected"
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"
nHasAttr :: NExprLoc -> Ann SrcSpan (NAttrPath NExprLoc) -> NExprLoc
nHasAttr e1@(AnnE s1 _) (Ann s2 ats) = AnnE (s1 <> s2) (NHasAttr e1 ats)
nHasAttr _ _ = error "nHasAttr: unexpected"
nAbs :: Ann SrcSpan (Params NExprLoc) -> NExprLoc -> NExprLoc
nAbs (Ann s1 ps) e1@(AnnE s2 _) = AnnE (s1 <> s2) (NAbs ps e1)
nAbs _ _ = error "nAbs: unexpected"
@ -104,9 +89,5 @@ nAbs _ _ = error "nAbs: unexpected"
nStr :: Ann SrcSpan (NString NExprLoc) -> NExprLoc
nStr (Ann s1 s) = AnnE s1 (NStr s)
deltaInfo :: Delta -> (Text, Int, Int)
deltaInfo = \case
Columns c _ -> ("<string>", 1, fromIntegral c + 1)
Tab {} -> ("<string>", 1, 1)
Lines l _ _ _ -> ("<string>", fromIntegral l + 1, 1)
Directed fn l c _ _ -> (pack fn, fromIntegral l + 1, fromIntegral c + 1)
deltaInfo :: SourcePos -> (Text, Int, Int)
deltaInfo (SourcePos fp l c) = (pack fp, unPos l, unPos c)

View file

@ -1,4 +1,3 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
@ -6,8 +5,6 @@
module Nix.Parser (
parseNixFile,
parseNixFileLoc,
parseNixString,
parseNixStringLoc,
parseNixText,
parseNixTextLoc,
Result(..)
@ -16,27 +13,15 @@ module Nix.Parser (
import Control.Applicative hiding (many, some)
import Control.Monad
import Control.Monad.IO.Class
import Data.Foldable hiding (concat)
import Data.Functor
import qualified Data.List.NonEmpty as NE
import qualified Data.HashMap.Strict.InsOrd as M
import Data.Text hiding (map, foldl', concat)
import Data.Text hiding (map, concat)
import Nix.Expr hiding (($>))
import Nix.Parser.Library
import Nix.Parser.Operators
import Nix.StringOperations
--------------------------------------------------------------------------------
annotateLocation :: Parser a -> Parser (Ann SrcSpan a)
annotateLocation p = do
begin <- position
res <- p
end <- position
let span = SrcSpan begin end
pure $ Ann span res
annotateLocation1 :: Parser (NExprF NExprLoc) -> Parser NExprLoc
annotateLocation1 = fmap annToAnnF . annotateLocation
import Text.Megaparsec.Expr
--------------------------------------------------------------------------------
@ -45,28 +30,10 @@ nixExpr = stripAnnotation <$> nixExprLoc
-- | The lexer for this parser is defined in 'Nix.Parser.Library'.
nixExprLoc :: Parser NExprLoc
nixExprLoc =
whiteSpace *> (nixToplevelForm <|> foldl' makeParser nixTerm nixOperators)
where
makeParser :: Parser NExprLoc -> Either NSpecialOp NOperatorDef
-> Parser NExprLoc
makeParser term (Left NSelectOp) = nixSelect term
makeParser term (Left NAppOp) = chainl1 term (pure nApp)
makeParser term (Left NHasAttrOp) = nixHasAttr term
makeParser term (Right (NUnaryDef name op)) =
build <$> many (annotateLocation (void $ symbol name)) <*> term
where
build :: [Ann SrcSpan ()] -> NExprLoc -> NExprLoc
build = flip $ foldl' (\t' (Ann s ()) -> nUnary (Ann s op) t')
nixExprLoc = whiteSpace *> (nixToplevelForm <|> exprParser)
makeParser term (Right (NBinaryDef assoc ops)) = case assoc of
NAssocLeft -> chainl1 term op
NAssocRight -> chainr1 term op
NAssocNone -> term <**> (flip <$> op <*> term <|> pure id)
where
op :: Parser (NExprLoc -> NExprLoc -> NExprLoc)
op = choice . map (\(n,o) -> (\(Ann a ()) -> nBinary (Ann a o))
<$> annotateLocation (reservedOp n)) $ ops
exprParser :: Parser NExprLoc
exprParser = makeExprParser nixTerm (map (map (\(_,_,x) -> x)) nixOperators)
antiStart :: Parser Text
antiStart = try (symbol "${") <?> show ("${" :: String)
@ -81,24 +48,9 @@ selDot = try (char '.' *> notFollowedBy (("path" :: String) <$ nixPath)) *> whit
nixSelector :: Parser (Ann SrcSpan (NAttrPath NExprLoc))
nixSelector = annotateLocation $ keyName `sepBy1` selDot
nixSelect :: Parser NExprLoc -> Parser NExprLoc
nixSelect term = build
<$> term
<*> optional ((,) <$> (selDot *> nixSelector) <*> optional (reserved "or" *> nixTerm))
where
build :: NExprLoc -> Maybe (Ann SrcSpan (NAttrPath NExprLoc), Maybe NExprLoc) -> NExprLoc
build t Nothing = t
build t (Just (s,o)) = nSelectLoc t s o
nixHasAttr :: Parser NExprLoc -> Parser NExprLoc
nixHasAttr term = build <$> term <*> optional (reservedOp "?" *> nixSelector) where
build :: NExprLoc -> Maybe (Ann SrcSpan (NAttrPath NExprLoc)) -> NExprLoc
build t Nothing = t
build t (Just s) = nHasAttr t s
-- | A self-contained unit.
nixTerm :: Parser NExprLoc
nixTerm = nixSelect $ choice
nixTerm = choice
[ nixPath, nixSPath, nixFloat, nixInt, nixBool, nixNull, nixParens, nixList, nixUri
, nixStringExpr, nixSet, nixSym ]
@ -109,24 +61,24 @@ nixSym :: Parser NExprLoc
nixSym = annotateLocation1 $ mkSymF <$> identifier
nixInt :: Parser NExprLoc
nixInt = annotateLocation1 $ (mkIntF <$> integer <?> "integer")
nixInt = annotateLocation1 (mkIntF <$> integer <?> "integer")
nixFloat :: Parser NExprLoc
nixFloat = annotateLocation1 $ (try (mkFloatF . realToFrac <$> float) <?> "float")
nixFloat = annotateLocation1 (try (mkFloatF . realToFrac <$> float) <?> "float")
nixBool :: Parser NExprLoc
nixBool = annotateLocation1 $ (try (true <|> false) <?> "bool") where
nixBool = annotateLocation1 (try (true <|> false) <?> "bool") where
true = mkBoolF True <$ reserved "true"
false = mkBoolF False <$ reserved "false"
nixNull :: Parser NExprLoc
nixNull = annotateLocation1 $ (mkNullF <$ try (reserved "null") <?> "null")
nixNull = annotateLocation1 (mkNullF <$ try (reserved "null") <?> "null")
nixParens :: Parser NExprLoc
nixParens = parens nixExprLoc <?> "parens"
nixList :: Parser NExprLoc
nixList = annotateLocation1 $ (brackets (NList <$> many nixTerm) <?> "list")
nixList = annotateLocation1 (brackets (NList <$> many nixTerm) <?> "list")
pathChars :: String
pathChars = ['A'..'Z'] ++ ['a'..'z'] ++ "._-+" ++ ['0'..'9']
@ -134,26 +86,28 @@ pathChars = ['A'..'Z'] ++ ['a'..'z'] ++ "._-+" ++ ['0'..'9']
slash :: Parser Char
slash = try (char '/' <* notFollowedBy (void (char '/') <|>
void (char '*') <|>
someSpace))
whiteSpace))
<?> "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 '<' *> some (oneOf pathChars <|> slash) <* symbol ">")
nixSPath = annotateLocation1 (mkPathF True <$> try (char '<' *> some (oneOf pathChars <|> slash) <* symbol ">")
<?> "spath")
nixPath :: Parser NExprLoc
nixPath = annotateLocation1 (token (fmap (mkPathF False) (((++)
nixPath = annotateLocation1 (parseToken (fmap (mkPathF False) (((++)
<$> (try ((++) <$> many (oneOf pathChars) <*> fmap (:[]) slash) <?> "path")
<*> fmap concat
( some (some (oneOf pathChars)
<|> liftA2 (:) slash (some (oneOf pathChars)))
))
<?> "path")))
where
parseToken p = p <* whiteSpace
nixLet :: Parser NExprLoc
nixLet = annotateLocation1 $ (reserved "let"
nixLet = annotateLocation1 (reserved "let"
*> whiteSpace
*> (letBody <|> letBinders)
<?> "let block")
@ -163,26 +117,26 @@ nixLet = annotateLocation1 $ (reserved "let"
<*> (whiteSpace *> reserved "in" *> nixExprLoc)
-- Let expressions `let {..., body = ...}' are just desugared
-- into `(rec {..., body = ...}).body'.
letBody = (\x pos -> NSelect x [StaticKey "body" (Just pos)] Nothing)
<$> aset <*> position
letBody = liftM2 (NBinary NSelect) aset
(annotateLocation1 (pure (mkSymF "body")))
aset = annotateLocation1 $ NRecSet <$> braces nixBinders
nixIf :: Parser NExprLoc
nixIf = annotateLocation1 $ (NIf
nixIf = annotateLocation1 (NIf
<$> (reserved "if" *> nixExprLoc)
<*> (whiteSpace *> reserved "then" *> nixExprLoc)
<*> (whiteSpace *> reserved "else" *> nixExprLoc)
<?> "if")
nixAssert :: Parser NExprLoc
nixAssert = annotateLocation1 $ (NAssert
nixAssert = annotateLocation1 (NAssert
<$> (reserved "assert" *> nixExprLoc)
<*> (semi *> nixExprLoc)
<?> "assert")
nixWith :: Parser NExprLoc
nixWith = annotateLocation1 $ (NWith
nixWith = annotateLocation1 (NWith
<$> (reserved "with" *> nixExprLoc)
<*> (semi *> nixExprLoc)
<?> "with")
@ -194,14 +148,17 @@ nixStringExpr :: Parser NExprLoc
nixStringExpr = nStr <$> annotateLocation nixString
uriAfterColonC :: Parser Char
uriAfterColonC = alphaNumChar <|> oneOf "%/?:@&=+$,-_.!~*'"
uriAfterColonC = alphaNumChar <|>
satisfy (\x -> x `elem` ("%/?:@&=+$,-_.!~*'" :: String))
nixUri :: Parser NExprLoc
nixUri = annotateLocation1 $ token $ fmap (mkUriF . pack) $ (++)
nixUri = annotateLocation1 $ parseToken $ fmap (mkUriF . pack) $ (++)
<$> try ((++) <$> (scheme <* char ':') <*> fmap (\x -> [':',x]) uriAfterColonC)
<*> many uriAfterColonC
where
scheme = (:) <$> letterChar <*> many (alphaNumChar <|> oneOf "+-.")
scheme = (:) <$> letterChar
<*> many (alphaNumChar <|> satisfy (\x -> x `elem` ("+-." :: String)))
parseToken p = p <* whiteSpace
nixString :: Parser (NString NExprLoc)
nixString = doubleQuoted <|> indented <?> "string"
@ -212,7 +169,7 @@ nixString = doubleQuoted <|> indented <?> "string"
<* doubleQ)
<?> "double quoted string"
doubleQ = char '"'
doubleQ = void $ char '"'
doubleEscape = Plain . singleton <$> (char '\\' *> escapeCode)
indented :: Parser (NString NExprLoc)
@ -221,17 +178,19 @@ nixString = doubleQuoted <|> indented <?> "string"
<* indentedQ)
<?> "indented string"
indentedQ = try (string "''") <?> "\"''\""
indentedQ = void (try (string "''") <?> "\"''\"")
indentedEscape = fmap Plain
$ try (indentedQ *> char '\\') *> fmap singleton escapeCode
<|> try (indentedQ *> ("''" <$ char '\'' <|> "$" <$ char '$'))
stringChar end escStart esc
= esc
<|> Antiquoted <$> (antiStart *> nixExprLoc <* char '}') -- don't skip trailing space
<|> Plain . singleton <$> char '$'
<|> Plain . pack <$> some plainChar
where plainChar = notFollowedBy (end <|> void (char '$') <|> escStart) *> anyChar
stringChar end escStart esc = esc
<|> Antiquoted <$> (antiStart *> nixExprLoc <* char '}')
-- ^ don't skip trailing space
<|> Plain . singleton <$> char '$'
<|> Plain . pack <$> some plainChar
where
plainChar =
notFollowedBy (end <|> void (char '$') <|> escStart) *> anyChar
escapeCode = choice [ c <$ char e | (c,e) <- escapeCodes ] <|> anyChar
@ -242,7 +201,7 @@ argExpr = choice [atLeft, onlyname, atRight] <* symbol ":" where
-- 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 = choice [nixUri >> unexpected "valid uri",
onlyname = choice [nixUri >> unexpected (Label ('v' NE.:| "alid uri")),
Param <$> identifier]
-- Parameters named by an identifier on the left (`args @ {x, y}`)
@ -292,12 +251,12 @@ nixBinders = (inherit <|> namedVar) `endBy` semi where
keyName :: Parser (NKeyName NExprLoc)
keyName = dynamicKey <|> staticKey where
staticKey = do
beg <- position
beg <- getPosition
StaticKey <$> identifier <*> pure (Just beg)
dynamicKey = DynamicKey <$> nixAntiquoted nixString
nixSet :: Parser NExprLoc
nixSet = annotateLocation1 $ ((isRec <*> braces nixBinders) <?> "set") where
nixSet = annotateLocation1 ((isRec <*> braces nixBinders) <?> "set") where
isRec = (try (reserved "rec" $> NRecSet) <?> "recursive set")
<|> pure NSet
@ -307,14 +266,8 @@ parseNixFile = parseFromFileEx $ nixExpr <* eof
parseNixFileLoc :: MonadIO m => FilePath -> m (Result NExprLoc)
parseNixFileLoc = parseFromFileEx $ nixExprLoc <* eof
parseNixString :: String -> Result NExpr
parseNixString = parseFromString $ nixExpr <* eof
parseNixStringLoc :: String -> Result NExprLoc
parseNixStringLoc = parseFromString $ nixExprLoc <* eof
parseNixText :: Text -> Result NExpr
parseNixText = parseNixString . unpack
parseNixText = parseFromText $ nixExpr <* eof
parseNixTextLoc :: Text -> Result NExprLoc
parseNixTextLoc = parseNixStringLoc . unpack
parseNixTextLoc = parseFromText $ nixExprLoc <* eof

View file

@ -1,28 +1,19 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -Wno-missing-signatures #-}
module Nix.Parser.Library
( module Nix.Parser.Library
, module X
) where
import Control.Applicative hiding (many, some)
import Control.Applicative hiding (many)
import Control.Monad
import Control.Monad.IO.Class
import Data.Data
import Data.Functor
import Data.Functor.Identity
import qualified Data.HashSet as HashSet
import Data.Int (Int64)
import Data.List (nub)
import Data.Text
import qualified Data.Text.IO as T
import GHC.Generics
import Text.Megaparsec as X
import Text.Megaparsec.Char as X
import qualified Text.Megaparsec.Char.Lexer as L
@ -164,18 +155,10 @@ whiteSpace = L.space space1 lineCmnt blockCmnt
lineCmnt = L.skipLineComment "//"
blockCmnt = L.skipBlockComment "/*" "*/"
data Delta
= Columns !Int64 !Int64
| Tab !Int64 !Int64 !Int64
| Lines !Int64 !Int64 !Int64 !Int64
| Directed !FilePath !Int64 !Int64 !Int64 !Int64
deriving (Generic, Data, Eq, Ord, Show, Read)
type Parser = ParsecT () Text Identity
parseFromFileEx :: MonadIO m => Parser a -> FilePath -> m (Result a)
parseFromString :: Parser a -> String -> Result a
position :: Parser Delta
parseFromText :: Parser a -> Text -> Result a
data Result a = Success a | Failure Doc deriving Show
@ -183,7 +166,5 @@ parseFromFileEx p path =
(either (Failure . text . show) Success . parse p path)
`liftM` liftIO (T.readFile path)
parseFromString p =
either (Failure . text . show) Success . parse p "<string>" . pack
position = return $ Columns 0 0
parseFromText p =
either (Failure . text . show) Success . parse p "<string>"

View file

@ -1,16 +1,21 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wno-missing-signatures #-}
module Nix.Parser.Operators where
import Data.Data (Data(..))
import Data.Foldable (concat)
import qualified Data.Map as Map
import Data.Maybe (catMaybes)
import Data.Text (Text)
import Data.Typeable (Typeable)
import GHC.Generics
import GHC.Generics hiding (Prefix)
import Nix.Expr
import Nix.Parser.Library
import Text.Megaparsec.Expr
data NSpecialOp = NHasAttrOp | NSelectOp | NAppOp
deriving (Eq, Ord, Generic, Typeable, Data, Show)
@ -19,64 +24,76 @@ data NAssoc = NAssocNone | NAssocLeft | NAssocRight
deriving (Eq, Ord, Generic, Typeable, Data, Show)
data NOperatorDef
= NUnaryDef String NUnaryOp
| NBinaryDef NAssoc [(String, NBinaryOp)]
= NUnaryDef Text NUnaryOp
| NBinaryDef NAssoc [(Text, NBinaryOp)]
deriving (Eq, Ord, Generic, Typeable, Data, Show)
nixOperators :: [Either NSpecialOp NOperatorDef]
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
opWithLoc :: Text -> o -> (Ann SrcSpan o -> a) -> Parser a
opWithLoc name op f = do
Ann ann _ <- annotateLocation (symbol name)
return $ f (Ann ann op)
binaryN name op = (Right (op, NAssocNone),
name, InfixN (opWithLoc name op nBinary))
binaryL name op = (Right (op, NAssocLeft),
name, InfixL (opWithLoc name op nBinary))
binaryR name op = (Right (op, NAssocRight),
name, InfixR (opWithLoc name op nBinary))
prefix name op = (Left op, name, Prefix (opWithLoc name op nUnary))
postfix name op = (Left op, name, Postfix (opWithLoc name op nUnary))
nixOperators
:: [[(Either NUnaryOp (NBinaryOp, NAssoc),
Text, Operator Parser NExprLoc)]]
nixOperators =
[ Left NSelectOp
, Left NAppOp
, Right $ NUnaryDef "-" NNeg
, Left NHasAttrOp
] ++ map Right
[ NBinaryDef NAssocRight [("++", NConcat)]
, NBinaryDef NAssocLeft [("*", NMult), ("/", NDiv)]
, NBinaryDef NAssocLeft [("+", NPlus), ("-", NMinus)]
, NUnaryDef "!" NNot
, NBinaryDef NAssocRight [("//", NUpdate)]
, NBinaryDef NAssocLeft [("<", NLt), (">", NGt), ("<=", NLte), (">=", NGte)]
, NBinaryDef NAssocNone [("==", NEq), ("!=", NNEq)]
, NBinaryDef NAssocLeft [("&&", NAnd)]
, NBinaryDef NAssocLeft [("||", NOr)]
, NBinaryDef NAssocNone [("->", NImpl)]
[ {- 1 -} [ binaryL "." NSelect ]
, {- 2 -} [ binaryL " " NApp ]
, {- 3 -} [ prefix "-" NNeg ]
, {- 4 -} [ binaryL "?" NHasAttr ]
, {- 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 :: String
, operatorName :: Text
} deriving (Eq, Ord, Generic, Typeable, Data, Show)
getUnaryOperator :: NUnaryOp -> OperatorInfo
getUnaryOperator = (m Map.!) where
m = Map.fromList . concat . zipWith buildEntry [1..] . reverse $
nixOperators
buildEntry i = \case
Right (NUnaryDef name op) -> [(op, OperatorInfo i NAssocNone name)]
m = Map.fromList $ concat $ zipWith buildEntry [1..] nixOperators
buildEntry i = concatMap $ \case
(Left op, name, _) -> [(op, OperatorInfo i NAssocNone name)]
_ -> []
getBinaryOperator :: NBinaryOp -> OperatorInfo
getBinaryOperator = (m Map.!) where
m = Map.fromList . concat . zipWith buildEntry [1..] . reverse $
nixOperators
buildEntry i = \case
Right (NBinaryDef assoc ops) ->
[(op, OperatorInfo i assoc name) | (name,op) <- ops]
m = Map.fromList $ concat $ zipWith buildEntry [1..] nixOperators
buildEntry i = concatMap $ \case
(Right (op, assoc), name, _) -> [(op, OperatorInfo i assoc name)]
_ -> []
getSpecialOperatorPrec :: NSpecialOp -> Int
getSpecialOperatorPrec = (m Map.!) where
m = Map.fromList . catMaybes . zipWith buildEntry [1..] . reverse $
nixOperators
buildEntry _ (Right _) = Nothing
buildEntry i (Left op) = Just (op, i)
selectOp :: OperatorInfo
selectOp = OperatorInfo (getSpecialOperatorPrec NSelectOp) NAssocLeft "."
hasAttrOp :: OperatorInfo
hasAttrOp = OperatorInfo (getSpecialOperatorPrec NHasAttrOp) NAssocLeft "?"
appOp :: OperatorInfo
appOp = OperatorInfo (getSpecialOperatorPrec NAppOp) NAssocLeft " "

View file

@ -29,7 +29,6 @@ import GHC.Generics
import Nix.Atoms
import Nix.Expr.Types
import Nix.Expr.Types.Annotated (deltaInfo)
import Nix.Parser.Library (Delta(..))
import Nix.Thunk
import Nix.Utils
@ -42,7 +41,7 @@ data NValueF m r
| NVStr Text (DList Text)
| NVPath FilePath
| NVList [r]
| NVSet (AttrSet r) (AttrSet Delta)
| NVSet (AttrSet r) (AttrSet SourcePos)
| NVClosure (Params ()) (m (NValue m) -> m (NValue m))
-- ^ A function is a closed set of parameters representing the "call
-- signature", used at application time to check the type of arguments
@ -113,8 +112,9 @@ builtin3 :: Monad m
builtin3 name f =
builtin name $ \a -> builtin name $ \b -> builtin name $ \c -> f a b c
posFromDelta :: forall m v t. (MonadThunk v t m, Convertible v t) => Delta -> v
posFromDelta (deltaInfo -> (f, l, c)) =
posFromSourcePos :: forall m v t. (MonadThunk v t m, Convertible v t)
=> SourcePos -> v
posFromSourcePos (SourcePos f l c) =
ofVal $ M.fromList
[ ("file" :: Text, value @_ @_ @m $ ofVal f)
, ("line", value @_ @_ @m $ ofVal l)