{-|
Copyright        : (c) Galois, Inc. 2025
Maintainer       : Langston Barrett <langston@galois.com>

For the sake of correctness, consistency, and concision, it is desirable to
declaratively specify the types of arguments expected by 'Cmd.Command's. These
specifications are used to:

* Parse said arguments (see 'match')
* Generate usage hints for @usage@ (see 'usage')
* Perform syntax highlighting (see "Lang.Crucible.Debug.Style")
* Provide tab-completions (see 'complete')

Perhaps the simplest workable argument specification would be a list of basic
types (e.g., integer, string). However, the purpose of the command language
is to be convenient for interactive use. In particular, users should not have
to remember the names of several variants of a command that do fundamentally
similar tasks. To provide sufficient flexibilty to unite such variants under
a single command, the specification should allow (in increasing order of
sophistication):

* sequencing (i.e., arity higher than 1),
* disjunction (at the very least, in a limited form), and
* quantification (optionality, repetition, and in particular, variable arity).

To justify the necessity of such features, consider the following examples of
each, taken from the bread-and-butter commands of the @gdb@ command language:

* sequencing: @break@ takes several (optional) arguments
* optionality: @step@ takes an optional integer argument
* quantification: @delete@ takes a variable number of breakpoint numbers

The basic list-of-types specification clearly lacks such features. Luckily,
there is a well-understood specification language that allows all of the above,
namely, regular expressions. Thus, the debugger\'s commands are specified
using the facilities provided by "Lang.Crucible.Debug.Regex". The tokens of
the regular expression are basic types (see 'ArgTypeRepr'). Operations like
'derivative' are used internally to provide the high-level functionality
described at the beginning of this documentation.

Commands that are not well-suited to this kind of argument validation can simply
accept @TEXT*@ and perform their own parsing (or not) at the cost of lacking
helpful documentation and completion. This is exactly the specification of the
comment (@#@) command, for example.
-}

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ExplicitNamespaces #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}

module Lang.Crucible.Debug.Arg
  ( Arg(..)
  -- * Parsers
  , ArgParseError(..)
  , ArgParser(..)
  , convert
  -- * Operations
  , match
  , derivative
  , types
  , usage
  ) where

import Data.Coerce (coerce)
import Data.Foldable qualified as Foldable
import Data.Kind (Type)
import Data.Map.Strict (Map)
import Data.Map.Strict qualified as Map
import Data.Parameterized.Some (Some(Some))
import Data.Parameterized.SymbolRepr (SymbolRepr, symbolRepr)
import Data.Parameterized.TraversableFC (fmapFC)
import Data.Sequence (Seq)
import Data.Text qualified as Text
import Lang.Crucible.Debug.Arg.Type (type ArgType(..), ArgTypeRepr(..))
import Lang.Crucible.Debug.Breakpoint (Breakpoint(BreakFunction))
import Lang.Crucible.Debug.Command qualified as Cmd
import Lang.Crucible.Debug.Regex qualified as Rgx
import Prelude hiding (Int)
import Prelude qualified as Prelude
import Prettyprinter qualified as PP
import Text.Read (readMaybe)
import What4.FunctionName qualified as W4

type Arg :: Type -> ArgType -> Type
data Arg cExt i where
  ABreakpoint :: Breakpoint -> Arg cExt 'TBreakpoint
  ACommand :: Cmd.Command cExt -> Arg cExt 'TCommand
  AExactly :: SymbolRepr s -> Arg cExt ('TExactly s)
  AFunction :: W4.FunctionName -> Arg cExt 'TFunction
  AInt :: Prelude.Int -> Arg cExt 'TInt
  APath :: Text.Text -> Arg cExt 'TPath
  AText :: Text.Text -> Arg cExt 'TText

data ArgParseError
  = NotACommand Text.Text
  | NotAnInt Text.Text
  | NotExactly Text.Text Text.Text
  deriving Int -> ArgParseError -> ShowS
[ArgParseError] -> ShowS
ArgParseError -> String
(Int -> ArgParseError -> ShowS)
-> (ArgParseError -> String)
-> ([ArgParseError] -> ShowS)
-> Show ArgParseError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ArgParseError -> ShowS
showsPrec :: Int -> ArgParseError -> ShowS
$cshow :: ArgParseError -> String
show :: ArgParseError -> String
$cshowList :: [ArgParseError] -> ShowS
showList :: [ArgParseError] -> ShowS
Show

instance PP.Pretty ArgParseError where
  pretty :: forall ann. ArgParseError -> Doc ann
pretty =
    \case
      NotACommand Text
t -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
PP.squotes (Text -> Doc ann
forall ann. Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
PP.pretty Text
t) Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
PP.<+> Doc ann
"is not a command"
      NotAnInt Text
t -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
PP.squotes (Text -> Doc ann
forall ann. Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
PP.pretty Text
t) Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
PP.<+> Doc ann
"is not an integer"
      NotExactly Text
e Text
t -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
PP.squotes (Text -> Doc ann
forall ann. Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
PP.pretty Text
t) Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
PP.<+> Doc ann
"is not" Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
PP.<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
PP.squotes (Text -> Doc ann
forall ann. Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
PP.pretty Text
e)

newtype ArgParser cExt t
  = ArgParser { forall cExt (t :: ArgType).
ArgParser cExt t -> TokenParser Text ArgParseError (Arg cExt) t
_runArgParser :: Rgx.TokenParser Text.Text ArgParseError (Arg cExt) t }

argParser :: (Text.Text -> Either ArgParseError (Arg cExt t)) -> ArgParser cExt t
argParser :: forall cExt (t :: ArgType).
(Text -> Either ArgParseError (Arg cExt t)) -> ArgParser cExt t
argParser = TokenParser Text ArgParseError (Arg cExt) t -> ArgParser cExt t
forall cExt (t :: ArgType).
TokenParser Text ArgParseError (Arg cExt) t -> ArgParser cExt t
ArgParser (TokenParser Text ArgParseError (Arg cExt) t -> ArgParser cExt t)
-> ((Text -> Either ArgParseError (Arg cExt t))
    -> TokenParser Text ArgParseError (Arg cExt) t)
-> (Text -> Either ArgParseError (Arg cExt t))
-> ArgParser cExt t
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Either ArgParseError (Arg cExt t))
-> TokenParser Text ArgParseError (Arg cExt) t
forall k tok e (f :: k -> *) (t :: k).
(tok -> Either e (f t)) -> TokenParser tok e f t
Rgx.TokenParser

-- | Helper, not exported
maybeToEither :: e -> Maybe a -> Either e a
maybeToEither :: forall e a. e -> Maybe a -> Either e a
maybeToEither e
e =
  \case
    Maybe a
Nothing -> e -> Either e a
forall a b. a -> Either a b
Left e
e
    Just a
a -> a -> Either e a
forall a b. b -> Either a b
Right a
a

breakpoint :: ArgParser cExt 'TBreakpoint
breakpoint :: forall cExt. ArgParser cExt 'TBreakpoint
breakpoint =
  (Text -> Either ArgParseError (Arg cExt 'TBreakpoint))
-> ArgParser cExt 'TBreakpoint
forall cExt (t :: ArgType).
(Text -> Either ArgParseError (Arg cExt t)) -> ArgParser cExt t
argParser (Arg cExt 'TBreakpoint
-> Either ArgParseError (Arg cExt 'TBreakpoint)
forall a b. b -> Either a b
Right (Arg cExt 'TBreakpoint
 -> Either ArgParseError (Arg cExt 'TBreakpoint))
-> (Text -> Arg cExt 'TBreakpoint)
-> Text
-> Either ArgParseError (Arg cExt 'TBreakpoint)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Breakpoint -> Arg cExt 'TBreakpoint
forall cExt. Breakpoint -> Arg cExt 'TBreakpoint
ABreakpoint (Breakpoint -> Arg cExt 'TBreakpoint)
-> (Text -> Breakpoint) -> Text -> Arg cExt 'TBreakpoint
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FunctionName -> Breakpoint
BreakFunction (FunctionName -> Breakpoint)
-> (Text -> FunctionName) -> Text -> Breakpoint
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> FunctionName
W4.functionNameFromText)

function :: ArgParser cExt 'TFunction
function :: forall cExt. ArgParser cExt 'TFunction
function =
  (Text -> Either ArgParseError (Arg cExt 'TFunction))
-> ArgParser cExt 'TFunction
forall cExt (t :: ArgType).
(Text -> Either ArgParseError (Arg cExt t)) -> ArgParser cExt t
argParser (Arg cExt 'TFunction -> Either ArgParseError (Arg cExt 'TFunction)
forall a b. b -> Either a b
Right (Arg cExt 'TFunction -> Either ArgParseError (Arg cExt 'TFunction))
-> (Text -> Arg cExt 'TFunction)
-> Text
-> Either ArgParseError (Arg cExt 'TFunction)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FunctionName -> Arg cExt 'TFunction
forall cExt. FunctionName -> Arg cExt 'TFunction
AFunction (FunctionName -> Arg cExt 'TFunction)
-> (Text -> FunctionName) -> Text -> Arg cExt 'TFunction
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  Text -> FunctionName
W4.functionNameFromText)

command :: Cmd.CommandExt cExt -> ArgParser cExt 'TCommand
command :: forall cExt. CommandExt cExt -> ArgParser cExt 'TCommand
command CommandExt cExt
cExt = (Text -> Either ArgParseError (Arg cExt 'TCommand))
-> ArgParser cExt 'TCommand
forall cExt (t :: ArgType).
(Text -> Either ArgParseError (Arg cExt t)) -> ArgParser cExt t
argParser (\Text
t -> Command cExt -> Arg cExt 'TCommand
forall cExt. Command cExt -> Arg cExt 'TCommand
ACommand (Command cExt -> Arg cExt 'TCommand)
-> Either ArgParseError (Command cExt)
-> Either ArgParseError (Arg cExt 'TCommand)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ArgParseError
-> Maybe (Command cExt) -> Either ArgParseError (Command cExt)
forall e a. e -> Maybe a -> Either e a
maybeToEither (Text -> ArgParseError
NotACommand Text
t) (CommandExt cExt -> Text -> Maybe (Command cExt)
forall cExt. CommandExt cExt -> Text -> Maybe (Command cExt)
Cmd.parse CommandExt cExt
cExt Text
t))

exactly :: SymbolRepr s -> ArgParser cExt ('TExactly s)
exactly :: forall (s :: Symbol) cExt.
SymbolRepr s -> ArgParser cExt ('TExactly s)
exactly SymbolRepr s
s =
  (Text -> Either ArgParseError (Arg cExt ('TExactly s)))
-> ArgParser cExt ('TExactly s)
forall cExt (t :: ArgType).
(Text -> Either ArgParseError (Arg cExt t)) -> ArgParser cExt t
argParser ((Text -> Either ArgParseError (Arg cExt ('TExactly s)))
 -> ArgParser cExt ('TExactly s))
-> (Text -> Either ArgParseError (Arg cExt ('TExactly s)))
-> ArgParser cExt ('TExactly s)
forall a b. (a -> b) -> a -> b
$ \Text
t ->
    if Text
t Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== SymbolRepr s -> Text
forall (nm :: Symbol). SymbolRepr nm -> Text
symbolRepr SymbolRepr s
s
    then Arg cExt ('TExactly s)
-> Either ArgParseError (Arg cExt ('TExactly s))
forall a b. b -> Either a b
Right (SymbolRepr s -> Arg cExt ('TExactly s)
forall (s :: Symbol) cExt. SymbolRepr s -> Arg cExt ('TExactly s)
AExactly SymbolRepr s
s)
    else ArgParseError -> Either ArgParseError (Arg cExt ('TExactly s))
forall a b. a -> Either a b
Left (Text -> Text -> ArgParseError
NotExactly (SymbolRepr s -> Text
forall (nm :: Symbol). SymbolRepr nm -> Text
symbolRepr SymbolRepr s
s) Text
t)

int :: ArgParser cExt 'TInt
int :: forall cExt. ArgParser cExt 'TInt
int = (Text -> Either ArgParseError (Arg cExt 'TInt))
-> ArgParser cExt 'TInt
forall cExt (t :: ArgType).
(Text -> Either ArgParseError (Arg cExt t)) -> ArgParser cExt t
argParser (\Text
t -> Int -> Arg cExt 'TInt
forall cExt. Int -> Arg cExt 'TInt
AInt (Int -> Arg cExt 'TInt)
-> Either ArgParseError Int
-> Either ArgParseError (Arg cExt 'TInt)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ArgParseError -> Maybe Int -> Either ArgParseError Int
forall e a. e -> Maybe a -> Either e a
maybeToEither (Text -> ArgParseError
NotAnInt Text
t) (String -> Maybe Int
forall a. Read a => String -> Maybe a
readMaybe (Text -> String
Text.unpack Text
t)))

path :: ArgParser cExt 'TPath
path :: forall cExt. ArgParser cExt 'TPath
path = (Text -> Either ArgParseError (Arg cExt 'TPath))
-> ArgParser cExt 'TPath
forall cExt (t :: ArgType).
(Text -> Either ArgParseError (Arg cExt t)) -> ArgParser cExt t
argParser (Arg cExt 'TPath -> Either ArgParseError (Arg cExt 'TPath)
forall a b. b -> Either a b
Right (Arg cExt 'TPath -> Either ArgParseError (Arg cExt 'TPath))
-> (Text -> Arg cExt 'TPath)
-> Text
-> Either ArgParseError (Arg cExt 'TPath)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Arg cExt 'TPath
forall cExt. Text -> Arg cExt 'TPath
APath)

text :: ArgParser cExt 'TText
text :: forall cExt. ArgParser cExt 'TText
text = (Text -> Either ArgParseError (Arg cExt 'TText))
-> ArgParser cExt 'TText
forall cExt (t :: ArgType).
(Text -> Either ArgParseError (Arg cExt t)) -> ArgParser cExt t
argParser (Arg cExt 'TText -> Either ArgParseError (Arg cExt 'TText)
forall a b. b -> Either a b
Right (Arg cExt 'TText -> Either ArgParseError (Arg cExt 'TText))
-> (Text -> Arg cExt 'TText)
-> Text
-> Either ArgParseError (Arg cExt 'TText)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Arg cExt 'TText
forall cExt. Text -> Arg cExt 'TText
AText)

parser :: Cmd.CommandExt cExt -> ArgTypeRepr t -> ArgParser cExt t
parser :: forall cExt (t :: ArgType).
CommandExt cExt -> ArgTypeRepr t -> ArgParser cExt t
parser CommandExt cExt
cExt =
  \case
    ArgTypeRepr t
TBreakpointRepr -> ArgParser cExt t
ArgParser cExt 'TBreakpoint
forall cExt. ArgParser cExt 'TBreakpoint
breakpoint
    ArgTypeRepr t
TCommandRepr -> CommandExt cExt -> ArgParser cExt 'TCommand
forall cExt. CommandExt cExt -> ArgParser cExt 'TCommand
command CommandExt cExt
cExt
    TExactlyRepr SymbolRepr s
s -> SymbolRepr s -> ArgParser cExt ('TExactly s)
forall (s :: Symbol) cExt.
SymbolRepr s -> ArgParser cExt ('TExactly s)
exactly SymbolRepr s
s
    ArgTypeRepr t
TFunctionRepr -> ArgParser cExt t
ArgParser cExt 'TFunction
forall cExt. ArgParser cExt 'TFunction
function
    ArgTypeRepr t
TIntRepr -> ArgParser cExt t
ArgParser cExt 'TInt
forall cExt. ArgParser cExt 'TInt
int
    ArgTypeRepr t
TPathRepr -> ArgParser cExt t
ArgParser cExt 'TPath
forall cExt. ArgParser cExt 'TPath
path
    ArgTypeRepr t
TTextRepr -> ArgParser cExt t
ArgParser cExt 'TText
forall cExt. ArgParser cExt 'TText
text

convert ::
  Cmd.CommandExt cExt ->
  Rgx.RegexRepr ArgTypeRepr r ->
  Rgx.RegexRepr (ArgParser cExt) r
convert :: forall cExt (r :: Regex ArgType).
CommandExt cExt
-> RegexRepr ArgTypeRepr r -> RegexRepr (ArgParser cExt) r
convert CommandExt cExt
cExt = (forall (x :: ArgType). ArgTypeRepr x -> ArgParser cExt x)
-> forall (x :: Regex ArgType).
   RegexRepr ArgTypeRepr x -> RegexRepr (ArgParser cExt) x
forall k l (t :: (k -> *) -> l -> *) (f :: k -> *) (g :: k -> *).
FunctorFC t =>
(forall (x :: k). f x -> g x) -> forall (x :: l). t f x -> t g x
forall (f :: ArgType -> *) (g :: ArgType -> *).
(forall (x :: ArgType). f x -> g x)
-> forall (x :: Regex ArgType). RegexRepr f x -> RegexRepr g x
fmapFC (CommandExt cExt -> ArgTypeRepr x -> ArgParser cExt x
forall cExt (t :: ArgType).
CommandExt cExt -> ArgTypeRepr t -> ArgParser cExt t
parser CommandExt cExt
cExt)

match ::
  forall r cExt.
  Rgx.RegexRepr (ArgParser cExt) r ->
  [Text.Text] ->
  Either (Rgx.MatchError Text.Text ArgParseError) (Rgx.Match (Arg cExt) r)
match :: forall (r :: Regex ArgType) cExt.
RegexRepr (ArgParser cExt) r
-> [Text]
-> Either (MatchError Text ArgParseError) (Match (Arg cExt) r)
match RegexRepr (ArgParser cExt) r
r [Text]
toks =
  case forall {k} tok e (g :: k -> *) (r :: Regex k).
RegexRepr (TokenParser tok e g) r
-> [tok] -> Either (MatchError tok e) (Match g r, [tok])
forall tok e (g :: ArgType -> *) (r :: Regex ArgType).
RegexRepr (TokenParser tok e g) r
-> [tok] -> Either (MatchError tok e) (Match g r, [tok])
Rgx.match @_ @_ @(Arg cExt) (RegexRepr (ArgParser cExt) r
-> RegexRepr (TokenParser Text ArgParseError (Arg cExt)) r
forall a b. Coercible a b => a -> b
coerce RegexRepr (ArgParser cExt) r
r) [Text]
toks of
    Left MatchError Text ArgParseError
e -> MatchError Text ArgParseError
-> Either (MatchError Text ArgParseError) (Match (Arg cExt) r)
forall a b. a -> Either a b
Left MatchError Text ArgParseError
e
    Right (Match (Arg cExt) r
m, []) -> Match (Arg cExt) r
-> Either (MatchError Text ArgParseError) (Match (Arg cExt) r)
forall a b. b -> Either a b
Right Match (Arg cExt) r
m
    Right (Match (Arg cExt) r
_, [Text]
as) -> MatchError Text ArgParseError
-> Either (MatchError Text ArgParseError) (Match (Arg cExt) r)
forall a b. a -> Either a b
Left ([Text] -> MatchError Text ArgParseError
forall tok e. [tok] -> MatchError tok e
Rgx.NotEmpty [Text]
as)

derivative ::
  forall cExt r.
  Cmd.CommandExt cExt ->
  Text.Text ->
  Rgx.RegexRepr ArgTypeRepr r ->
  Rgx.DerivativeResult ArgTypeRepr (Arg cExt)
derivative :: forall cExt (r :: Regex ArgType).
CommandExt cExt
-> Text
-> RegexRepr ArgTypeRepr r
-> DerivativeResult ArgTypeRepr (Arg cExt)
derivative CommandExt cExt
cExt =
  (forall (t :: ArgType).
 ArgTypeRepr t -> TokenParser Text ArgParseError (Arg cExt) t)
-> Text
-> RegexRepr ArgTypeRepr r
-> DerivativeResult ArgTypeRepr (Arg cExt)
forall {k} (f :: k -> *) tok e (g :: k -> *) (r :: Regex k).
(forall (t :: k). f t -> TokenParser tok e g t)
-> tok -> RegexRepr f r -> DerivativeResult f g
Rgx.derivative
    (forall a b. Coercible a b => a -> b
forall a b. Coercible a b => a -> b
coerce @_ @(Rgx.TokenParser _ ArgParseError (Arg cExt) _) (ArgParser cExt t -> TokenParser Text ArgParseError (Arg cExt) t)
-> (ArgTypeRepr t -> ArgParser cExt t)
-> ArgTypeRepr t
-> TokenParser Text ArgParseError (Arg cExt) t
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CommandExt cExt -> ArgTypeRepr t -> ArgParser cExt t
forall cExt (t :: ArgType).
CommandExt cExt -> ArgTypeRepr t -> ArgParser cExt t
parser CommandExt cExt
cExt)

-- | Get the potential types that the regex assigns each argument, plus what it
-- would assign to the next one.
types ::
  forall r cExt.
  Cmd.CommandExt cExt ->
  Rgx.RegexRepr ArgTypeRepr r ->
  [Text.Text] ->
  (Map Text.Text (Seq (Some ArgTypeRepr)), Seq (Some ArgTypeRepr))
types :: forall (r :: Regex ArgType) cExt.
CommandExt cExt
-> RegexRepr ArgTypeRepr r
-> [Text]
-> (Map Text (Seq (Some ArgTypeRepr)), Seq (Some ArgTypeRepr))
types CommandExt cExt
cExt RegexRepr ArgTypeRepr r
r =
  \case
    [] -> (Map Text (Seq (Some ArgTypeRepr))
forall k a. Map k a
Map.empty, RegexRepr ArgTypeRepr r -> Seq (Some ArgTypeRepr)
forall {k} (f :: k -> *) (r :: Regex k).
RegexRepr f r -> Seq (Some f)
Rgx.nextLits RegexRepr ArgTypeRepr r
r)
    (Text
t : [Text]
ts) ->
      case CommandExt cExt
-> Text
-> RegexRepr ArgTypeRepr r
-> DerivativeResult ArgTypeRepr (Arg cExt)
forall cExt (r :: Regex ArgType).
CommandExt cExt
-> Text
-> RegexRepr ArgTypeRepr r
-> DerivativeResult ArgTypeRepr (Arg cExt)
derivative CommandExt cExt
cExt Text
t RegexRepr ArgTypeRepr r
r of
        Rgx.DerivativeResult (Some RegexRepr ArgTypeRepr x
r') Seq (Some (Arg cExt))
_ ->
          let (Map Text (Seq (Some ArgTypeRepr))
m, Seq (Some ArgTypeRepr)
final) = CommandExt cExt
-> RegexRepr ArgTypeRepr x
-> [Text]
-> (Map Text (Seq (Some ArgTypeRepr)), Seq (Some ArgTypeRepr))
forall (r :: Regex ArgType) cExt.
CommandExt cExt
-> RegexRepr ArgTypeRepr r
-> [Text]
-> (Map Text (Seq (Some ArgTypeRepr)), Seq (Some ArgTypeRepr))
types CommandExt cExt
cExt RegexRepr ArgTypeRepr x
r' [Text]
ts in
          ((Seq (Some ArgTypeRepr)
 -> Seq (Some ArgTypeRepr) -> Seq (Some ArgTypeRepr))
-> Text
-> Seq (Some ArgTypeRepr)
-> Map Text (Seq (Some ArgTypeRepr))
-> Map Text (Seq (Some ArgTypeRepr))
forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
Map.insertWith Seq (Some ArgTypeRepr)
-> Seq (Some ArgTypeRepr) -> Seq (Some ArgTypeRepr)
forall a. Semigroup a => a -> a -> a
(<>) Text
t (RegexRepr ArgTypeRepr r -> Seq (Some ArgTypeRepr)
forall {k} (f :: k -> *) (r :: Regex k).
RegexRepr f r -> Seq (Some f)
Rgx.nextLits RegexRepr ArgTypeRepr r
r) Map Text (Seq (Some ArgTypeRepr))
m, Seq (Some ArgTypeRepr)
final)

usage :: Rgx.RegexRepr ArgTypeRepr r -> [PP.Doc ann]
usage :: forall (r :: Regex ArgType) ann.
RegexRepr ArgTypeRepr r -> [Doc ann]
usage RegexRepr ArgTypeRepr r
r =
  Seq (Doc ann) -> [Doc ann]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
Foldable.toList (Seq (Doc ann) -> [Doc ann]) -> Seq (Doc ann) -> [Doc ann]
forall a b. (a -> b) -> a -> b
$
    (Some (Sugar ArgTypeRepr) -> Doc ann)
-> Seq (Some (Sugar ArgTypeRepr)) -> Seq (Doc ann)
forall a b. (a -> b) -> Seq a -> Seq b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\(Some Sugar ArgTypeRepr x
r') -> Doc ann
-> (forall (t :: ArgType). ArgTypeRepr t -> Doc ann)
-> Sugar ArgTypeRepr x
-> Doc ann
forall {k} ann (f :: k -> *) (r :: Regex k).
Doc ann
-> (forall (t :: k). f t -> Doc ann) -> Sugar f r -> Doc ann
Rgx.prettySugar Doc ann
" " ArgTypeRepr t -> Doc ann
forall a ann. Pretty a => a -> Doc ann
forall ann. ArgTypeRepr t -> Doc ann
forall (t :: ArgType). ArgTypeRepr t -> Doc ann
PP.pretty Sugar ArgTypeRepr x
r') (Sugar ArgTypeRepr r -> Seq (Some (Sugar ArgTypeRepr))
forall {k} (f :: k -> *) (r :: Regex k).
Sugar f r -> Seq (Some (Sugar f))
Rgx.liftOrs (RegexRepr ArgTypeRepr r -> Sugar ArgTypeRepr r
forall {k} (f :: k -> *) (r :: Regex k).
TestEquality f =>
RegexRepr f r -> Sugar f r
Rgx.sugar RegexRepr ArgTypeRepr r
r))