module CmdLineParser3(
-- Parser type:
P,
-- Parser constructors:
token,cmd,(!),(<@),(#@),chk,nil,many,arg,kw,opt,flag,(--:),
-- Parser destructors:
run,usage,parseAll
) where
import Pretty
import Monad(ap,mplus)
import Maybe(isJust)
import System(getArgs)
import PM
import qualified Grammar as G
import Grammar hiding (Many)
infixl 3 <@,`chk`,#@
infix 2 :--,--:
infixr 1 :!,!
chk p p' = const `fmap` p `Ap` p'
cmd s p = Nil p `chk` kw s
f #@ p = fmap f p
(!) = (:!)
(<@) = Ap
(--:) = (:--)
nil = Nil
token = Token
arg = token Just
many p = Many id id p
kw s = token check s
where check a = if a==s then Just () else Nothing
opt p = fmap Just p ! nil Nothing
flag s = isJust `fmap` opt (kw s)
usage prefix p = render (usageDoc prefix p)
usageDoc prefix p =
(text "Usage:" $$
nest 2 (nest 2 (text prefix<+>main) $$
if null aux then empty else text "where" $$ vcat aux))
where
(main,aux) = ppGrammar (grammar p)
grammar :: P a -> Grammar
grammar p =
case p of
Nil _ -> Empty
Ap p1 p2 -> Seq (grammar p1) (grammar p2)
Named s p -> Nonterminal s (grammar p)
p :-- s -> grammar p :--- s
Token to s -> Terminal s
p1 :! Nil _ -> Opt (grammar p1)
p1 :! p2 -> Alt (grammar p1) (grammar p2)
Many _ _ p -> G.Many (grammar p)
parse :: P res -> PM res
parse p =
case p of
Nil res -> return res
Ap pf pa -> parse pf `ap` parse pa
Named _ p -> parse p
p :-- s -> parse p
Token check s -> tokenP check s
p1 :! p2 -> parse p1 `mplus` parse p2
Many to from p ->
parse (cons `fmap` p `Ap` Many to from p ! Nil (from []))
where cons x xs = from (x:to xs)