{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ImpredicativeTypes #-}
{-# LANGUAGE RankNTypes #-}

-- | LibClang is a Haskell binding to the libclang library, a compiler
-- front-end for C-family languages. It allows you to produce and walk
-- an AST, get a list of diagnostic warnings and errors, perform code
-- completion, and more.
--
-- Your starting point for using LibClang should be this module, which
-- exports the 'ClangT' monad and the functions you'll need to start
-- analyzing source code. The other modules in this library, such as
-- "Clang.Cursor" and "Clang.Type", are meant to be imported
-- qualified, and provide the functions you'll need to get more
-- detailed information about the AST.
module Clang (
-- * Parsing
  parseSourceFile

-- * Traversing the AST
, FFI.CursorList
, getChildren
, getDescendants
, getDeclarations
, getReferences
, getDeclarationsAndReferences

, FFI.ParentedCursorList
, getParentedDescendants
, getParentedDeclarations
, getParentedReferences
, getParentedDeclarationsAndReferences

-- * Traversing inclusions
, FFI.Inclusion(..)
, FFI.InclusionList
, getInclusions

-- * The ClangT monad
, ClangT
, Clang
, ClangBase
, ClangValue(..)
, ClangValueList(..)
, clangScope

-- * Clang AST types
, FFI.AvailabilityKind(..)
, FFI.CursorKind(..)
, FFI.LinkageKind(..)
, FFI.LanguageKind(..)
, FFI.Cursor
, FFI.CursorSet
, FFI.ParentedCursor(..)
, FFI.ObjCPropertyAttrKind(..)
, FFI.ObjCDeclQualifierKind(..)
, FFI.NameRefFlags(..)
, FFI.Version(..)
, FFI.PlatformAvailability(..)
, FFI.PlatformAvailabilityInfo(..)
, FFI.Diagnostic
, FFI.DiagnosticSet
, FFI.File
, FFI.Remapping
, FFI.SourceLocation
, FFI.SourceRange
, FFI.ClangString
, FFI.Token
, FFI.TokenKind(..)
, FFI.Index
, FFI.TranslationUnit
, FFI.UnsavedFile
, FFI.Module (..)
, FFI.Type
, FFI.TypeKind(..)
, FFI.CallingConv(..)
, FFI.CXXAccessSpecifier(..)
, FFI.TypeLayoutError(..)
, FFI.RefQualifierKind(..)
) where

import qualified Data.Vector as DV

import qualified Clang.Internal.FFI as FFI
import qualified Clang.Index as Index
import Clang.Internal.Monad
import qualified Clang.TranslationUnit as TU

-- | Parses a source file using libclang and allows you to analyze the
-- resulting AST using a callback.
--
-- More flexible alternatives to 'parseSourceFile' are available in
-- "Clang.Index" and "Clang.TranslationUnit".
parseSourceFile :: ClangBase m
                => FilePath  -- ^ Source filename
                -> [String]  -- ^ Clang-compatible compilation arguments
                -> (forall s. FFI.TranslationUnit s -> ClangT s m a)  -- ^ Callback
                -> m (Maybe a)
parseSourceFile path args f =
  Index.withNew False False $ \index ->
    TU.withParsed index (Just path) args DV.empty [] f

-- | Gets an 'FFI.CursorList' of the children of this 'FFI.Cursor'.
getChildren :: ClangBase m => FFI.Cursor s' -> ClangT s m (FFI.CursorList s)
getChildren = FFI.getChildren

-- | Gets an 'FFI.CursorList' of all descendants of this
-- 'FFI.Cursor'. If you are planning on visiting all the descendants
-- anyway, this is often more efficient than calling 'getChildren'
-- repeatedly. The descendants are listed according to a preorder
-- traversal of the AST.
getDescendants :: ClangBase m => FFI.Cursor s' -> ClangT s m (FFI.CursorList s)
getDescendants = FFI.getDescendants

-- | Like 'getDescendants', but each descendant is annotated with its
-- parent AST node. This provides enough information to replicate the
-- preorder traversal of the AST, but maintains the performance
-- benefits relative to 'getChildren'.
getParentedDescendants :: ClangBase m => FFI.Cursor s' -> ClangT s m (FFI.ParentedCursorList s)
getParentedDescendants = FFI.getParentedDescendants

-- | Gets an 'FFI.CursorList' of all declarations in this 'FFI.TranslationUnit'.
getDeclarations :: ClangBase m => FFI.TranslationUnit s' -> ClangT s m (FFI.CursorList s)
getDeclarations = FFI.getDeclarations

-- | Like 'getDeclarations', but each declaration is annotated with
-- its parent AST node.
getParentedDeclarations :: ClangBase m => FFI.TranslationUnit s'
                        -> ClangT s m (FFI.ParentedCursorList s)
getParentedDeclarations = FFI.getParentedDeclarations

-- | Gets an 'FFI.CursorList' of all references in this 'FFI.TranslationUnit'.
getReferences :: ClangBase m => FFI.TranslationUnit s' -> ClangT s m (FFI.CursorList s)
getReferences = FFI.getReferences

-- | Like 'getReferences', but each reference is annotated with
-- its parent AST node.
getParentedReferences :: ClangBase m => FFI.TranslationUnit s'
                      -> ClangT s m (FFI.ParentedCursorList s)
getParentedReferences = FFI.getParentedReferences

-- | Gets two 'FFI.CursorList's, one containing all declarations in
-- this 'FFI.TranslationUnit', and another containing all
-- references. If you need both lists, this is more efficient than
-- calling 'getDeclarations' and 'getReferences' individually, as it
-- only traverses the AST once.
getDeclarationsAndReferences :: ClangBase m => FFI.TranslationUnit s'
                             -> ClangT s m (FFI.CursorList s, FFI.CursorList s)
getDeclarationsAndReferences = FFI.getDeclarationsAndReferences

-- | Like 'getDeclarationsAndReferences', but each reference is annotated with
-- its parent AST node.
getParentedDeclarationsAndReferences :: ClangBase m => FFI.TranslationUnit s'
                                     -> ClangT s m (FFI.ParentedCursorList s,
                                                    FFI.ParentedCursorList s)
getParentedDeclarationsAndReferences = FFI.getParentedDeclarationsAndReferences

-- | Gets all inclusions in this 'FFI.TranslationUnit'.
getInclusions :: ClangBase m => FFI.TranslationUnit s' -> ClangT s m (FFI.InclusionList s)
getInclusions = FFI.getInclusions

-- | 'Clang' is a specialization of the 'ClangT' monad to 'IO',
-- provided as a convenience. If you have a more complicated monad
-- stack, you may find it useful to define your own 'Clang'-like
-- type synonym.
type Clang s a = ClangT s IO a