Add addAlternatives, Add/Expose varPartDesc
parent
2e245432a5
commit
7d56c9ae1d
|
@ -73,7 +73,9 @@ module UI.Butcher.Monadic.Command
|
||||||
, addCmdPartMany
|
, addCmdPartMany
|
||||||
, addCmdPartInp
|
, addCmdPartInp
|
||||||
, addCmdPartManyInp
|
, addCmdPartManyInp
|
||||||
|
, addAlternatives
|
||||||
, ManyUpperBound (..)
|
, ManyUpperBound (..)
|
||||||
|
, varPartDesc
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ module UI.Butcher.Monadic.Internal.Core
|
||||||
, addCmdHidden
|
, addCmdHidden
|
||||||
, addNullCmd
|
, addNullCmd
|
||||||
, addCmdImpl
|
, addCmdImpl
|
||||||
|
, addAlternatives
|
||||||
, reorderStart
|
, reorderStart
|
||||||
, reorderStop
|
, reorderStop
|
||||||
, checkCmdParser
|
, checkCmdParser
|
||||||
|
@ -31,6 +32,7 @@ module UI.Butcher.Monadic.Internal.Core
|
||||||
, runCmdParserA
|
, runCmdParserA
|
||||||
, runCmdParserAExt
|
, runCmdParserAExt
|
||||||
, mapOut
|
, mapOut
|
||||||
|
, varPartDesc
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
|
@ -236,6 +238,25 @@ addCmdHidden
|
||||||
addCmdHidden str sub =
|
addCmdHidden str sub =
|
||||||
liftF $ CmdParserChild (Just str) Hidden sub (pure ()) ()
|
liftF $ CmdParserChild (Just str) Hidden sub (pure ()) ()
|
||||||
|
|
||||||
|
-- | Add a list of sub-parsers one of which will be selected and used based
|
||||||
|
-- on the provided predicate function. The input elements consist of:
|
||||||
|
-- a) a name used for the command description of the output,
|
||||||
|
-- b) a predicate function; the first True predicate determines which element
|
||||||
|
-- to apply
|
||||||
|
-- c) a CmdParser.
|
||||||
|
addAlternatives
|
||||||
|
:: Typeable p
|
||||||
|
=> [(String, String -> Bool, CmdParser f out p)]
|
||||||
|
-> CmdParser f out p
|
||||||
|
addAlternatives elems = liftF $ CmdParserAlternatives desc alts id
|
||||||
|
where
|
||||||
|
desc = PartAlts $ [PartVariable s | (s, _, _) <- elems]
|
||||||
|
alts = [(a, b) | (_, a, b) <- elems]
|
||||||
|
|
||||||
|
-- | Create a simple PartDesc from a string.
|
||||||
|
varPartDesc :: String -> PartDesc
|
||||||
|
varPartDesc = PartVariable
|
||||||
|
|
||||||
-- | Add a new nameless child command in the current context. Nameless means
|
-- | Add a new nameless child command in the current context. Nameless means
|
||||||
-- that this command matches the empty input, i.e. will always apply.
|
-- that this command matches the empty input, i.e. will always apply.
|
||||||
-- This feature is experimental and CommandDesc pretty-printing might not
|
-- This feature is experimental and CommandDesc pretty-printing might not
|
||||||
|
@ -334,13 +355,13 @@ checkCmdParser mTopLevel cmdParser =
|
||||||
<$ desc { _cmd_parts = Data.Foldable.toList descs }
|
<$ desc { _cmd_parts = Data.Foldable.toList descs }
|
||||||
StackLayer _ _ _ -> Left "unclosed ReorderStart or GroupStart"
|
StackLayer _ _ _ -> Left "unclosed ReorderStart or GroupStart"
|
||||||
processMain
|
processMain
|
||||||
:: CmdParser f out ()
|
:: CmdParser f out a
|
||||||
-> MultiRWSS.MultiRWST
|
-> MultiRWSS.MultiRWST
|
||||||
'[]
|
'[]
|
||||||
'[]
|
'[]
|
||||||
'[CommandDesc out, CmdDescStack]
|
'[CommandDesc out, CmdDescStack]
|
||||||
(Either String)
|
(Either String)
|
||||||
()
|
a
|
||||||
processMain = \case
|
processMain = \case
|
||||||
Pure x -> return x
|
Pure x -> return x
|
||||||
Free (CmdParserHelp h next) -> do
|
Free (CmdParserHelp h next) -> do
|
||||||
|
@ -428,6 +449,21 @@ checkCmdParser mTopLevel cmdParser =
|
||||||
stackCur <- mGet
|
stackCur <- mGet
|
||||||
mSet $ StackLayer mempty "" stackCur
|
mSet $ StackLayer mempty "" stackCur
|
||||||
processMain next
|
processMain next
|
||||||
|
Free (CmdParserAlternatives desc alts nextF) -> do
|
||||||
|
mModify (descStackAdd desc)
|
||||||
|
states <- MultiRWSS.mGetRawS
|
||||||
|
let go
|
||||||
|
:: [(String -> Bool, CmdParser f out p)]
|
||||||
|
-> MultiRWSS.MultiRWST
|
||||||
|
'[] '[] '[CommandDesc out, CmdDescStack] (Either String) p
|
||||||
|
go [] = lift $ Left $ "Empty alternatives"
|
||||||
|
go [(_, alt)] = processMain alt
|
||||||
|
go ((_, alt1):altr) = do
|
||||||
|
case MultiRWSS.runMultiRWSTNil $ MultiRWSS.withMultiStates states (processMain alt1) of
|
||||||
|
Left{} -> go altr
|
||||||
|
Right (p, states') -> MultiRWSS.mPutRawS states' $> p
|
||||||
|
p <- go alts
|
||||||
|
processMain $ nextF p
|
||||||
|
|
||||||
monadMisuseError :: a
|
monadMisuseError :: a
|
||||||
monadMisuseError =
|
monadMisuseError =
|
||||||
|
@ -530,7 +566,8 @@ runCmdParserAExt mTopLevel inputInitial cmdParser =
|
||||||
res =
|
res =
|
||||||
if null errs' then Right cmd' else Left $ ParsingError errs' inputRest
|
if null errs' then Right cmd' else Left $ ParsingError errs' inputRest
|
||||||
processMain
|
processMain
|
||||||
:: CmdParser f out ()
|
:: -- forall a
|
||||||
|
CmdParser f out ()
|
||||||
-> MultiRWSS.MultiRWS
|
-> MultiRWSS.MultiRWS
|
||||||
'[]
|
'[]
|
||||||
'[[String]]
|
'[[String]]
|
||||||
|
@ -540,7 +577,7 @@ runCmdParserAExt mTopLevel inputInitial cmdParser =
|
||||||
()]
|
()]
|
||||||
(f ())
|
(f ())
|
||||||
processMain = \case
|
processMain = \case
|
||||||
Pure () -> return $ pure $ ()
|
Pure () -> return $ pure ()
|
||||||
Free (CmdParserHelp h next) -> do
|
Free (CmdParserHelp h next) -> do
|
||||||
cmd :: CommandDesc out <- mGet
|
cmd :: CommandDesc out <- mGet
|
||||||
mSet $ cmd { _cmd_help = Just h }
|
mSet $ cmd { _cmd_help = Just h }
|
||||||
|
@ -551,7 +588,7 @@ runCmdParserAExt mTopLevel inputInitial cmdParser =
|
||||||
$ cmd { _cmd_synopsis = Just $ PP.fsep $ fmap PP.text $ List.words s }
|
$ cmd { _cmd_synopsis = Just $ PP.fsep $ fmap PP.text $ List.words s }
|
||||||
processMain next
|
processMain next
|
||||||
Free (CmdParserPeekDesc nextF) -> do
|
Free (CmdParserPeekDesc nextF) -> do
|
||||||
parser <- mGet
|
parser :: CmdParser f out () <- mGet
|
||||||
-- partialDesc :: CommandDesc out <- mGet
|
-- partialDesc :: CommandDesc out <- mGet
|
||||||
-- partialStack :: CmdDescStack <- mGet
|
-- partialStack :: CmdDescStack <- mGet
|
||||||
-- run the rest without affecting the actual stack
|
-- run the rest without affecting the actual stack
|
||||||
|
@ -813,6 +850,18 @@ runCmdParserAExt mTopLevel inputInitial cmdParser =
|
||||||
actRest <- processMain fr
|
actRest <- processMain fr
|
||||||
return $ acts *> actRest
|
return $ acts *> actRest
|
||||||
else monadMisuseError
|
else monadMisuseError
|
||||||
|
Free (CmdParserAlternatives desc alts nextF) -> do
|
||||||
|
input :: Input <- mGet
|
||||||
|
case input of
|
||||||
|
InputString str
|
||||||
|
| Just (_, sub) <- find (\(predicate, _sub) -> predicate str) alts ->
|
||||||
|
processMain $ sub >>= nextF
|
||||||
|
InputArgs (str:_)
|
||||||
|
| Just (_, sub) <- find (\(predicate, _sub) -> predicate str) alts ->
|
||||||
|
processMain $ sub >>= nextF
|
||||||
|
_ -> do
|
||||||
|
mTell ["could not parse any of " ++ getPartSeqDescPositionName desc]
|
||||||
|
processMain $ nextF monadMisuseError
|
||||||
|
|
||||||
reorderPartGather
|
reorderPartGather
|
||||||
:: ( MonadMultiState Int m
|
:: ( MonadMultiState Int m
|
||||||
|
@ -854,6 +903,7 @@ runCmdParserAExt mTopLevel inputInitial cmdParser =
|
||||||
CmdParserReorderStart{} -> restCase
|
CmdParserReorderStart{} -> restCase
|
||||||
CmdParserGrouped{} -> restCase
|
CmdParserGrouped{} -> restCase
|
||||||
CmdParserGroupEnd{} -> restCase
|
CmdParserGroupEnd{} -> restCase
|
||||||
|
CmdParserAlternatives{} -> restCase
|
||||||
where
|
where
|
||||||
restCase = do
|
restCase = do
|
||||||
mTell ["Did not find expected ReorderStop after the reordered parts"]
|
mTell ["Did not find expected ReorderStop after the reordered parts"]
|
||||||
|
@ -873,7 +923,7 @@ runCmdParserAExt mTopLevel inputInitial cmdParser =
|
||||||
Free (CmdParserPeekInput nextF) -> do
|
Free (CmdParserPeekInput nextF) -> do
|
||||||
childrenGather $ nextF $ inputToString inputInitial
|
childrenGather $ nextF $ inputToString inputInitial
|
||||||
Free (CmdParserPeekDesc nextF) -> do
|
Free (CmdParserPeekDesc nextF) -> do
|
||||||
parser <- mGet
|
parser :: CmdParser f out () <- mGet
|
||||||
-- partialDesc :: CommandDesc out <- mGet
|
-- partialDesc :: CommandDesc out <- mGet
|
||||||
-- partialStack :: CmdDescStack <- mGet
|
-- partialStack :: CmdDescStack <- mGet
|
||||||
-- run the rest without affecting the actual stack
|
-- run the rest without affecting the actual stack
|
||||||
|
@ -1010,8 +1060,8 @@ runCmdParserAExt mTopLevel inputInitial cmdParser =
|
||||||
-- user needs to use check for that purpose instead.
|
-- user needs to use check for that purpose instead.
|
||||||
processCmdShallow
|
processCmdShallow
|
||||||
:: (MonadMultiState (CommandDesc out) m, MonadMultiState CmdDescStack m)
|
:: (MonadMultiState (CommandDesc out) m, MonadMultiState CmdDescStack m)
|
||||||
=> CmdParserF f out (m ())
|
=> CmdParserF f out (m a)
|
||||||
-> m ()
|
-> m a
|
||||||
processCmdShallow = \case
|
processCmdShallow = \case
|
||||||
CmdParserHelp h next -> do
|
CmdParserHelp h next -> do
|
||||||
cmd :: CommandDesc out <- mGet
|
cmd :: CommandDesc out <- mGet
|
||||||
|
@ -1062,15 +1112,13 @@ runCmdParserAExt mTopLevel inputInitial cmdParser =
|
||||||
CmdParserGroupEnd next -> do
|
CmdParserGroupEnd next -> do
|
||||||
stackCur <- mGet
|
stackCur <- mGet
|
||||||
case stackCur of
|
case stackCur of
|
||||||
StackBottom{} -> do
|
StackBottom{} -> pure ()
|
||||||
return ()
|
StackLayer _descs "" _up -> pure ()
|
||||||
StackLayer _descs "" _up -> do
|
|
||||||
return ()
|
|
||||||
StackLayer descs groupName up -> do
|
StackLayer descs groupName up -> do
|
||||||
mSet $ descStackAdd
|
mSet $ descStackAdd
|
||||||
(PartRedirect groupName (PartSeq (Data.Foldable.toList descs)))
|
(PartRedirect groupName (PartSeq (Data.Foldable.toList descs)))
|
||||||
up
|
up
|
||||||
next
|
next
|
||||||
CmdParserReorderStop next -> do
|
CmdParserReorderStop next -> do
|
||||||
stackCur <- mGet
|
stackCur <- mGet
|
||||||
case stackCur of
|
case stackCur of
|
||||||
|
@ -1083,6 +1131,10 @@ runCmdParserAExt mTopLevel inputInitial cmdParser =
|
||||||
stackCur <- mGet
|
stackCur <- mGet
|
||||||
mSet $ StackLayer mempty "" stackCur
|
mSet $ StackLayer mempty "" stackCur
|
||||||
next
|
next
|
||||||
|
CmdParserAlternatives _ [] _ -> error "empty alternatives"
|
||||||
|
CmdParserAlternatives desc ((_, alt):_) nextF -> do
|
||||||
|
mModify (descStackAdd desc)
|
||||||
|
nextF =<< iterM processCmdShallow alt
|
||||||
|
|
||||||
failureCurrentShallowRerun
|
failureCurrentShallowRerun
|
||||||
:: ( m ~ MultiRWSS.MultiRWST r w s m0
|
:: ( m ~ MultiRWSS.MultiRWST r w s m0
|
||||||
|
@ -1093,7 +1145,7 @@ runCmdParserAExt mTopLevel inputInitial cmdParser =
|
||||||
)
|
)
|
||||||
=> m ()
|
=> m ()
|
||||||
failureCurrentShallowRerun = do
|
failureCurrentShallowRerun = do
|
||||||
parser <- mGet
|
parser :: CmdParser f out () <- mGet
|
||||||
cmd :: CommandDesc out <-
|
cmd :: CommandDesc out <-
|
||||||
MultiRWSS.withMultiStateS emptyCommandDesc
|
MultiRWSS.withMultiStateS emptyCommandDesc
|
||||||
$ iterM processCmdShallow parser
|
$ iterM processCmdShallow parser
|
||||||
|
@ -1161,7 +1213,7 @@ takeCommandChild key = do
|
||||||
return r
|
return r
|
||||||
|
|
||||||
-- | map over the @out@ type argument
|
-- | map over the @out@ type argument
|
||||||
mapOut :: (outa -> outb) -> CmdParser f outa () -> CmdParser f outb ()
|
mapOut :: (outa -> outb) -> CmdParser f outa a -> CmdParser f outb a
|
||||||
mapOut f = hoistFree $ \case
|
mapOut f = hoistFree $ \case
|
||||||
CmdParserHelp doc r -> CmdParserHelp doc r
|
CmdParserHelp doc r -> CmdParserHelp doc r
|
||||||
CmdParserSynopsis s r -> CmdParserSynopsis s r
|
CmdParserSynopsis s r -> CmdParserSynopsis s r
|
||||||
|
@ -1175,11 +1227,15 @@ mapOut f = hoistFree $ \case
|
||||||
CmdParserPartManyInp bound desc fp fa fr
|
CmdParserPartManyInp bound desc fp fa fr
|
||||||
CmdParserChild s vis child act r ->
|
CmdParserChild s vis child act r ->
|
||||||
CmdParserChild s vis (mapOut f child) act r
|
CmdParserChild s vis (mapOut f child) act r
|
||||||
CmdParserImpl out r -> CmdParserImpl (f out) r
|
CmdParserImpl out r -> CmdParserImpl (f out) r
|
||||||
CmdParserReorderStart r -> CmdParserReorderStart r
|
CmdParserReorderStart r -> CmdParserReorderStart r
|
||||||
CmdParserReorderStop r -> CmdParserReorderStop r
|
CmdParserReorderStop r -> CmdParserReorderStop r
|
||||||
CmdParserGrouped s r -> CmdParserGrouped s r
|
CmdParserGrouped s r -> CmdParserGrouped s r
|
||||||
CmdParserGroupEnd r -> CmdParserGroupEnd r
|
CmdParserGroupEnd r -> CmdParserGroupEnd r
|
||||||
|
CmdParserAlternatives desc alts r -> CmdParserAlternatives
|
||||||
|
desc
|
||||||
|
[ (predicate, mapOut f sub) | (predicate, sub) <- alts ]
|
||||||
|
r
|
||||||
|
|
||||||
-- cmdActionPartial :: CommandDesc out -> Either String out
|
-- cmdActionPartial :: CommandDesc out -> Either String out
|
||||||
-- cmdActionPartial = maybe (Left err) Right . _cmd_out
|
-- cmdActionPartial = maybe (Left err) Right . _cmd_out
|
||||||
|
|
|
@ -80,6 +80,7 @@ data CmdParserF f out a
|
||||||
| CmdParserReorderStop a
|
| CmdParserReorderStop a
|
||||||
| CmdParserGrouped String a
|
| CmdParserGrouped String a
|
||||||
| CmdParserGroupEnd a
|
| CmdParserGroupEnd a
|
||||||
|
| forall p . Typeable p => CmdParserAlternatives PartDesc [((String -> Bool), CmdParser f out p)] (p -> a)
|
||||||
|
|
||||||
-- | The CmdParser monad type. It is a free monad over some functor but users
|
-- | The CmdParser monad type. It is a free monad over some functor but users
|
||||||
-- of butcher don't need to know more than that 'CmdParser' is a 'Monad'.
|
-- of butcher don't need to know more than that 'CmdParser' is a 'Monad'.
|
||||||
|
|
Loading…
Reference in New Issue