{-# LANGUAGE FlexibleContexts #-} module Puppet.Lens ( -- * Pure resolution prisms _PResolveExpression , _PResolveValue -- * Prisms for PValues , _PHash , _PBoolean , _PString , _PResourceReference , _PArray -- * Parsing prism , _PParse -- * Lenses and Prisms for 'Statement's , _VariableAssignment , _NodeDeclaration , _DefineDeclaration , _ClassDeclaration , _Statements ) where import Control.Lens import Control.Lens.Aeson import Control.Applicative import Puppet.PP (displayNocolor) import Puppet.Parser.Types import Puppet.Interpreter.Types import Puppet.Interpreter.Resolve import Puppet.Parser import Puppet.Parser.PrettyPrinter (ppStatements) import qualified Data.Vector as V import qualified Data.HashMap.Strict as HM import qualified Data.Text as T import qualified Data.Maybe.Strict as S import Data.Tuple.Strict hiding (uncurry) import Text.Parsec.Prim (runParserT) import Text.PrettyPrint.ANSI.Leijen (renderPretty,displayS,SimpleDoc(..)) import System.IO.Unsafe import Data.Bits import Text.Parser.Combinators (eof) -- | Incomplete _PResolveExpression :: Prism' Expression PValue _PResolveExpression = prism reinject extract where extract x@(PValue v) = case v ^? _PResolveValue of Just r -> Right r Nothing -> Left x extract x@(And a b) = let a' = a ^? _PResolveExpression . to pValue2Bool b' = b ^? _PResolveExpression . to pValue2Bool in case (a',b') of (Just False, _) -> Right (PBoolean False) (Just _, Just r) -> Right (PBoolean r) _ -> Left x extract x@(Or a b) = let a' = a ^? _PResolveExpression . to pValue2Bool b' = b ^? _PResolveExpression . to pValue2Bool in case (a',b') of (Just True, _) -> Right (PBoolean True) (Just _, Just r) -> Right (PBoolean r) _ -> Left x extract x@(Addition a b) = extractBinop x a b (+) (+) extract x@(Substraction a b) = extractBinop x a b (-) (-) extract x@(Division a b) = extractNotZero b >> extractBinop x a b div (/) extract x@(Multiplication a b) = extractBinop x a b (*) (*) extract x@(Modulo a b) = extractNotZero b >> extractIntOp x a b mod extract x@(RightShift a b) = extractIntOp x a b (\v -> shiftR v . fromIntegral) extract x@(LeftShift a b) = extractIntOp x a b (\v -> shiftL v . fromIntegral) extract x = Left x reinject = PValue . review _PResolveValue extractNotZero :: Expression -> Either Expression PValue extractNotZero e = case e ^? _PResolveExpression of Just "0" -> Left e Just r -> Right r _ -> Left e extractBinop :: Expression -> Expression -> Expression -> (Integer -> Integer -> Integer) -> (Double -> Double -> Double) -> Either Expression PValue extractBinop x a b opi opf = case opi `fmap` (a ^? _PResolveExpression . _Integer) <*> (b ^? _PResolveExpression . _Integer) of Just ri -> Right $ review _Integer ri Nothing -> case opf `fmap` (a ^? _PResolveExpression . _Double) <*> (b ^? _PResolveExpression . _Double) of Just rd -> Right $ review _Double rd Nothing -> Left x extractIntOp :: Expression -> Expression -> Expression -> (Integer -> Integer -> Integer) -> Either Expression PValue extractIntOp x a b opi = case opi `fmap` (a ^? _PResolveExpression . _Integer) <*> (b ^? _PResolveExpression . _Integer) of Just ri -> Right $ review _Integer ri Nothing -> Left x _PResolveValue :: Prism' UValue PValue _PResolveValue = prism toU toP where toP (UString s) = Right (PString s) toP UUndef = Right PUndef toP (UBoolean b) = Right (PBoolean b) toP r@(UResourceReference t n) = maybe (Left r) (Right . PResourceReference t) (n ^? _PResolveExpression . _PString) toP r@(UArray lst) = maybe (Left r) (Right . PArray) (V.mapM (preview _PResolveExpression) lst) toP r@(UHash lst) = maybe (Left r) (Right . PHash . HM.fromList) (mapM resolveKV (V.toList lst)) where resolveKV (k :!: v) = do k' <- k ^? _PResolveExpression . _PString v' <- v ^? _PResolveExpression return (k',v') toP r@(UInterpolable ip) = maybe (Left r) (Right . PString . T.concat . V.toList ) (V.mapM (preview (_PResolveValue . _PString)) ip) toP r = Left r toU (PBoolean x) = UBoolean x toU PUndef = UUndef toU (PString s) = UString s toU (PResourceReference t n) = UResourceReference t (PValue (UString n)) toU (PArray r) = UArray (fmap (PValue . toU) r) toU (PHash h) = UHash (V.fromList $ map (\(k,v) -> (PValue (UString k) :!: PValue (toU v))) $ HM.toList h) _PHash :: Prism' PValue (Container PValue) _PHash = prism PHash $ \c -> case c of; PHash x -> Right x; _ -> Left c _PBoolean :: Prism' PValue Bool _PBoolean = prism PBoolean $ \c -> case c of; PBoolean x -> Right x; _ -> Left c _PString :: Prism' PValue T.Text _PString = prism PString $ \c -> case c of; PString x -> Right x; _ -> Left c _PResourceReference :: Prism' PValue (T.Text, T.Text) _PResourceReference = prism (uncurry PResourceReference) $ \c -> case c of; PResourceReference t n -> Right (t,n); _ -> Left c _PArray :: Prism' PValue (V.Vector PValue) _PArray = prism PArray $ \c -> case c of; PArray x -> Right x; _ -> Left c -- | Warning, this uses 'unsafePerformIO' to parse (parsing Regexps -- requires IO). _PParse :: Prism' T.Text (V.Vector Statement) _PParse = prism dspl prs where prs i = case unsafePerformIO (runParserT (puppetParser <* eof) () "dummy" i) of Left _ -> Left i Right x -> Right x dspl = T.pack . displayNocolor . ppStatements _VariableAssignment :: Prism' Statement (T.Text,Expression,PPosition) _VariableAssignment = prism rebuild extract where extract (VariableAssignment t e p) = Right (t,e,p) extract x = Left x rebuild (t,e,p) = VariableAssignment t e p _NodeDeclaration :: Prism' Statement (NodeDesc, V.Vector Statement, S.Maybe NodeDesc, PPosition) _NodeDeclaration = prism rebuild extract where extract (Node nd s nd' p) = Right (nd, s, nd', p) extract x = Left x rebuild (nd, s, nd', p) = Node nd s nd' p _DefineDeclaration :: Prism' Statement (T.Text, V.Vector (Pair T.Text (S.Maybe Expression)), V.Vector Statement, PPosition) _DefineDeclaration = prism rebuild extract where extract (DefineDeclaration n args stmts p) = Right (n, args, stmts, p) extract x = Left x rebuild (n, args, stmts, p) = DefineDeclaration n args stmts p _ClassDeclaration :: Prism' Statement (T.Text, V.Vector (Pair T.Text (S.Maybe Expression)), S.Maybe T.Text, V.Vector Statement, PPosition) _ClassDeclaration = prism rebuild extract where extract (ClassDeclaration n args inh stmts p) = Right (n, args, inh, stmts, p) extract x = Left x rebuild (n, args, inh, stmts, p) = ClassDeclaration n args inh stmts p _TopContainer :: Prism' Statement (V.Vector Statement, Statement) _TopContainer = prism rebuild extract where extract (TopContainer spur s) = Right (spur, s) extract x = Left x rebuild (spur, s) = TopContainer spur s -- | Extracts the statements from 'ClassDeclaration', 'DefineDeclaration', -- 'Node' and the spurious statements of 'TopContainer'. _Statements :: Lens' Statement [Statement] _Statements = lens (V.toList . sget) (\s v -> sset s (V.fromList v)) where sget :: Statement -> V.Vector Statement sget (ClassDeclaration _ _ _ s _) = s sget (DefineDeclaration _ _ s _) = s sget (Node _ s _ _) = s sget (TopContainer s _) = s sget _ = V.empty sset :: Statement -> V.Vector Statement -> Statement sset (ClassDeclaration n args inh _ p) s = ClassDeclaration n args inh s p sset (Node ns _ nd' p) s = Node ns s nd' p sset (DefineDeclaration n args _ p) s = DefineDeclaration n args s p sset (TopContainer _ p) s = TopContainer s p sset x _ = x