packages feed

crucible-debug-0.1.0: src/Lang/Crucible/Debug/Command.hs

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

{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}

module Lang.Crucible.Debug.Command
  ( Command(..)
  , CommandExt(..)
  , voidExts
  , allCmds
  , name
  , abbrev
  , parse
  , detail
  , help
  , regex
  ) where

import Data.List qualified as List
import Data.Parameterized.Some (Some)
import Data.Text (Text)
import Data.Void (Void, absurd)
import Lang.Crucible.Debug.Arg.Type (ArgTypeRepr)
import Lang.Crucible.Debug.Command.Base qualified as BCmd
import Lang.Crucible.Debug.Regex qualified as Rgx
import Prettyprinter qualified as PP

data CommandExt cExt
  = CommandExt
  { -- | Used in 'abbrev', 'parse'
    extAbbrev :: cExt -> Text
  , extList :: [cExt]
    -- | Multi-line help string. Used in 'detail'.
    --
    -- This is always displayed as a new paragraph following 'extHelp', so it
    -- should not repeat the information there.
    --
    -- Should be long-form prose, with proper capitalization and punctuation.
    -- Should not rely on being shown in monospaced font.
  , extDetail :: cExt -> Maybe Text
    -- | Single-line help string. Used in 'help'.
    --
    -- The first letter should be capitalized, it should not end in a period.
    -- It should probably be less than about 70 characters long.
  , extHelp :: cExt -> Text
    -- | Used in 'help', 'parse'
  , extName :: cExt -> Text
    -- | Used in 'help'
  , extRegex :: cExt -> Some (Rgx.RegexRepr ArgTypeRepr)
  }

voidExts :: CommandExt Void
voidExts =
  CommandExt
  { extAbbrev = absurd
  , extDetail = absurd
  , extHelp = absurd
  , extList = []
  , extName = absurd
  , extRegex = absurd
  }

data Command cExt
  = Base BCmd.BaseCommand
  | Ext cExt
  deriving (Functor, Show)

instance PP.Pretty cExt => PP.Pretty (Command cExt) where
  pretty =
    \case
      Base bCmd -> PP.pretty bCmd
      Ext xCmd -> PP.pretty xCmd

name :: CommandExt cExt -> Command cExt -> Text
name cExts =
  \case
    Base bCmd -> BCmd.name bCmd
    Ext xCmd -> extName cExts xCmd

abbrev :: CommandExt cExt -> Command cExt -> Text
abbrev cExts =
  \case
    Base bCmd -> BCmd.abbrev bCmd
    Ext xCmd -> extAbbrev cExts xCmd

allCmds :: CommandExt cExt -> [Command cExt]
allCmds cExts = map Base [minBound..maxBound] ++ map Ext (extList cExts)

parse :: CommandExt cExt -> Text -> Maybe (Command cExt)
parse cExts txt =
  List.find (\c -> name cExts c == txt || abbrev cExts c == txt) (allCmds cExts)

detail :: CommandExt cExt -> Command cExt -> Maybe Text
detail cExts =
  \case
    Base bCmd -> BCmd.detail bCmd
    Ext xCmd -> extDetail cExts xCmd

help :: CommandExt cExt -> Command cExt -> Text
help cExts =
  \case
    Base bCmd -> BCmd.help bCmd
    Ext xCmd -> extHelp cExts xCmd

regex :: CommandExt cExt -> Command cExt -> Some (Rgx.RegexRepr ArgTypeRepr)
regex cExts =
  \case
    Base bCmd -> BCmd.regex bCmd
    Ext xCmd -> extRegex cExts xCmd