haskell-awk-1.0.1: src/System/Console/Hawk/Config/Extend.hs
-- Copyright 2013 Mario Pastorelli (pastorelli.mario@gmail.com) Samuel Gélineau (gelisam@gmail.com)
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
{-# LANGUAGE OverloadedStrings #-}
module System.Console.Hawk.Config.Extend
( extendModules
, extendSource
, getModuleName
)
where
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as C8
import qualified Data.ByteString.Search as BSS
import Data.Char
import Data.Maybe
import Data.Monoid ((<>))
import Text.Printf
import System.Console.Hawk.Config.Base
extendModules :: [ExtensionName]
-> [QualifiedModule]
-> [QualifiedModule]
extendModules extensions modules = addIfNecessary (shouldAddPrelude extensions modules)
(unqualified_prelude:)
modules
where
unqualified_prelude = ("Prelude", Nothing)
-- adjust the prelude to make it loadable from hint.
extendSource :: FilePath
-> [ExtensionName]
-> [QualifiedModule]
-> Source
-> Source
extendSource configFile extensions modules = addPreludeIfMissing . addModuleIfMissing
where
addModuleIfMissing s = addIfNecessary (shouldAddModule s)
(addModule configFile)
s
addPreludeIfMissing = addIfNecessary (shouldAddPrelude extensions modules)
(addImport "Prelude" configFile)
addIfNecessary :: Bool -> (a -> a) -> a -> a
addIfNecessary True f x = f x
addIfNecessary False _ x = x
shouldAddModule :: Source -> Bool
shouldAddModule = (== Nothing) . parseModuleName
shouldAddPrelude :: [ExtensionName] -> [QualifiedModule] -> Bool
shouldAddPrelude extensions _ | "NoImplicitPrelude" `elem` extensions = False
shouldAddPrelude _ modules | "Prelude" `elem` map fst modules = False
shouldAddPrelude _ _ | otherwise = True
-- add a module to a string representing a Haskell source file
addModule :: FilePath -> Source -> Source
addModule configFile source =
let strippedCode = C8.dropWhile isSpace source
maybePragma = if "{-#" `C8.isPrefixOf` strippedCode
then let (pragma,afterPragma) = BSS.breakAfter "#-}" strippedCode
in (Just pragma, afterPragma)
else (Nothing,strippedCode)
line :: Int -> ByteString
line n = C8.pack $ printf "{-# LINE %d %s #-}" n $ show configFile
moduleLine = C8.pack $ unwords ["module", defaultModuleName, "where"]
in case maybePragma of
(Nothing,c) -> C8.unlines [moduleLine,c]
(Just pragma,c) -> let n = 1 + C8.length (C8.filter (=='\n') pragma)
in C8.unlines [line 1,pragma,moduleLine,line n,c]
-- add an import statement to a string representing a Haskell source file
addImport :: String -> FilePath -> Source -> Source
addImport moduleName configFile source =
let (premodule,postmodule) = BSS.breakAfter "module " source
(prewhere,postwhere) = BSS.breakAfter " where" postmodule
(prenewline,postnewline) = BSS.breakAfter "\n" postwhere
preimports = premodule <> prewhere <> prenewline
postimports = postnewline
line :: Int -> ByteString
line n = C8.pack $ printf "{-# LINE %d %s #-}" n $ show configFile
importLine = C8.pack $ unwords ["import", moduleName]
m = 1 + C8.length (C8.filter (=='\n') preimports)
extraLines = C8.unlines [importLine, line m]
in preimports <> extraLines <> postimports
-- get the module name from a file if it exists
parseModuleName :: Source -> Maybe ByteString
parseModuleName bs = case BSS.indices (C8.pack "module") bs of
[] -> Nothing
(i:_) -> Just
. C8.takeWhile (\c -> isAlphaNum c || c == '.')
. C8.dropWhile isSpace
. C8.drop (i + 6) $ bs
-- same, but crash if there is no module
getModuleName :: Source -> String
getModuleName = C8.unpack . fromJust . parseModuleName