haskell-awk 1.0 → 1.0.1
raw patch · 6 files changed
+378/−2 lines, 6 filesdep ~basedep ~haskell-src-extsdep ~network
Dependency ranges changed: base, haskell-src-exts, network
Files
- haskell-awk.cabal +3/−2
- src/System/Console/Hawk/Config/Base.hs +25/−0
- src/System/Console/Hawk/Config/Cache.hs +91/−0
- src/System/Console/Hawk/Config/Compile.hs +55/−0
- src/System/Console/Hawk/Config/Extend.hs +115/−0
- src/System/Console/Hawk/Config/Parse.hs +89/−0
haskell-awk.cabal view
@@ -1,5 +1,5 @@ Name: haskell-awk-Version: 1.0+Version: 1.0.1 Author: Mario Pastorelli <pastorelli.mario@gmail.com>, Samuel Gélineau <gelisam@gmail.com> Maintainer: Mario Pastorelli <pastorelli.mario@gmail.com>, Samuel Gélineau <gelisam@gmail.com> Synopsis: Transform text from the command-line using Haskell expressions.@@ -12,8 +12,9 @@ License-File: LICENSE Build-Type: Simple Cabal-version: >=1.10-Extra-Source-Files: src/System/Console/Hawk.hs+Extra-Source-Files: src/System/Console/*.hs , src/System/Console/Hawk/*.hs+ , src/System/Console/Hawk/Config/*.hs , README.md , tests/System/Console/Hawk/Representable/Test.hs
+ src/System/Console/Hawk/Config/Base.hs view
@@ -0,0 +1,25 @@+-- 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.++module System.Console.Hawk.Config.Base where++import Data.ByteString.Char8+++type ExtensionName = String+type QualifiedModule = (String, Maybe String)+type Source = ByteString++defaultModuleName :: String+defaultModuleName = "System.Console.Hawk.CachedPrelude"
+ src/System/Console/Hawk/Config/Cache.hs view
@@ -0,0 +1,91 @@+-- 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.Cache+ ( getConfigDir+ , getConfigFile+ , getCacheDir+ , getConfigInfosFile+ , getExtensionsFile+ , getModulesFile+ , getCompiledFile+ , getSourceFile+ , cacheExtensions+ , cacheModules+ , cacheSource+ )+ where++import Control.Applicative ((<$>))++import qualified Data.ByteString.Char8 as B+import qualified Language.Haskell.Interpreter as Interpreter+import System.EasyFile++import System.Console.Hawk.Config.Base+++(<//>) :: IO FilePath -- the left filepath in the IO monad+ -> FilePath -- the right filepath+ -> IO FilePath -- the filepath resulting+lpath <//> rpath = (</> rpath) <$> lpath++getConfigDir :: IO FilePath+getConfigDir = getHomeDirectory <//> ".hawk"++getConfigFile :: IO FilePath+getConfigFile = getConfigDir <//> "prelude.hs"++getCacheDir :: IO FilePath+getCacheDir = getConfigDir <//> "cache"++getConfigInfosFile :: IO FilePath+getConfigInfosFile = getCacheDir <//> "configInfos"++getModulesFile :: IO FilePath+getModulesFile = getCacheDir <//> "modules"++getExtensionsFile :: IO FilePath+getExtensionsFile = getCacheDir <//> "extensions"+++getSourceBasename :: IO String+getSourceBasename = getCacheDir <//> "cached_prelude"++getCompiledFile :: IO String+getCompiledFile = getSourceBasename++getSourceFile :: IO String+getSourceFile = (++ ".hs") <$> getSourceBasename+++cacheExtensions :: FilePath+ -> [ExtensionName]+ -> IO ()+cacheExtensions extensionsFile extensions = + writeFile extensionsFile $ show extensions'+ where+ extensions' :: [Interpreter.Extension]+ extensions' = map read extensions++cacheModules :: FilePath+ -> [QualifiedModule]+ -> IO ()+cacheModules modulesFile modules = writeFile modulesFile $ show modules++cacheSource :: FilePath+ -> Source+ -> IO ()+cacheSource = B.writeFile
+ src/System/Console/Hawk/Config/Compile.hs view
@@ -0,0 +1,55 @@+-- 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.Compile+ ( compile+ )+ where++import Control.Monad (when)++import System.Exit+import System.IO+import System.Process++import System.Console.Hawk.Sandbox (extraGhcArgs)+++-- compile a haskell file+-- TODO: this should return the error instead of print it and exit+compile :: FilePath -- ^ the source file+ -> FilePath -- ^ the output file+ -> FilePath -- ^ the directory used for compiler files+ -> IO ()+compile sourceFile outputFile dir = do+ let basicArgs = [ "--make"+ , sourceFile+ , "-i"+ , "-ilib"+ , "-fforce-recomp"+ , "-v0"+ , "-o",outputFile]+ extraArgs <- extraGhcArgs+ let args = basicArgs ++ extraArgs+ compExitCode <-+ waitForProcess =<< runProcess "ghc"+ args+ (Just dir)+ Nothing+ Nothing+ Nothing+ (Just stderr)+ when (compExitCode /= ExitSuccess) $ do+ exitFailure
+ src/System/Console/Hawk/Config/Extend.hs view
@@ -0,0 +1,115 @@+-- 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
+ src/System/Console/Hawk/Config/Parse.hs view
@@ -0,0 +1,89 @@+-- 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.Parse+ ( ExtensionName+ , QualifiedModule+ , parseExtensions+ , parseModules+ , parseSource+ )+ where++import Control.Applicative ((<$>))++import qualified Data.ByteString.Char8 as C8+import Data.Maybe+import Language.Haskell.Exts ( parseFileWithExts )+import Language.Haskell.Exts.Extension ( parseExtension, Extension (..) )+import Language.Haskell.Exts.Parser+ ( getTopPragmas+ , ParseResult (..)+ )+import Language.Haskell.Exts.Syntax+import System.Exit+import Text.Printf++import System.Console.Hawk.Config.Base+++getResult :: FilePath -> ParseResult a -> IO a+getResult _ (ParseOk x) = return x+getResult sourceFile (ParseFailed srcLoc err) = do+ putStrLn $ printf "error parsing file %s:%s: %s" sourceFile (show srcLoc) err+ exitFailure+++parseExtensions :: FilePath -> IO [ExtensionName]+parseExtensions sourceFile = do+ result <- getTopPragmas <$> readFile sourceFile + listExtensions <$> getResult sourceFile result+ where+ listExtensions :: [ModulePragma] -> [ExtensionName]+ listExtensions = map getName . concat . mapMaybe extensionNames+ + extensionNames :: ModulePragma -> Maybe [Name]+ extensionNames (LanguagePragma _ names) = Just names+ extensionNames _ = Nothing+ + getName :: Name -> ExtensionName+ getName (Ident s) = s+ getName (Symbol s) = s+++parseModules :: FilePath -> [ExtensionName] -> IO [QualifiedModule]+parseModules sourceFile extensions = do+ result <- parseFileWithExts extensions' sourceFile+ Module _ _ _ _ _ importDeclarations _ <- getResult sourceFile result+ return $ concatMap toHintModules importDeclarations+ where+ extensions' :: [Extension]+ extensions' = map parseExtension extensions+ + toHintModules :: ImportDecl -> [QualifiedModule]+ toHintModules importDecl =+ case importDecl of+ ImportDecl _ (ModuleName mn) False _ _ Nothing _ -> [(mn,Nothing)]+ ImportDecl _ (ModuleName mn) False _ _ (Just (ModuleName s)) _ ->+ [(mn,Nothing),(mn,Just s)]+ ImportDecl _ (ModuleName mn) True _ _ Nothing _ -> [(mn,Just mn)]+ ImportDecl _ (ModuleName mn) True _ _ (Just (ModuleName s)) _ ->+ [(mn,Just s)]+++-- the configuration format is designed to look like a Haskell module,+-- so we just return the whole file.+parseSource :: FilePath -> IO Source+parseSource = C8.readFile