forked from DanielG/ghc-mod
-
Notifications
You must be signed in to change notification settings - Fork 0
/
GHCMod.hs
122 lines (107 loc) · 3.88 KB
/
GHCMod.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
{-# LANGUAGE DeriveDataTypeable #-}
module Main where
import Browse
import Check
import Control.Applicative
import Control.Exception
import Data.Typeable
import Info
import Lang
import Lint
import List
import Prelude
import System.Console.GetOpt
import System.Directory
import System.Environment (getArgs)
import System.IO (hPutStr, hPutStrLn, stderr)
import Types
----------------------------------------------------------------
usage :: String
usage = "ghc-mod version 0.5.1\n"
++ "Usage:\n"
++ "\t ghc-mod [-l] list\n"
++ "\t ghc-mod [-l] lang\n"
++ "\t ghc-mod [-l] browse <module> [<module> ...]\n"
++ "\t ghc-mod check <HaskellFile>\n"
++ "\t ghc-mod type <HaskellFile> <module> <expression>\n"
++ "\t ghc-mod info <HaskellFile> <module> <expression>\n"
++ "\t ghc-mod [-h opt] lint <HaskellFile>\n"
++ "\t ghc-mod boot\n"
++ "\t ghc-mod help\n"
----------------------------------------------------------------
defaultOptions :: Options
defaultOptions = Options {
convert = toPlain
, hlintOpts = []
}
argspec :: [OptDescr (Options -> Options)]
argspec = [ Option "l" ["tolisp"]
(NoArg (\opts -> opts { convert = toLisp }))
"print as a list of Lisp"
, Option "h" ["hlintOpt"]
(ReqArg (\h opts -> opts { hlintOpts = h : hlintOpts opts }) "hlintOpt")
"hint to be ignored"
]
parseArgs :: [OptDescr (Options -> Options)] -> [String] -> (Options, [String])
parseArgs spec argv
= case getOpt Permute spec argv of
(o,n,[] ) -> (foldl (flip id) defaultOptions o, n)
(_,_,errs) -> throw (CmdArg errs)
----------------------------------------------------------------
data GHCModError = SafeList
| NoSuchCommand String
| CmdArg [String]
| FileNotExist String deriving (Show, Typeable)
instance Exception GHCModError
----------------------------------------------------------------
main :: IO ()
main = flip catches handlers $ do
args <- getArgs
let (opt,cmdArg) = parseArgs argspec args
res <- case safelist cmdArg 0 of
"browse" -> concat <$> mapM (browseModule opt) (tail cmdArg)
"list" -> listModules opt
"check" -> withFile (checkSyntax opt) (safelist cmdArg 1)
"type" -> withFile (typeExpr opt (safelist cmdArg 2) (safelist cmdArg 3)) (safelist cmdArg 1)
"info" -> withFile (infoExpr opt (safelist cmdArg 2) (safelist cmdArg 3)) (safelist cmdArg 1)
"lint" -> withFile (lintSyntax opt) (safelist cmdArg 1)
"lang" -> listLanguages opt
"boot" -> do
mods <- listModules opt
langs <- listLanguages opt
pre <- browseModule opt "Prelude"
return $ mods ++ langs ++ pre
cmd -> throw (NoSuchCommand cmd)
putStr res
where
handlers = [Handler handler1, Handler handler2]
handler1 :: ErrorCall -> IO ()
handler1 e = print e -- for debug
handler2 :: GHCModError -> IO ()
handler2 SafeList = printUsage
handler2 (NoSuchCommand cmd) = do
hPutStrLn stderr $ "\"" ++ cmd ++ "\" not supported"
printUsage
handler2 (CmdArg errs) = do
mapM_ (hPutStr stderr) errs
printUsage
handler2 (FileNotExist file) = do
hPutStrLn stderr $ "\"" ++ file ++ "\" not found"
printUsage
printUsage = hPutStrLn stderr $ "\n" ++ usageInfo usage argspec
withFile cmd file = do
exist <- doesFileExist file
if exist
then cmd file
else throw (FileNotExist file)
safelist xs idx
| length xs <= idx = throw SafeList
| otherwise = xs !! idx
----------------------------------------------------------------
toLisp :: [String] -> String
toLisp ms = "(" ++ unwords quoted ++ ")\n"
where
quote x = "\"" ++ x ++ "\""
quoted = map quote ms
toPlain :: [String] -> String
toPlain = unlines