packages feed

anatomy-0.4: src/Anatomy/Types.hs

{-# LANGUAGE DeriveDataTypeable, TypeSynonymInstances #-}
module Anatomy.Types where

import Control.Monad.State
import Data.IORef
import Data.Typeable
import Text.Parsec (SourcePos)

import Atomo.Lexer.Base (TaggedToken)
import qualified Atomo.Types as AT

data Title =
    Title
        { titleText :: Segment
        , titleTag :: Maybe Segment
        , titleVersion :: Maybe Segment
        }
    deriving (Show, Typeable)

data Style
    = None
    | TOC
    | Unnumbered
    | Annotated
    | Class String
    | Styles [Style]
    deriving (Eq, Show, Typeable)

data BindingKey
    = KeywordKey [String]
    | SingleKey String
    deriving (Eq, Ord, Show, Typeable)

data Definition =
    Definition
        { defThumb :: AT.Expr
        , defContracts :: [AT.Expr]
        , defReturn :: AT.Expr
        }
    deriving Show

data Section =
    Section
        { sectionID :: SectionRef
        , sectionTitle :: Title
        , sectionStyle :: Style    -- style flags (e.g. TOC)
        , sectionBody :: [Segment] -- un-built content with parts from step 1 removed
        , sectionBindings :: [BindingKey]
        , sectionParent :: Maybe SectionRef
        , subSections :: [Section] -- included sections
        , sectionDepth :: Int
        , sectionNumber :: Int
        , sectionPath :: FilePath
        , sectionA :: AT.Value
        }
    deriving (Show, Typeable)

type SectionRef = IORef Section

instance Show SectionRef where
    show _ = "SectionRef"

type AVM = StateT Section AT.VM

data Segment
    = Chunk String
    | KeywordDispatch [String] [Segment]
    | SingleDispatch String
    | Atomo AT.Expr
    | Nested [Segment]
    | SectionReference Int
    | TableOfContents
    | FullTableOfContents
    | InlineDefinition Definition (Maybe Segment)
    deriving Show

data TOCTree
    = Node String String
    | Branch String String [TOCTree]
    deriving Show

data AToken
    = ATokChunk String
    | ATokKeyword [String] [TaggedAToken]
    | ATokSingle String
    | ATokAtomo [TaggedToken]
    | ATokNested [TaggedAToken]
    | ATokDefinition [TaggedToken] [[TaggedToken]] [TaggedToken]
    deriving Show

data TaggedAToken =
    TaggedAToken
        { taToken :: AToken
        , taLocation :: SourcePos
        }
    deriving Show

styleToClass :: Style -> String
styleToClass (Class s) = s
styleToClass TOC = "table-of-contents"
styleToClass Unnumbered = "unnumbered"
styleToClass Annotated = "annotated"
styleToClass None = "normal"
styleToClass (Styles ss) = unwords (map styleToClass ss)

addStyle :: Style -> Style -> Style
addStyle a None = a
addStyle (Styles a) (Styles b) = Styles (a ++ b)
addStyle a (Styles b) = Styles (a:b)
addStyle (Styles a) b = Styles (a ++ [b])
addStyle a b = Styles [a, b]

styleMatch :: Style -> Style -> Bool
styleMatch a b | a == b = True
styleMatch a (Styles b) = any (styleMatch a) b
styleMatch _ _ = False

defKey :: Definition -> BindingKey
defKey d =
    case defThumb d of
        AT.EDispatch { AT.eMessage = AT.Keyword { AT.mNames = ns } } -> KeywordKey ns
        AT.EDispatch { AT.eMessage = AT.Single { AT.mName = n } } -> SingleKey n
        _ -> error $ "no defKey for: " ++ show (defThumb d)

bindingID :: BindingKey -> String
bindingID (KeywordKey ns) = "definition_" ++ concatMap (++ ":") ns
bindingID (SingleKey n) = "definition_" ++ n

runAVM :: AVM a -> Section -> AVM a
runAVM a s = lift (evalStateT a s)

runAVM' :: AVM a -> Section -> AT.VM a
runAVM' = evalStateT

newSection :: (Section -> Section) -> IO Section
newSection f = do
    r <- newIORef undefined
    writeIORef r (sec r)
    return (sec r)
  where
    sec r = f Section
        { sectionID = r
        , sectionTitle = Title (Chunk "Untitled") Nothing Nothing
        , sectionStyle = None
        , sectionBody = []
        , sectionBindings = []
        , sectionParent = Nothing
        , subSections = []
        , sectionDepth = 0
        , sectionNumber = 1
        , sectionPath = ""
        , sectionA = error "no section anatomy"
        }