packages feed

tdlib-gen-0.4.0: src/Processing.hs

module Processing where

import Data.Either (rights)
import Data.List (partition)
import qualified Data.Map.Strict as M
import Data.Text (Text)
import Language.TL.AST
import qualified Language.TL.AST as A
import Language.TL.Comment
import Language.TL.Types
import qualified Language.TL.Types as T
import Text.Megaparsec

getComment :: Comment -> Text
getComment (LineComment t) = t
getComment (BlockComment t) = t

type CombD = ([[Attr]], Combinator)

parseComments :: [Comment] -> [[Attr]]
parseComments = rights . fmap (runParser attrs "" . getComment)

hasClassAttr :: [Attr] -> Bool
hasClassAttr = any (\(t, _) -> t == "class")

classDesc :: [[Attr]] -> Maybe Text
classDesc l =
  let (t, _) = partition hasClassAttr l
      l' = if null t then [] else head t
      desc = lookup "description" l'
   in desc

constructDoc :: [[Attr]] -> Doc
constructDoc = M.fromList . concat

tyConName :: Type -> Text
tyConName (A.Type t) = t
tyConName (A.TypeApp (A.Type t) _) = t
tyConName _ = error "not a type constructor"

combType :: Combinator -> Text
combType = tyConName . A.resType

splitDecls :: [CombD] -> ([CombD], [CombD])
splitDecls decls =
  let (_, c) = head decls
      tyIdent = combType c
   in break (\(_, c') -> combType c' /= tyIdent) decls

formADT :: [CombD] -> ADT
formADT decls =
  let (l, c) = head decls
      ann = classDesc l
      name = combType c
      constructors = fmap snd decls
   in ADT {..}

oneADT :: [CombD] -> (ADT, [CombD])
oneADT decls =
  let (h, rest) = splitDecls decls
   in (formADT h, rest)

filterAnnDecl :: [AnnDecl] -> [CombD]
filterAnnDecl [] = []
filterAnnDecl (AnnDecl cmt (T.Combinator c) : xs) =
  let l = parseComments cmt
   in (l, combConv (constructDoc l) c) : filterAnnDecl xs
filterAnnDecl (_ : xs) = filterAnnDecl xs

declBlockToADT :: [CombD] -> [ADT]
declBlockToADT [] = []
declBlockToADT decls =
  let (h, rest) = oneADT decls
   in h : declBlockToADT rest

declBlockToFun :: [CombD] -> [Function]
declBlockToFun = fmap (\(_, c) -> Function c)

convProgram :: Program -> ([ADT], [Function])
convProgram prog =
  foldr
    ( \blk (c, f) -> case blk of
        FunDeclBlk decls -> (c, (declBlockToFun $ filterAnnDecl decls) <> f)
        TypeDeclBlk decls -> ((declBlockToADT $ filterAnnDecl decls) <> c, f)
    )
    ([], [])
    prog