packages feed

ronn-1.0.0.0: src/Ronn/AST.hs

-- |
--
-- Module      : Ronn.AST
-- Copyright   : (c) 2024 Patrick Brisbin
-- License     : AGPL-3
-- Maintainer  : pbrisbin@gmail.com
-- Stability   : experimental
-- Portability : POSIX
module Ronn.AST
  ( Ronn (..)
  , RonnSection (..)
  , RonnContent (..)
  , RonnDefinition (..)
  , RonnGroup (..)
  , RonnLine (..)
  , RonnPart (..)

    -- * References
  , ManRef (..)
  , ManSection (..)
  , manSectionNumber
  ) where

import Prelude

import Data.String (IsString (..))
import Data.Text (Text, pack)

data Ronn = Ronn
  { name :: ManRef
  , description :: [RonnPart]
  , sections :: [RonnSection]
  }

data RonnSection = RonnSection
  { name :: Text
  , content :: [RonnContent]
  }

data RonnContent
  = RonnDefinitions [RonnDefinition]
  | RonnGroups [RonnGroup]

instance IsString RonnContent where
  fromString = RonnGroups . pure . fromString

data RonnDefinition = RonnDefinition
  { name :: RonnPart
  , description :: RonnLine
  -- ^ A line of nested description is required
  , content :: Maybe [RonnContent]
  -- ^ More content can be optionally nested
  }

data RonnGroup
  = RonnTitle ManRef [RonnPart]
  | RonnHeader Text
  | RonnLines [RonnLine]

instance IsString RonnGroup where
  fromString = RonnLines . pure . fromString

newtype RonnLine = RonnLine
  { unwrap :: [RonnPart]
  }

instance IsString RonnLine where
  fromString = RonnLine . pure . fromString

data RonnPart
  = -- | 'RonnConcat' joins 'RonnPart's without automaticaly inserting a space
    --
    -- The following expressions are equivalent:
    --
    -- - @'ronnLineToText' $ 'RonnLine' [p1, p2]@
    -- - @'ronnLineToText' $ 'RonnLine' ['RonnConcat' [p1, " ", p2]]@
    -- - @'ronnLineToText' $ 'RonnLine' [p1 <> " " <> p2]@
    --
    -- Using the 'Semigroup' instance should be preferred, in case the AST
    -- changes in the future.
    RonnConcat [RonnPart]
  | RonnCode RonnPart
  | RonnUserInput RonnPart
  | RonnStrong RonnPart
  | RonnVariable RonnPart
  | RonnEphasis RonnPart
  | RonnBrackets RonnPart
  | RonnParens RonnPart
  | RonnRef ManRef
  | RonnRaw Text

instance IsString RonnPart where
  fromString = RonnRaw . pack

instance Semigroup RonnPart where
  RonnConcat as <> RonnConcat bs = RonnConcat $ as <> bs
  RonnConcat as <> b = RonnConcat $ as <> [b]
  a <> RonnConcat bs = RonnConcat $ a : bs
  a <> b = RonnConcat [a, b]

instance Monoid RonnPart where
  mempty = RonnConcat []

data ManRef = ManRef
  { name :: Text
  , section :: ManSection
  }

-- TODO: enum?
newtype ManSection = ManSection Int

manSectionNumber :: ManSection -> Int
manSectionNumber (ManSection n) = n