    {-# LINE 1 "CMarkGFM.hsc" #-}
    {-# LANGUAGE CPP, ForeignFunctionInterface, GeneralizedNewtypeDeriving,
        DeriveGeneric, DeriveDataTypeable, FlexibleContexts #-}

    module CMarkGFM (
        commonmarkToHtml
      , commonmarkToXml
      , commonmarkToMan
      , commonmarkToLaTeX
      , commonmarkToNode
      , nodeToHtml
      , nodeToXml
      , nodeToMan
      , nodeToLaTeX
      , nodeToCommonmark
      , optSourcePos
      , optHardBreaks
      , optSmart
      , optSafe
      , optUnsafe
      , extStrikethrough
      , extTable
      , extAutolink
      , extTagfilter
      , extTaskList
      , Node(..)
      , NodeType(..)
      , PosInfo(..)
      , DelimType(..)
      , ListType(..)
      , ListAttributes(..)
      , Url
      , Title
      , Level
      , Info
      , TableCellAlignment(..)
      , CMarkOption
      , CMarkExtension
      ) where

    import Foreign
    import Foreign.C.Types
    import Foreign.C.String (CString, withCString)
    import qualified System.IO.Unsafe as Unsafe
    import Data.Maybe (fromMaybe)
    import GHC.Generics (Generic)
    import Data.Data (Data)
    import Data.Typeable (Typeable)
    import Data.Text (Text, empty, snoc)
    import qualified Data.Text.Foreign as TF
    import Data.ByteString.Unsafe (unsafePackMallocCString)
    import Data.Text.Encoding (decodeUtf8)
    import Control.Applicative ((<$>), (<*>))

    -- | Ensure core extensions are registered.
    ensurePluginsRegistered :: IO ()
    ensurePluginsRegistered = c_cmark_gfm_core_extensions_ensure_registered

    -- | Frees a cmark linked list, produced by extsToLlist.
    freeLlist :: LlistPtr a -> IO ()
    freeLlist = c_cmark_llist_free c_cmark_mem

    -- | Converts a list of resolved extension pointers to a single cmark
    -- linked list, which can be passed to functions requiring a list of
    -- extensions.
    extsToLlist :: [ExtensionPtr] -> IO (LlistPtr ExtensionPtr)
    extsToLlist [] = return nullPtr
    extsToLlist (h:t) = do
      t' <- extsToLlist t
      c_cmark_llist_append c_cmark_mem t' (castPtr h)

    -- | Resolves CMarkExtensions to pointers.
    resolveExts :: [CMarkExtension] -> IO [ExtensionPtr]
    resolveExts exts = do
      ensurePluginsRegistered
      mapM resolveExt exts
      where resolveExt ext = do p <- withCString (unCMarkExtension ext) c_cmark_find_syntax_extension
                                if p == nullPtr then
                                  fail $ "could not load extension " ++ unCMarkExtension ext
                                else
                                  return p

    -- | Convert CommonMark formatted text to Html, using cmark's
    -- built-in renderer.
    commonmarkToHtml :: [CMarkOption] -> [CMarkExtension] -> Text -> Text
    commonmarkToHtml opts exts =
      commonmarkToX render_html opts exts Nothing
      where exts' = Unsafe.unsafePerformIO $ resolveExts exts
            render_html n o _ = do
              llist <- extsToLlist exts'
              r <- c_cmark_render_html n o llist
              freeLlist llist
              return r

    -- | Convert CommonMark formatted text to CommonMark XML, using cmark's
    -- built-in renderer.
    commonmarkToXml :: [CMarkOption] -> [CMarkExtension] -> Text -> Text
    commonmarkToXml opts exts = commonmarkToX render_xml opts exts Nothing
      where render_xml n o _ = c_cmark_render_xml n o

    -- | Convert CommonMark formatted text to groff man, using cmark's
    -- built-in renderer.
    commonmarkToMan :: [CMarkOption] -> [CMarkExtension] -> Maybe Int -> Text -> Text
    commonmarkToMan = commonmarkToX c_cmark_render_man

    -- | Convert CommonMark formatted text to latex, using cmark's
    -- built-in renderer.
    commonmarkToLaTeX :: [CMarkOption] -> [CMarkExtension] -> Maybe Int -> Text -> Text
    commonmarkToLaTeX = commonmarkToX c_cmark_render_latex

    -- | Convert CommonMark formatted text to a structured 'Node' tree,
    -- which can be transformed or rendered using Haskell code.
    commonmarkToNode :: [CMarkOption] -> [CMarkExtension] -> Text -> Node
    commonmarkToNode opts exts s = Unsafe.unsafePerformIO $ do
      exts' <- resolveExts exts
      parser <- c_cmark_parser_new (combineOptions opts)
      mapM_ (c_cmark_parser_attach_syntax_extension parser) exts'
      TF.withCStringLen s $! \(ptr, len) ->
                 c_cmark_parser_feed parser ptr len
      nptr <- c_cmark_parser_finish parser
      c_cmark_parser_free parser
      fptr <- newForeignPtr c_cmark_node_free nptr
      withForeignPtr fptr toNode

    nodeToHtml :: [CMarkOption] -> [CMarkExtension] -> Node -> Text
    nodeToHtml opts exts =
      nodeToX render_html opts Nothing
      where exts' = Unsafe.unsafePerformIO $ resolveExts exts
            render_html n o _ = do
              llist <- extsToLlist exts'
              r <- c_cmark_render_html n o llist
              freeLlist llist
              return r

    nodeToXml :: [CMarkOption] -> Node -> Text
    nodeToXml opts = nodeToX render_xml opts Nothing
      where render_xml n o _ = c_cmark_render_xml n o

    nodeToMan :: [CMarkOption] -> Maybe Int -> Node -> Text
    nodeToMan = nodeToX c_cmark_render_man

    nodeToLaTeX :: [CMarkOption] -> Maybe Int -> Node -> Text
    nodeToLaTeX = nodeToX c_cmark_render_latex

    nodeToCommonmark :: [CMarkOption] -> Maybe Int -> Node -> Text
    nodeToCommonmark = nodeToX c_cmark_render_commonmark

    type Renderer = NodePtr -> CInt -> Int -> IO CString

    nodeToX :: Renderer -> [CMarkOption] -> Maybe Int -> Node -> Text
    nodeToX renderer opts mbWidth node = Unsafe.unsafePerformIO $ do
      nptr <- fromNode node
      fptr <- newForeignPtr c_cmark_node_free nptr
      withForeignPtr fptr $ \ptr -> do
        cstr <- renderer ptr (combineOptions opts) (fromMaybe 0 mbWidth)
        decodeUtf8 <$> unsafePackMallocCString cstr

    commonmarkToX :: Renderer
                  -> [CMarkOption]
                  -> [CMarkExtension]
                  -> Maybe Int
                  -> Text
                  -> Text
    commonmarkToX renderer opts exts mbWidth s = Unsafe.unsafePerformIO $
      TF.withCStringLen s $ \(ptr, len) -> do
        let opts' = combineOptions opts
        exts' <- resolveExts exts
        parser <- c_cmark_parser_new opts'
        mapM_ (c_cmark_parser_attach_syntax_extension parser) exts'
        c_cmark_parser_feed parser ptr len
        nptr <- c_cmark_parser_finish parser
        c_cmark_parser_free parser
        fptr <- newForeignPtr c_cmark_node_free nptr
        withForeignPtr fptr $ \p -> do
          str <- renderer p opts' (fromMaybe 0 mbWidth)
          decodeUtf8 <$> unsafePackMallocCString str

    data ParserPhantom
    type ParserPtr = Ptr ParserPhantom

    data NodePhantom
    type NodePtr = Ptr NodePhantom

    data LlistPhantom a
    type LlistPtr a = Ptr (LlistPhantom a)

    data MemPhantom
    type MemPtr = Ptr MemPhantom

    data ExtensionPhantom
    type ExtensionPtr = Ptr ExtensionPhantom

    data Node = Node (Maybe PosInfo) NodeType [Node]
         deriving (Show, Read, Eq, Ord, Typeable, Data, Generic)

    data DelimType =
        PERIOD_DELIM
      | PAREN_DELIM
      deriving (Show, Read, Eq, Ord, Typeable, Data, Generic)

    data ListType =
        BULLET_LIST
      | ORDERED_LIST
      deriving (Show, Read, Eq, Ord, Typeable, Data, Generic)

    data ListAttributes = ListAttributes{
        listType     :: ListType
      , listTight    :: Bool
      , listStart    :: Int
      , listDelim    :: DelimType
      } deriving (Show, Read, Eq, Ord, Typeable, Data, Generic)

    type Url = Text

    type Title = Text

    type Level = Int

    type Info = Text

    type OnEnter = Text

    type OnExit = Text

    data TableCellAlignment = NoAlignment | LeftAligned | CenterAligned | RightAligned
         deriving (Show, Read, Eq, Ord, Typeable, Data, Generic)

    data NodeType =
        DOCUMENT
      | THEMATIC_BREAK
      | PARAGRAPH
      | BLOCK_QUOTE
      | HTML_BLOCK Text
      | CUSTOM_BLOCK OnEnter OnExit
      | CODE_BLOCK Info Text
      | HEADING Level
      | LIST ListAttributes
      | ITEM
      | TEXT Text
      | SOFTBREAK
      | LINEBREAK
      | HTML_INLINE Text
      | CUSTOM_INLINE OnEnter OnExit
      | CODE Text
      | EMPH
      | STRONG
      | LINK Url Title
      | IMAGE Url Title
      | STRIKETHROUGH
      | TABLE [TableCellAlignment]
      | TABLE_ROW
      | TABLE_CELL
      deriving (Show, Read, Eq, Ord, Typeable, Data, Generic)

    data PosInfo = PosInfo{ startLine   :: Int
                          , startColumn :: Int
                          , endLine     :: Int
                          , endColumn   :: Int
                          }
      deriving (Show, Read, Eq, Ord, Typeable, Data, Generic)

    newtype CMarkOption = CMarkOption { unCMarkOption :: CInt }

    -- | Combine a list of options into a single option, using bitwise or.
    combineOptions :: [CMarkOption] -> CInt
    combineOptions = foldr ((.|.) . unCMarkOption) 0

    -- | Include a @data-sourcepos@ attribute on block elements.
    optSourcePos :: CMarkOption
    optSourcePos = CMarkOption 2
    {-# LINE 273 "CMarkGFM.hsc" #-}

    -- | Render @softbreak@ elements as hard line breaks.
    optHardBreaks :: CMarkOption
    optHardBreaks = CMarkOption 4
    {-# LINE 277 "CMarkGFM.hsc" #-}

    -- | Convert straight quotes to curly, @---@ to em-dash, @--@ to en-dash.
    optSmart :: CMarkOption
    optSmart = CMarkOption 1024
    {-# LINE 281 "CMarkGFM.hsc" #-}

    -- | optSafe is defined here for API compatibility, but it no longer has any
    -- effect. "Safe" mode is now the default: set optUnsafe to disable it.
    optSafe :: CMarkOption
    optSafe = CMarkOption 8
    {-# LINE 286 "CMarkGFM.hsc" #-}

    -- | Allow rendering of raw HTML and potentially dangerous URLs in links
    -- and images.
    optUnsafe :: CMarkOption
    optUnsafe = CMarkOption 131072
    {-# LINE 291 "CMarkGFM.hsc" #-}

    newtype CMarkExtension = CMarkExtension { unCMarkExtension :: String }

    extStrikethrough :: CMarkExtension
    extStrikethrough = CMarkExtension "strikethrough"

    extTable :: CMarkExtension
    extTable = CMarkExtension "table"

    extAutolink :: CMarkExtension
    extAutolink = CMarkExtension "autolink"

    extTagfilter :: CMarkExtension
    extTagfilter = CMarkExtension "tagfilter"

    extTaskList :: CMarkExtension
    extTaskList = CMarkExtension "tasklist"

    ptrToNodeType :: NodePtr -> IO NodeType
    ptrToNodeType ptr = do
      nodeType <- c_cmark_node_get_type ptr
      case nodeType of
           32769
    {-# LINE 314 "CMarkGFM.hsc" #-}
             -> return DOCUMENT
           32778
    {-# LINE 316 "CMarkGFM.hsc" #-}
             -> return THEMATIC_BREAK
           32776
    {-# LINE 318 "CMarkGFM.hsc" #-}
             -> return PARAGRAPH
           32770
    {-# LINE 320 "CMarkGFM.hsc" #-}
             -> return BLOCK_QUOTE
           32774
    {-# LINE 322 "CMarkGFM.hsc" #-}
             -> HTML_BLOCK <$> literal
           32775
    {-# LINE 324 "CMarkGFM.hsc" #-}
             -> CUSTOM_BLOCK <$> onEnter <*> onExit
           32773
    {-# LINE 326 "CMarkGFM.hsc" #-}
             -> CODE_BLOCK <$> info
                           <*> literal
           32771
    {-# LINE 329 "CMarkGFM.hsc" #-}
             -> LIST <$> listAttr
           32772
    {-# LINE 331 "CMarkGFM.hsc" #-}
             -> return ITEM
           32777
    {-# LINE 333 "CMarkGFM.hsc" #-}
             -> HEADING <$> level
           49159
    {-# LINE 335 "CMarkGFM.hsc" #-}
             -> return EMPH
           49160
    {-# LINE 337 "CMarkGFM.hsc" #-}
             -> return STRONG
           49161
    {-# LINE 339 "CMarkGFM.hsc" #-}
             -> LINK <$> url <*> title
           49162
    {-# LINE 341 "CMarkGFM.hsc" #-}
             -> IMAGE <$> url <*> title
           49153
    {-# LINE 343 "CMarkGFM.hsc" #-}
             -> TEXT <$> literal
           49156
    {-# LINE 345 "CMarkGFM.hsc" #-}
             -> CODE <$> literal
           49157
    {-# LINE 347 "CMarkGFM.hsc" #-}
             -> HTML_INLINE <$> literal
           49158
    {-# LINE 349 "CMarkGFM.hsc" #-}
             -> CUSTOM_INLINE <$> onEnter <*> onExit
           49154
    {-# LINE 351 "CMarkGFM.hsc" #-}
             -> return SOFTBREAK
           49155
    {-# LINE 353 "CMarkGFM.hsc" #-}
             -> return LINEBREAK
           _ -> if nodeType == fromIntegral (Unsafe.unsafePerformIO $ peek c_CMARK_NODE_STRIKETHROUGH) then
                  return STRIKETHROUGH
                else if nodeType == fromIntegral (Unsafe.unsafePerformIO $ peek c_CMARK_NODE_TABLE) then
                  TABLE <$> alignments
                else if nodeType == fromIntegral (Unsafe.unsafePerformIO $ peek c_CMARK_NODE_TABLE_ROW) then
                  return TABLE_ROW
                else if nodeType == fromIntegral (Unsafe.unsafePerformIO $ peek c_CMARK_NODE_TABLE_CELL) then
                  return TABLE_CELL
                else
                  error $ "Unknown node type " ++ (show nodeType)
      where literal   = c_cmark_node_get_literal ptr >>= totext
            level     = c_cmark_node_get_heading_level ptr
            onEnter    = c_cmark_node_get_on_enter ptr >>= totext
            onExit     = c_cmark_node_get_on_exit  ptr >>= totext
            listAttr  = do
              listtype <- c_cmark_node_get_list_type ptr
              listdelim <- c_cmark_node_get_list_delim ptr
              tight <- c_cmark_node_get_list_tight ptr
              start <- c_cmark_node_get_list_start ptr
              return ListAttributes{
                listType  = case listtype of
                                 (2) -> ORDERED_LIST
    {-# LINE 376 "CMarkGFM.hsc" #-}
                                 (1)  -> BULLET_LIST
    {-# LINE 377 "CMarkGFM.hsc" #-}
                                 _                           -> BULLET_LIST
              , listDelim  = case listdelim of
                                 (1) -> PERIOD_DELIM
    {-# LINE 380 "CMarkGFM.hsc" #-}
                                 (2)  -> PAREN_DELIM
    {-# LINE 381 "CMarkGFM.hsc" #-}
                                 _                           -> PERIOD_DELIM
              , listTight  = tight
              , listStart  = start
              }
            url       = c_cmark_node_get_url ptr >>= totext
            title     = c_cmark_node_get_title ptr >>= totext
            info      = c_cmark_node_get_fence_info ptr >>= totext
            alignments = do
              ncols <- c_cmark_gfm_extensions_get_table_columns ptr
              cols <- c_cmark_gfm_extensions_get_table_alignments ptr
              mapM (fmap ucharToAlignment . peekElemOff cols) [0..(fromIntegral ncols) - 1]
            ucharToAlignment (CUChar 108) = LeftAligned
            ucharToAlignment (CUChar 99)  = CenterAligned
            ucharToAlignment (CUChar 114) = RightAligned
            ucharToAlignment _            = NoAlignment

    getPosInfo :: NodePtr -> IO (Maybe PosInfo)
    getPosInfo ptr = do
      startline <- c_cmark_node_get_start_line ptr
      endline <- c_cmark_node_get_end_line ptr
      startcol <- c_cmark_node_get_start_column ptr
      endcol <- c_cmark_node_get_end_column ptr
      if startline + endline + startcol + endcol == 0
         then return Nothing
         else return $ Just PosInfo{ startLine = startline
                                   , startColumn = startcol
                                   , endLine = endline
                                   , endColumn = endcol }

    toNode :: NodePtr -> IO Node
    toNode ptr = do
      let handleNodes ptr' =
            if ptr' == nullPtr
               then return []
               else do
                  x  <- toNode ptr'
                  xs <- c_cmark_node_next ptr' >>= handleNodes
                  return $! (x:xs)
      nodeType <- ptrToNodeType ptr
      children <- c_cmark_node_first_child ptr >>= handleNodes
      posinfo <- getPosInfo ptr
      return $! Node posinfo nodeType children

    fromNode :: Node -> IO NodePtr
    fromNode (Node _ nodeType children) = do
      node <- case nodeType of
                DOCUMENT    -> c_cmark_node_new (32769)
    {-# LINE 428 "CMarkGFM.hsc" #-}
                THEMATIC_BREAK -> c_cmark_node_new (32778)
    {-# LINE 429 "CMarkGFM.hsc" #-}
                PARAGRAPH   -> c_cmark_node_new (32776)
    {-# LINE 430 "CMarkGFM.hsc" #-}
                BLOCK_QUOTE -> c_cmark_node_new (32770)
    {-# LINE 431 "CMarkGFM.hsc" #-}
                HTML_BLOCK literal -> do
                         n <- c_cmark_node_new (32774)
    {-# LINE 433 "CMarkGFM.hsc" #-}
                         withtext literal (c_cmark_node_set_literal n)
                         return n
                CUSTOM_BLOCK onEnter onExit -> do
                         n <- c_cmark_node_new (32775)
    {-# LINE 437 "CMarkGFM.hsc" #-}
                         withtext onEnter (c_cmark_node_set_on_enter n)
                         withtext onExit  (c_cmark_node_set_on_exit  n)
                         return n
                CODE_BLOCK info literal -> do
                         n <- c_cmark_node_new (32773)
    {-# LINE 442 "CMarkGFM.hsc" #-}
                         withtext literal (c_cmark_node_set_literal n)
                         withtext info (c_cmark_node_set_fence_info n)
                         return n
                LIST attr   -> do
                         n <- c_cmark_node_new (32771)
    {-# LINE 447 "CMarkGFM.hsc" #-}
                         c_cmark_node_set_list_type n $ case listType attr of
                             ORDERED_LIST -> 2
    {-# LINE 449 "CMarkGFM.hsc" #-}
                             BULLET_LIST  -> 1
    {-# LINE 450 "CMarkGFM.hsc" #-}
                         c_cmark_node_set_list_delim n $ case listDelim attr of
                             PERIOD_DELIM -> 1
    {-# LINE 452 "CMarkGFM.hsc" #-}
                             PAREN_DELIM  -> 2
    {-# LINE 453 "CMarkGFM.hsc" #-}
                         c_cmark_node_set_list_tight n $ listTight attr
                         c_cmark_node_set_list_start n $ listStart attr
                         return n
                ITEM        -> c_cmark_node_new (32772)
    {-# LINE 457 "CMarkGFM.hsc" #-}
                HEADING lev  -> do
                         n <- c_cmark_node_new (32777)
    {-# LINE 459 "CMarkGFM.hsc" #-}
                         c_cmark_node_set_heading_level n lev
                         return n
                EMPH        -> c_cmark_node_new (49159)
    {-# LINE 462 "CMarkGFM.hsc" #-}
                STRONG      -> c_cmark_node_new (49160)
    {-# LINE 463 "CMarkGFM.hsc" #-}
                LINK url title -> do
                         n <- c_cmark_node_new (49161)
    {-# LINE 465 "CMarkGFM.hsc" #-}
                         withtext url (c_cmark_node_set_url n)
                         withtext title (c_cmark_node_set_title n)
                         return n
                IMAGE url title -> do
                         n <- c_cmark_node_new (49162)
    {-# LINE 470 "CMarkGFM.hsc" #-}
                         withtext url (c_cmark_node_set_url n)
                         withtext title (c_cmark_node_set_title n)
                         return n
                TEXT literal -> do
                         n <- c_cmark_node_new (49153)
    {-# LINE 475 "CMarkGFM.hsc" #-}
                         withtext literal (c_cmark_node_set_literal n)
                         return n
                CODE literal -> do
                         n <- c_cmark_node_new (49156)
    {-# LINE 479 "CMarkGFM.hsc" #-}
                         withtext literal (c_cmark_node_set_literal n)
                         return n
                HTML_INLINE literal -> do
                         n <- c_cmark_node_new (49157)
    {-# LINE 483 "CMarkGFM.hsc" #-}
                         withtext literal (c_cmark_node_set_literal n)
                         return n
                CUSTOM_INLINE onEnter onExit -> do
                         n <- c_cmark_node_new (49158)
    {-# LINE 487 "CMarkGFM.hsc" #-}
                         withtext onEnter (c_cmark_node_set_on_enter n)
                         withtext onExit  (c_cmark_node_set_on_exit  n)
                         return n
                SOFTBREAK   -> c_cmark_node_new (49154)
    {-# LINE 491 "CMarkGFM.hsc" #-}
                LINEBREAK   -> c_cmark_node_new (49155)
    {-# LINE 492 "CMarkGFM.hsc" #-}
                STRIKETHROUGH -> c_cmark_node_new (fromIntegral . Unsafe.unsafePerformIO $ peek c_CMARK_NODE_STRIKETHROUGH)
                TABLE _       -> error "constructing table not supported"
                TABLE_ROW     -> error "constructing table row not supported"
                TABLE_CELL    -> error "constructing table cell not supported"
      mapM_ (\child -> fromNode child >>= c_cmark_node_append_child node) children
      return node

    totext :: CString -> IO Text
    totext str
      | str == nullPtr = return empty
      | otherwise      = TF.peekCStringLen (str, c_strlen str)

    withtext :: Text -> (CString -> IO a) -> IO a
    withtext t f = TF.withCStringLen (snoc t '\0') (f . fst)

    foreign import ccall "string.h strlen"
        c_strlen :: CString -> Int

    foreign import ccall "cmark-gfm.h cmark_node_new"
        c_cmark_node_new :: Int -> IO NodePtr

    foreign import ccall "cmark-gfm.h cmark_render_html"
        c_cmark_render_html :: NodePtr -> CInt -> LlistPtr ExtensionPtr -> IO CString

    foreign import ccall "cmark-gfm.h cmark_render_xml"
        c_cmark_render_xml :: NodePtr -> CInt -> IO CString

    foreign import ccall "cmark-gfm.h cmark_render_man"
        c_cmark_render_man :: NodePtr -> CInt -> Int -> IO CString

    foreign import ccall "cmark-gfm.h cmark_render_latex"
        c_cmark_render_latex :: NodePtr -> CInt -> Int -> IO CString

    foreign import ccall "cmark-gfm.h cmark_render_commonmark"
        c_cmark_render_commonmark :: NodePtr -> CInt -> Int -> IO CString

    foreign import ccall "cmark-gfm.h cmark_parser_new"
        c_cmark_parser_new :: CInt -> IO ParserPtr

    foreign import ccall "cmark-gfm.h cmark_parser_feed"
        c_cmark_parser_feed :: ParserPtr -> CString -> Int -> IO ()

    foreign import ccall "cmark-gfm.h cmark_parser_finish"
        c_cmark_parser_finish :: ParserPtr -> IO NodePtr

    foreign import ccall "cmark-gfm.h cmark_parser_free"
        c_cmark_parser_free :: ParserPtr -> IO ()

    foreign import ccall "cmark-gfm.h cmark_node_get_type"
        c_cmark_node_get_type :: NodePtr -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_first_child"
        c_cmark_node_first_child :: NodePtr -> IO NodePtr

    foreign import ccall "cmark-gfm.h cmark_node_next"
        c_cmark_node_next :: NodePtr -> IO NodePtr

    foreign import ccall "cmark-gfm.h cmark_node_get_literal"
        c_cmark_node_get_literal :: NodePtr -> IO CString

    foreign import ccall "cmark-gfm.h cmark_node_get_url"
        c_cmark_node_get_url :: NodePtr -> IO CString

    foreign import ccall "cmark-gfm.h cmark_node_get_title"
        c_cmark_node_get_title :: NodePtr -> IO CString

    foreign import ccall "cmark-gfm.h cmark_node_get_heading_level"
        c_cmark_node_get_heading_level :: NodePtr -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_get_list_type"
        c_cmark_node_get_list_type :: NodePtr -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_get_list_tight"
        c_cmark_node_get_list_tight :: NodePtr -> IO Bool

    foreign import ccall "cmark-gfm.h cmark_node_get_list_start"
        c_cmark_node_get_list_start :: NodePtr -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_get_list_delim"
        c_cmark_node_get_list_delim :: NodePtr -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_get_fence_info"
        c_cmark_node_get_fence_info :: NodePtr -> IO CString

    foreign import ccall "cmark-gfm.h cmark_node_get_start_line"
        c_cmark_node_get_start_line :: NodePtr -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_get_start_column"
        c_cmark_node_get_start_column :: NodePtr -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_get_end_line"
        c_cmark_node_get_end_line :: NodePtr -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_get_end_column"
        c_cmark_node_get_end_column :: NodePtr -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_get_on_enter"
        c_cmark_node_get_on_enter :: NodePtr -> IO CString

    foreign import ccall "cmark-gfm.h cmark_node_get_on_exit"
        c_cmark_node_get_on_exit :: NodePtr -> IO CString

    foreign import ccall "cmark-gfm.h cmark_node_append_child"
        c_cmark_node_append_child :: NodePtr -> NodePtr -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_set_literal"
        c_cmark_node_set_literal :: NodePtr -> CString -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_set_url"
        c_cmark_node_set_url :: NodePtr -> CString -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_set_title"
        c_cmark_node_set_title :: NodePtr -> CString -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_set_heading_level"
        c_cmark_node_set_heading_level :: NodePtr -> Int -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_set_list_type"
        c_cmark_node_set_list_type :: NodePtr -> Int -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_set_list_tight"
        c_cmark_node_set_list_tight :: NodePtr -> Bool -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_set_list_start"
        c_cmark_node_set_list_start :: NodePtr -> Int -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_set_list_delim"
        c_cmark_node_set_list_delim :: NodePtr -> Int -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_set_fence_info"
        c_cmark_node_set_fence_info :: NodePtr -> CString -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_set_on_enter"
        c_cmark_node_set_on_enter :: NodePtr -> CString -> IO Int

    foreign import ccall "cmark-gfm.h cmark_node_set_on_exit"
        c_cmark_node_set_on_exit :: NodePtr -> CString -> IO Int

    foreign import ccall "cmark-gfm.h &cmark_node_free"
        c_cmark_node_free :: FunPtr (NodePtr -> IO ())

    foreign import ccall "cmark-gfm-core-extensions.h cmark_gfm_core_extensions_ensure_registered"
        c_cmark_gfm_core_extensions_ensure_registered :: IO ()

    foreign import ccall "cmark-gfm-extension_api.h cmark_find_syntax_extension"
        c_cmark_find_syntax_extension :: CString -> IO ExtensionPtr

    foreign import ccall "cmark-gfm.h cmark_llist_append"
        c_cmark_llist_append :: MemPtr -> LlistPtr a -> Ptr () -> IO (LlistPtr a)

    foreign import ccall "cmark-gfm.h cmark_llist_free"
        c_cmark_llist_free :: MemPtr -> LlistPtr a -> IO ()

    foreign import ccall "cmark-gfm.h cmark_get_default_mem_allocator"
        c_cmark_mem :: MemPtr

    foreign import ccall "cmark-gfm-extension_api.h cmark_parser_attach_syntax_extension"
        c_cmark_parser_attach_syntax_extension :: ParserPtr -> ExtensionPtr -> IO ()

    foreign import ccall "strikethrough.h &CMARK_NODE_STRIKETHROUGH"
        c_CMARK_NODE_STRIKETHROUGH :: Ptr Word32
    {-# LINE 653 "CMarkGFM.hsc" #-}

    foreign import ccall "table.h &CMARK_NODE_TABLE"
        c_CMARK_NODE_TABLE :: Ptr Word32
    {-# LINE 656 "CMarkGFM.hsc" #-}

    foreign import ccall "table.h &CMARK_NODE_TABLE_ROW"
        c_CMARK_NODE_TABLE_ROW :: Ptr Word32
    {-# LINE 659 "CMarkGFM.hsc" #-}

    foreign import ccall "table.h &CMARK_NODE_TABLE_CELL"
        c_CMARK_NODE_TABLE_CELL :: Ptr Word32
    {-# LINE 662 "CMarkGFM.hsc" #-}

    foreign import ccall "cmark-gfm-core-extensions.h cmark_gfm_extensions_get_table_columns"
        c_cmark_gfm_extensions_get_table_columns :: NodePtr -> IO CUShort

    foreign import ccall "cmark-gfm-core-extensions.h cmark_gfm_extensions_get_table_alignments"
        c_cmark_gfm_extensions_get_table_alignments :: NodePtr -> IO (Ptr CUChar)