Use OPTIONS rather than OPTIONS_GHC for pragmas
[ghc-hetmet.git] / compiler / main / CmdLineParser.hs
1 -----------------------------------------------------------------------------
2 --
3 -- Command-line parser
4 --
5 -- This is an abstract command-line parser used by both StaticFlags and
6 -- DynFlags.
7 --
8 -- (c) The University of Glasgow 2005
9 --
10 -----------------------------------------------------------------------------
11
12 {-# OPTIONS -w #-}
13 -- The above warning supression flag is a temporary kludge.
14 -- While working on this module you are encouraged to remove it and fix
15 -- any warnings in the module. See
16 --     http://hackage.haskell.org/trac/ghc/wiki/CodingStyle#Warnings
17 -- for details
18
19 module CmdLineParser (
20         processArgs, OptKind(..), 
21         CmdLineP(..), getCmdLineState, putCmdLineState
22   ) where
23
24 #include "HsVersions.h"
25
26 import Util     ( maybePrefixMatch, notNull, removeSpaces )
27 #ifdef DEBUG
28 import Panic    ( assertPanic )
29 #endif
30
31 data OptKind m          -- Suppose the flag is -f
32         = NoArg (m ())                  -- -f all by itself
33         | HasArg    (String -> m ())    -- -farg or -f arg
34         | SepArg    (String -> m ())    -- -f arg
35         | Prefix    (String -> m ())    -- -farg 
36         | OptPrefix (String -> m ())    -- -f or -farg (i.e. the arg is optional)
37         | OptIntSuffix (Maybe Int -> m ())      -- -f or -f=n; pass n to fn
38         | IntSuffix (Int -> m ())               -- -f or -f=n; pass n to fn
39         | PassFlag  (String -> m ())    -- -f; pass "-f" fn
40         | AnySuffix (String -> m ())    -- -f or -farg; pass entire "-farg" to fn
41         | PrefixPred    (String -> Bool) (String -> m ())
42         | AnySuffixPred (String -> Bool) (String -> m ())
43  
44 processArgs :: Monad m
45             => [(String, OptKind m)]    -- cmdline parser spec
46             -> [String]                 -- args
47             -> m (
48                 [String],  -- spare args
49                 [String]   -- errors
50                 )
51 processArgs spec args = process spec args [] []
52   where
53     process _spec [] spare errs =
54       return (reverse spare, reverse errs)
55     
56     process spec (dash_arg@('-':arg):args) spare errs =
57       case findArg spec arg of
58         Just (rest,action) -> 
59            case processOneArg action rest arg args of
60              Left err            -> process spec args spare (err:errs)
61              Right (action,rest) -> action >> process spec rest spare errs
62         Nothing -> process spec args (dash_arg:spare) errs
63     
64     process spec (arg:args) spare errs = 
65       process spec args (arg:spare) errs
66
67
68 processOneArg :: OptKind m -> String -> String -> [String]
69               -> Either String (m (), [String])
70 processOneArg action rest arg args 
71   = let dash_arg = '-' : arg
72         rest_no_eq = dropEq rest
73     in case action of
74         NoArg  a -> ASSERT(null rest) Right (a, args)
75
76         HasArg f | notNull rest_no_eq -> Right (f rest_no_eq, args)
77                  | otherwise    -> case args of
78                                     [] -> missingArgErr dash_arg
79                                     (arg1:args1) -> Right (f arg1, args1)
80
81         SepArg f -> case args of
82                         [] -> unknownFlagErr dash_arg
83                         (arg1:args1) -> Right (f arg1, args1)
84
85         Prefix f | notNull rest_no_eq -> Right (f rest_no_eq, args)
86                  | otherwise  -> unknownFlagErr dash_arg
87         
88         PrefixPred p f | notNull rest_no_eq -> Right (f rest_no_eq, args)
89                        | otherwise          -> unknownFlagErr dash_arg
90         
91         PassFlag f  | notNull rest -> unknownFlagErr dash_arg
92                     | otherwise    -> Right (f dash_arg, args)
93
94         OptIntSuffix f | null rest                     -> Right (f Nothing,  args)
95                        | Just n <- parseInt rest_no_eq -> Right (f (Just n), args)
96                        | otherwise -> Left ("malformed integer argument in " ++ dash_arg)
97
98         IntSuffix f | Just n <- parseInt rest_no_eq -> Right (f n, args)
99                     | otherwise -> Left ("malformed integer argument in " ++ dash_arg)
100
101         OptPrefix f       -> Right (f rest_no_eq, args)
102         AnySuffix f       -> Right (f dash_arg, args)
103         AnySuffixPred p f -> Right (f dash_arg, args)
104
105
106 findArg :: [(String,OptKind a)] -> String -> Maybe (String,OptKind a)
107 findArg spec arg
108   = case [ (removeSpaces rest, k) 
109          | (pat,k)   <- spec, 
110            Just rest <- [maybePrefixMatch pat arg],
111            arg_ok k rest arg ] 
112     of
113         []      -> Nothing
114         (one:_) -> Just one
115
116 arg_ok (NoArg _)            rest arg = null rest
117 arg_ok (HasArg _)           rest arg = True
118 arg_ok (SepArg _)           rest arg = null rest
119 arg_ok (Prefix _)           rest arg = notNull rest
120 arg_ok (PrefixPred p _)     rest arg = notNull rest && p (dropEq rest)
121 arg_ok (OptIntSuffix _)     rest arg = True
122 arg_ok (IntSuffix _)        rest arg = True
123 arg_ok (OptPrefix _)        rest arg = True
124 arg_ok (PassFlag _)         rest arg = null rest 
125 arg_ok (AnySuffix _)        rest arg = True
126 arg_ok (AnySuffixPred p _)  rest arg = p arg
127
128 parseInt :: String -> Maybe Int
129 -- Looks for "433" or "=342", with no trailing gubbins
130 --   n or =n      => Just n
131 --   gibberish    => Nothing
132 parseInt s = case reads s of
133                 ((n,""):_) -> Just n
134                 other      -> Nothing
135
136 dropEq :: String -> String
137 -- Discards a leading equals sign
138 dropEq ('=' : s) = s
139 dropEq s         = s
140
141 unknownFlagErr :: String -> Either String a
142 unknownFlagErr f = Left ("unrecognised flag: " ++ f)
143
144 missingArgErr :: String -> Either String a
145 missingArgErr f = Left ("missing argument for flag: " ++ f)
146
147 -- -----------------------------------------------------------------------------
148 -- A state monad for use in the command-line parser
149
150 newtype CmdLineP s a = CmdLineP { runCmdLine :: s -> (a, s) }
151
152 instance Monad (CmdLineP s) where
153         return a = CmdLineP $ \s -> (a, s)
154         m >>= k  = CmdLineP $ \s -> let
155                 (a, s') = runCmdLine m s
156                 in runCmdLine (k a) s'
157
158 getCmdLineState   = CmdLineP $ \s -> (s,s)
159 putCmdLineState s = CmdLineP $ \_ -> ((),s)