libclang-bindings-0.1.0.0: clang-tutorial/clang-tutorial.hs
-- * Haskell translation of the @libclang@ tutorial
--
-- See <https://clang.llvm.org/docs/LibClang.html>
module Main (main) where
import Control.Monad
import Data.Default (Default (def))
import Data.Text qualified as Text
import System.Environment
import Clang.Enum.Bitfield
import Clang.Enum.Simple
import Clang.LowLevel.Core
import Clang.Paths
{-------------------------------------------------------------------------------
Reproduce the clang tutorial in Haskell
-------------------------------------------------------------------------------}
tutorial :: FilePath -> IO ()
tutorial fp = do
--
-- Obtain a cursor at the root of the translation unit
--
index <- clang_createIndex DontDisplayDiagnostics
unit <- clang_parseTranslationUnit
index
(Just $ SourcePath (Text.pack fp))
def
[]
(bitfieldEnum [CXTranslationUnit_None])
cursor <- clang_getTranslationUnitCursor unit
--
-- Visiting elements of an AST
--
_terminatedPrematurely <- clang_visitChildren
cursor -- Root cursor
(\current_cursor _parent -> do
current_display_name <- clang_getCursorDisplayName current_cursor
putStrLn $ "Visiting element " ++ show current_display_name
--
-- Extracting information from a Cursor
--
-- Extracting the Cursor kind
cursor_type <- clang_getCursorType current_cursor
type_kind_spelling <- clang_getTypeKindSpelling (cxtKind cursor_type)
putStrLn $ concat [
" "
, "Type Kind: " ++ show type_kind_spelling
, " (" ++ show (fromSimpleEnum $ cxtKind cursor_type) ++ ")"
]
when (isPointerType $ cxtKind cursor_type) $ do
pointed_to_type <- clang_getPointeeType(cursor_type)
pointed_to_type_spelling <- clang_getTypeSpelling pointed_to_type
putStrLn $ " pointing to type: " ++ show pointed_to_type_spelling
when (isRecordType $ cxtKind cursor_type) $ do
type_spelling <- clang_getTypeSpelling cursor_type
putStrLn $ " namely " ++ show type_spelling
--
-- Retrieving source locations
--
cursor_spelling <- clang_getCursorSpelling current_cursor
cursor_range <- clang_getCursorExtent current_cursor
range_start <- clang_getRangeStart cursor_range
range_end <- clang_getRangeEnd cursor_range
(_, start_line, start_column, _) <-
clang_getExpansionLocation range_start
(_, end_line, end_column, _) <-
clang_getExpansionLocation range_end
putStrLn $ concat [
" Cursor " ++ show cursor_spelling
, " spanning lines "
, show start_line ++ ":" ++ show start_column
, " to "
, show end_line ++ ":" ++ show end_column
]
return $ simpleEnum CXChildVisit_Recurse
)
return ()
{-------------------------------------------------------------------------------
Classifying types
-------------------------------------------------------------------------------}
-- | Check if this is a pointer type
--
-- Pointer types are types for which we can call 'clang_getPointeeType'.
isPointerType :: SimpleEnum CXTypeKind -> Bool
isPointerType = either (const False) aux . fromSimpleEnum
where
aux :: CXTypeKind -> Bool
aux CXType_Pointer = True
aux CXType_LValueReference = True
aux CXType_RValueReference = True
aux _ = False
isRecordType :: SimpleEnum CXTypeKind -> Bool
isRecordType = (== Right CXType_Record) . fromSimpleEnum
{-------------------------------------------------------------------------------
Main application
-------------------------------------------------------------------------------}
main :: IO ()
main = do
args <- getArgs
case args of
fp : _ -> tutorial fp
_ -> return ()