{-# LANGUAGE Strict #-} module Language.Cimple.SemCheck.Includes ( collectIncludes , normaliseIncludes ) where import Control.Monad.State.Strict (State) import qualified Control.Monad.State.Strict as State import Data.Fix (Fix (..)) import Data.List (isInfixOf) import Data.Text (Text) import qualified Data.Text as Text import Language.Cimple.Ast (NodeF (..)) import Language.Cimple.Lexer (Lexeme (..)) import Language.Cimple.MapAst (IdentityActions, doNode, identityActions, mapAst) import Language.Cimple.Tokens (LexemeClass (..)) import Language.Cimple.TranslationUnit (TranslationUnit) import System.FilePath (joinPath, splitPath, takeDirectory) collectIncludes :: [FilePath] -> TranslationUnit Text -> [FilePath] -> Either String ((), FilePath, [FilePath]) collectIncludes :: [FilePath] -> TranslationUnit Text -> [FilePath] -> Either FilePath ((), FilePath, [FilePath]) collectIncludes [FilePath] sources (FilePath file, [Node (Lexeme Text)] _) [FilePath] includes = case (FilePath -> Bool) -> [FilePath] -> [FilePath] forall a. (a -> Bool) -> [a] -> [a] filter (Bool -> Bool not (Bool -> Bool) -> (FilePath -> Bool) -> FilePath -> Bool forall b c a. (b -> c) -> (a -> b) -> a -> c . FilePath -> Bool exempt) ([FilePath] -> [FilePath]) -> ([FilePath] -> [FilePath]) -> [FilePath] -> [FilePath] forall b c a. (b -> c) -> (a -> b) -> a -> c . (FilePath -> Bool) -> [FilePath] -> [FilePath] forall a. (a -> Bool) -> [a] -> [a] filter (Bool -> Bool not (Bool -> Bool) -> (FilePath -> Bool) -> FilePath -> Bool forall b c a. (b -> c) -> (a -> b) -> a -> c . (FilePath -> [FilePath] -> Bool forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool `elem` [FilePath] sources)) ([FilePath] -> [FilePath]) -> [FilePath] -> [FilePath] forall a b. (a -> b) -> a -> b $ [FilePath] includes of [] -> ((), FilePath, [FilePath]) -> Either FilePath ((), FilePath, [FilePath]) forall a b. b -> Either a b Right ((), FilePath file, [FilePath] includes) FilePath missing:[FilePath] _ -> FilePath -> Either FilePath ((), FilePath, [FilePath]) forall a b. a -> Either a b Left (FilePath -> Either FilePath ((), FilePath, [FilePath])) -> FilePath -> Either FilePath ((), FilePath, [FilePath]) forall a b. (a -> b) -> a -> b $ FilePath file FilePath -> FilePath -> FilePath forall a. Semigroup a => a -> a -> a <> FilePath " includes missing " FilePath -> FilePath -> FilePath forall a. Semigroup a => a -> a -> a <> FilePath missing where exempt :: FilePath -> Bool exempt = (FilePath "/third_party/" FilePath -> FilePath -> Bool forall a. Eq a => [a] -> [a] -> Bool `isInfixOf`) relativeTo :: FilePath -> FilePath -> FilePath relativeTo :: FilePath -> FilePath -> FilePath relativeTo FilePath "." FilePath file = FilePath file relativeTo FilePath dir FilePath file = [FilePath] -> [FilePath] -> FilePath go (FilePath -> [FilePath] splitPath FilePath dir) (FilePath -> [FilePath] splitPath FilePath file) where go :: [FilePath] -> [FilePath] -> FilePath go [FilePath] d (FilePath "../":[FilePath] f) = [FilePath] -> [FilePath] -> FilePath go ([FilePath] -> [FilePath] forall a. [a] -> [a] init [FilePath] d) [FilePath] f go [FilePath] d [FilePath] f = [FilePath] -> FilePath joinPath ([FilePath] d [FilePath] -> [FilePath] -> [FilePath] forall a. [a] -> [a] -> [a] ++ [FilePath] f) normaliseIncludes' :: FilePath -> IdentityActions (State [FilePath]) Text normaliseIncludes' :: FilePath -> IdentityActions (State [FilePath]) Text normaliseIncludes' FilePath dir = IdentityActions (State [FilePath]) Text forall (f :: * -> *) text. Applicative f => AstActions f text text identityActions { doNode :: FilePath -> Node (Lexeme Text) -> State [FilePath] (Node (Lexeme Text)) -> State [FilePath] (Node (Lexeme Text)) doNode = \FilePath _ Node (Lexeme Text) node State [FilePath] (Node (Lexeme Text)) act -> case Node (Lexeme Text) node of Fix (PreprocInclude (L AlexPosn spos LexemeClass LitString Text include)) -> do let includePath :: FilePath includePath = FilePath -> FilePath -> FilePath relativeTo FilePath dir (FilePath -> FilePath) -> FilePath -> FilePath forall a b. (a -> b) -> a -> b $ Text -> FilePath tread Text include ([FilePath] -> [FilePath]) -> State [FilePath] () forall s (m :: * -> *). MonadState s m => (s -> s) -> m () State.modify (FilePath includePath FilePath -> [FilePath] -> [FilePath] forall a. a -> [a] -> [a] :) Node (Lexeme Text) -> State [FilePath] (Node (Lexeme Text)) forall (m :: * -> *) a. Monad m => a -> m a return (Node (Lexeme Text) -> State [FilePath] (Node (Lexeme Text))) -> Node (Lexeme Text) -> State [FilePath] (Node (Lexeme Text)) forall a b. (a -> b) -> a -> b $ NodeF (Lexeme Text) (Node (Lexeme Text)) -> Node (Lexeme Text) forall (f :: * -> *). f (Fix f) -> Fix f Fix (NodeF (Lexeme Text) (Node (Lexeme Text)) -> Node (Lexeme Text)) -> NodeF (Lexeme Text) (Node (Lexeme Text)) -> Node (Lexeme Text) forall a b. (a -> b) -> a -> b $ Lexeme Text -> NodeF (Lexeme Text) (Node (Lexeme Text)) forall lexeme a. lexeme -> NodeF lexeme a PreprocInclude (AlexPosn -> LexemeClass -> Text -> Lexeme Text forall text. AlexPosn -> LexemeClass -> text -> Lexeme text L AlexPosn spos LexemeClass LitString (FilePath -> Text tshow FilePath includePath)) Node (Lexeme Text) _ -> State [FilePath] (Node (Lexeme Text)) act } where tshow :: FilePath -> Text tshow = FilePath -> Text Text.pack (FilePath -> Text) -> (FilePath -> FilePath) -> FilePath -> Text forall b c a. (b -> c) -> (a -> b) -> a -> c . FilePath -> FilePath forall a. Show a => a -> FilePath show tread :: Text -> FilePath tread = FilePath -> FilePath forall a. Read a => FilePath -> a read (FilePath -> FilePath) -> (Text -> FilePath) -> Text -> FilePath forall b c a. (b -> c) -> (a -> b) -> a -> c . Text -> FilePath Text.unpack normaliseIncludes :: TranslationUnit Text -> (TranslationUnit Text, [FilePath]) normaliseIncludes :: TranslationUnit Text -> (TranslationUnit Text, [FilePath]) normaliseIncludes (FilePath file, [Node (Lexeme Text)] ast) = ((FilePath file, [Node (Lexeme Text)] ast'), [FilePath] includes) where ([Node (Lexeme Text)] ast', [FilePath] includes) = State [FilePath] [Node (Lexeme Text)] -> [FilePath] -> ([Node (Lexeme Text)], [FilePath]) forall s a. State s a -> s -> (a, s) State.runState (IdentityActions (State [FilePath]) Text -> [Node (Lexeme Text)] -> State [FilePath] (Mapped Text Text [Node (Lexeme Text)]) forall itext otext a (f :: * -> *). (MapAst itext otext a, Applicative f, HasCallStack) => AstActions f itext otext -> a -> f (Mapped itext otext a) mapAst (FilePath -> IdentityActions (State [FilePath]) Text normaliseIncludes' (FilePath -> FilePath takeDirectory FilePath file)) [Node (Lexeme Text)] ast) []