2024-11-22 10:36:51 -08:00
|
|
|
module Preprocessor where
|
|
|
|
|
|
|
|
|
|
import Control.Monad.Except
|
|
|
|
|
import qualified Data.Text as T
|
|
|
|
|
import System.FilePath
|
|
|
|
|
|
|
|
|
|
newtype PreprocessorError = ParseError Text
|
|
|
|
|
|
2024-11-22 19:44:31 -08:00
|
|
|
instance ToText PreprocessorError where
|
|
|
|
|
toText (ParseError t) = "Preprocessor error on line '" <> t <> "'"
|
|
|
|
|
|
|
|
|
|
instance ToString PreprocessorError where
|
|
|
|
|
toString = toString . toText
|
2024-11-22 10:36:51 -08:00
|
|
|
|
|
|
|
|
type Result = Either PreprocessorError
|
|
|
|
|
type ResultIO = ExceptT PreprocessorError IO
|
|
|
|
|
|
|
|
|
|
concatMapM :: (Applicative f) => (a -> f Text) -> [a] -> f Text
|
|
|
|
|
concatMapM _ [] = pure mempty
|
|
|
|
|
concatMapM f (x : xs) = ((<>) . (<> "\n") <$> f x) <*> concatMapM f xs
|
|
|
|
|
|
|
|
|
|
preprocess :: String -> ResultIO Text
|
|
|
|
|
preprocess filename = do
|
2024-11-22 19:44:31 -08:00
|
|
|
text <- decodeUtf8With lenientDecode <$> readFileBS filename
|
|
|
|
|
result <- concatMapM (preprocessLine $ takeDirectory filename) (lines text)
|
|
|
|
|
putStrLn $ "loading: " ++ filename
|
2024-11-22 10:36:51 -08:00
|
|
|
pure result
|
|
|
|
|
|
|
|
|
|
parseInclude :: Text -> Result Text
|
2024-11-22 19:44:31 -08:00
|
|
|
parseInclude line = maybeToRight (ParseError line) $ T.stripPrefix "@include " line
|
2024-11-22 10:36:51 -08:00
|
|
|
|
|
|
|
|
preprocessLine :: FilePath -> Text -> ResultIO Text
|
|
|
|
|
preprocessLine base line
|
2024-11-22 19:44:31 -08:00
|
|
|
| "@include " `T.isPrefixOf` line = liftEither (parseInclude line) >>= preprocess . normalise . (base </>) . toString
|
2024-11-22 10:36:51 -08:00
|
|
|
| otherwise = pure line
|