{-# LANGUAGE RecordWildCards, PatternGuards #-}
-- | Parsing type information from GIR files.
module Data.GI.GIR.Type
    ( parseType
    , queryCType
    , parseCType
    , queryElementCType
    , parseOptionalType
    ) where

import Data.Maybe (catMaybes)
#if !MIN_VERSION_base(4,11,0)
import Data.Monoid ((<>))
#endif
import Data.Text (Text)
import qualified Data.Text as T
import Foreign.Storable (sizeOf)
import Foreign.C (CShort, CUShort, CSize)
import System.Posix.Types (CSsize)

import Data.GI.GIR.BasicTypes (Type(..), BasicType(..))
import Data.GI.GIR.Parser

-- | Map the given type name to a `BasicType` (defined in
-- Data.GI.GIR.BasicTypes), if possible.
nameToBasicType :: Text -> Maybe BasicType
nameToBasicType :: ParseError -> Maybe BasicType
nameToBasicType ParseError
"gpointer" = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TPtr
nameToBasicType ParseError
"gboolean" = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TBoolean
nameToBasicType ParseError
"gchar"    = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TInt8
nameToBasicType ParseError
"gint"     = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TInt
nameToBasicType ParseError
"guint"    = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TUInt
nameToBasicType ParseError
"glong"    = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TLong
nameToBasicType ParseError
"gulong"   = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TULong
nameToBasicType ParseError
"gint8"    = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TInt8
nameToBasicType ParseError
"guint8"   = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TUInt8
nameToBasicType ParseError
"gint16"   = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TInt16
nameToBasicType ParseError
"guint16"  = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TUInt16
nameToBasicType ParseError
"gint32"   = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TInt32
nameToBasicType ParseError
"guint32"  = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TUInt32
nameToBasicType ParseError
"gint64"   = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TInt64
nameToBasicType ParseError
"guint64"  = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TUInt64
nameToBasicType ParseError
"gfloat"   = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TFloat
nameToBasicType ParseError
"gdouble"  = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TDouble
nameToBasicType ParseError
"gunichar" = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TUniChar
nameToBasicType ParseError
"GType"    = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TGType
nameToBasicType ParseError
"utf8"     = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TUTF8
nameToBasicType ParseError
"filename" = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TFileName
nameToBasicType ParseError
"gintptr"  = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TIntPtr
nameToBasicType ParseError
"guintptr" = BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TUIntPtr
nameToBasicType ParseError
"gshort"   = case CShort -> Int
forall a. Storable a => a -> Int
sizeOf (CShort
0 :: CShort) of
                               Int
2 -> BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TInt16
                               Int
4 -> BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TInt32
                               Int
8 -> BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TInt64
                               Int
n -> [Char] -> Maybe BasicType
forall a. HasCallStack => [Char] -> a
error ([Char] -> Maybe BasicType) -> [Char] -> Maybe BasicType
forall a b. (a -> b) -> a -> b
$ [Char]
"Unexpected short size: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> [Char]
forall a. Show a => a -> [Char]
show Int
n
nameToBasicType ParseError
"gushort"  = case CUShort -> Int
forall a. Storable a => a -> Int
sizeOf (CUShort
0 :: CUShort) of
                               Int
2 -> BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TUInt16
                               Int
4 -> BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TUInt32
                               Int
8 -> BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TUInt64
                               Int
n -> [Char] -> Maybe BasicType
forall a. HasCallStack => [Char] -> a
error ([Char] -> Maybe BasicType) -> [Char] -> Maybe BasicType
forall a b. (a -> b) -> a -> b
$ [Char]
"Unexpected ushort size: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> [Char]
forall a. Show a => a -> [Char]
show Int
n
nameToBasicType ParseError
"gssize"   = case CSsize -> Int
forall a. Storable a => a -> Int
sizeOf (CSsize
0 :: CSsize) of
                               Int
4 -> BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TInt32
                               Int
8 -> BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TInt64
                               Int
n -> [Char] -> Maybe BasicType
forall a. HasCallStack => [Char] -> a
error ([Char] -> Maybe BasicType) -> [Char] -> Maybe BasicType
forall a b. (a -> b) -> a -> b
$ [Char]
"Unexpected ssize length: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> [Char]
forall a. Show a => a -> [Char]
show Int
n
nameToBasicType ParseError
"gsize"    = case CSize -> Int
forall a. Storable a => a -> Int
sizeOf (CSize
0 :: CSize) of
                               Int
4 -> BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TUInt32
                               Int
8 -> BasicType -> Maybe BasicType
forall a. a -> Maybe a
Just BasicType
TUInt64
                               Int
n -> [Char] -> Maybe BasicType
forall a. HasCallStack => [Char] -> a
error ([Char] -> Maybe BasicType) -> [Char] -> Maybe BasicType
forall a b. (a -> b) -> a -> b
$ [Char]
"Unexpected size length: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> [Char]
forall a. Show a => a -> [Char]
show Int
n
nameToBasicType ParseError
_          = Maybe BasicType
forall a. Maybe a
Nothing

-- | The different array types.
parseArrayInfo :: Parser Type
parseArrayInfo :: Parser Type
parseArrayInfo = Name -> Parser (Maybe ParseError)
queryAttr Name
"name" Parser (Maybe ParseError)
-> (Maybe ParseError -> Parser Type) -> Parser Type
forall a b.
ReaderT ParseContext (Except ParseError) a
-> (a -> ReaderT ParseContext (Except ParseError) b)
-> ReaderT ParseContext (Except ParseError) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
      Just ParseError
"GLib.Array" -> Type -> Type
TGArray (Type -> Type) -> Parser Type -> Parser Type
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Type
parseType
      Just ParseError
"GLib.PtrArray" -> Type -> Type
TPtrArray (Type -> Type) -> Parser Type -> Parser Type
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Type
parseType
      Just ParseError
"GLib.ByteArray" -> Type -> Parser Type
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return Type
TByteArray
      Just ParseError
other -> ParseError -> Parser Type
forall a. ParseError -> Parser a
parseError (ParseError -> Parser Type) -> ParseError -> Parser Type
forall a b. (a -> b) -> a -> b
$ ParseError
"Unsupported array type: \"" ParseError -> ParseError -> ParseError
forall a. Semigroup a => a -> a -> a
<> ParseError
other ParseError -> ParseError -> ParseError
forall a. Semigroup a => a -> a -> a
<> ParseError
"\""
      Maybe ParseError
Nothing -> Parser Type
parseCArrayType

-- | A C array
parseCArrayType :: Parser Type
parseCArrayType :: Parser Type
parseCArrayType = do
  Bool
zeroTerminated <- Name -> Parser (Maybe ParseError)
queryAttr Name
"zero-terminated" Parser (Maybe ParseError)
-> (Maybe ParseError
    -> ReaderT ParseContext (Except ParseError) Bool)
-> ReaderT ParseContext (Except ParseError) Bool
forall a b.
ReaderT ParseContext (Except ParseError) a
-> (a -> ReaderT ParseContext (Except ParseError) b)
-> ReaderT ParseContext (Except ParseError) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
                    Just ParseError
b -> ParseError -> ReaderT ParseContext (Except ParseError) Bool
parseBool ParseError
b
                    Maybe ParseError
Nothing -> Bool -> ReaderT ParseContext (Except ParseError) Bool
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
  Int
length <- Name -> Parser (Maybe ParseError)
queryAttr Name
"length" Parser (Maybe ParseError)
-> (Maybe ParseError
    -> ReaderT ParseContext (Except ParseError) Int)
-> ReaderT ParseContext (Except ParseError) Int
forall a b.
ReaderT ParseContext (Except ParseError) a
-> (a -> ReaderT ParseContext (Except ParseError) b)
-> ReaderT ParseContext (Except ParseError) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
            Just ParseError
l -> ParseError -> ReaderT ParseContext (Except ParseError) Int
forall a. Integral a => ParseError -> Parser a
parseIntegral ParseError
l
            Maybe ParseError
Nothing -> Int -> ReaderT ParseContext (Except ParseError) Int
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return (-Int
1)
  Int
fixedSize <- Name -> Parser (Maybe ParseError)
queryAttr Name
"fixed-size" Parser (Maybe ParseError)
-> (Maybe ParseError
    -> ReaderT ParseContext (Except ParseError) Int)
-> ReaderT ParseContext (Except ParseError) Int
forall a b.
ReaderT ParseContext (Except ParseError) a
-> (a -> ReaderT ParseContext (Except ParseError) b)
-> ReaderT ParseContext (Except ParseError) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
               Just ParseError
s -> ParseError -> ReaderT ParseContext (Except ParseError) Int
forall a. Integral a => ParseError -> Parser a
parseIntegral ParseError
s
               Maybe ParseError
Nothing -> Int -> ReaderT ParseContext (Except ParseError) Int
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return (-Int
1)
  Type
elementType <- Parser Type
parseType
  Type -> Parser Type
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return (Type -> Parser Type) -> Type -> Parser Type
forall a b. (a -> b) -> a -> b
$ Bool -> Int -> Int -> Type -> Type
TCArray Bool
zeroTerminated Int
fixedSize Int
length Type
elementType

-- | A hash table.
parseHashTable :: Parser Type
parseHashTable :: Parser Type
parseHashTable = Parser [Maybe Type]
parseTypeElements Parser [Maybe Type] -> ([Maybe Type] -> Parser Type) -> Parser Type
forall a b.
ReaderT ParseContext (Except ParseError) a
-> (a -> ReaderT ParseContext (Except ParseError) b)
-> ReaderT ParseContext (Except ParseError) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
                 [] -> Type -> Parser Type
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return (Type -> Parser Type) -> Type -> Parser Type
forall a b. (a -> b) -> a -> b
$ Type -> Type -> Type
TGHash (BasicType -> Type
TBasicType BasicType
TPtr) (BasicType -> Type
TBasicType BasicType
TPtr)
                 [Just Type
key, Just Type
value] -> Type -> Parser Type
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return (Type -> Parser Type) -> Type -> Parser Type
forall a b. (a -> b) -> a -> b
$ Type -> Type -> Type
TGHash Type
key Type
value
                 [Maybe Type]
other -> ParseError -> Parser Type
forall a. ParseError -> Parser a
parseError (ParseError -> Parser Type) -> ParseError -> Parser Type
forall a b. (a -> b) -> a -> b
$ ParseError
"Unsupported hash type: "
                                       ParseError -> ParseError -> ParseError
forall a. Semigroup a => a -> a -> a
<> [Char] -> ParseError
T.pack ([Maybe Type] -> [Char]
forall a. Show a => a -> [Char]
show [Maybe Type]
other)

-- | Parse a `GClosure` declaration.
parseClosure :: Parser Type
parseClosure :: Parser Type
parseClosure = Name -> Parser (Maybe ParseError)
queryAttr Name
"closure-type" Parser (Maybe ParseError)
-> (Maybe ParseError -> Parser Type) -> Parser Type
forall a b.
ReaderT ParseContext (Except ParseError) a
-> (a -> ReaderT ParseContext (Except ParseError) b)
-> ReaderT ParseContext (Except ParseError) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
                Just ParseError
t -> (Maybe Type -> Type
TGClosure (Maybe Type -> Type) -> (Type -> Maybe Type) -> Type -> Type
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Type -> Maybe Type
forall a. a -> Maybe a
Just) (Type -> Type) -> Parser Type -> Parser Type
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParseError -> Parser Type
parseTypeName ParseError
t
                Maybe ParseError
Nothing -> Type -> Parser Type
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return (Type -> Parser Type) -> Type -> Parser Type
forall a b. (a -> b) -> a -> b
$ Maybe Type -> Type
TGClosure Maybe Type
forall a. Maybe a
Nothing

-- | For GLists and GSLists there is sometimes no information about
-- the type of the elements. In these cases we report them as
-- pointers.
parseListType :: Parser Type
parseListType :: Parser Type
parseListType = Parser (Maybe Type)
queryType Parser (Maybe Type) -> (Maybe Type -> Parser Type) -> Parser Type
forall a b.
ReaderT ParseContext (Except ParseError) a
-> (a -> ReaderT ParseContext (Except ParseError) b)
-> ReaderT ParseContext (Except ParseError) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
                Just Type
t -> Type -> Parser Type
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return Type
t
                Maybe Type
Nothing -> Type -> Parser Type
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return (BasicType -> Type
TBasicType BasicType
TPtr)

-- | A type which is not a BasicType or array.
parseFundamentalType :: Text -> Text -> Parser Type
parseFundamentalType :: ParseError -> ParseError -> Parser Type
parseFundamentalType ParseError
"GLib" ParseError
"List" = Type -> Type
TGList (Type -> Type) -> Parser Type -> Parser Type
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Type
parseListType
parseFundamentalType ParseError
"GLib" ParseError
"SList" = Type -> Type
TGSList (Type -> Type) -> Parser Type -> Parser Type
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Type
parseListType
parseFundamentalType ParseError
"GLib" ParseError
"HashTable" = Parser Type
parseHashTable
parseFundamentalType ParseError
"GLib" ParseError
"Error" = Type -> Parser Type
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return Type
TError
parseFundamentalType ParseError
"GLib" ParseError
"Variant" = Type -> Parser Type
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return Type
TVariant
parseFundamentalType ParseError
"GObject" ParseError
"ParamSpec" = Type -> Parser Type
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return Type
TParamSpec
parseFundamentalType ParseError
"GObject" ParseError
"Value" = Type -> Parser Type
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return Type
TGValue
parseFundamentalType ParseError
"GObject" ParseError
"Closure" = Parser Type
parseClosure
-- A TInterface type (basically, everything that is not of a known type).
parseFundamentalType ParseError
ns ParseError
n = Name -> Parser Type
resolveQualifiedTypeName (ParseError -> ParseError -> Name
Name ParseError
ns ParseError
n)

-- | Parse a type given as a string.
parseTypeName :: Text -> Parser Type
parseTypeName :: ParseError -> Parser Type
parseTypeName ParseError
typeName = case ParseError -> Maybe BasicType
nameToBasicType ParseError
typeName of
    Just BasicType
b -> Type -> Parser Type
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return (BasicType -> Type
TBasicType BasicType
b)
    Maybe BasicType
Nothing -> case (Char -> Bool) -> ParseError -> [ParseError]
T.split (Char
'.' Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==) ParseError
typeName of
                 [ParseError
ns, ParseError
n] -> ParseError -> ParseError -> Parser Type
parseFundamentalType ParseError
ns ParseError
n
                 [ParseError
n] -> do
                   ParseError
ns <- Parser ParseError
currentNamespace
                   ParseError -> ParseError -> Parser Type
parseFundamentalType ParseError
ns ParseError
n
                 [ParseError]
_ -> ParseError -> Parser Type
forall a. ParseError -> Parser a
parseError (ParseError -> Parser Type) -> ParseError -> Parser Type
forall a b. (a -> b) -> a -> b
$ ParseError
"Unsupported type form: \""
                                   ParseError -> ParseError -> ParseError
forall a. Semigroup a => a -> a -> a
<> ParseError
typeName ParseError -> ParseError -> ParseError
forall a. Semigroup a => a -> a -> a
<> ParseError
"\""

-- | Parse information on a "type" element. Returns either a `Type`,
-- or `Nothing` indicating that the name of the type in the
-- introspection data was "none" (associated with @void@ in C).
parseTypeInfo :: Parser (Maybe Type)
parseTypeInfo :: Parser (Maybe Type)
parseTypeInfo = do
  ParseError
typeName <- Name -> Parser ParseError
getAttr Name
"name"
  if ParseError
typeName ParseError -> ParseError -> Bool
forall a. Eq a => a -> a -> Bool
== ParseError
"none"
  then Maybe Type -> Parser (Maybe Type)
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Type
forall a. Maybe a
Nothing
  else Type -> Maybe Type
forall a. a -> Maybe a
Just (Type -> Maybe Type) -> Parser Type -> Parser (Maybe Type)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParseError -> Parser Type
parseTypeName ParseError
typeName

-- | Find the children giving the type of the given element.
parseTypeElements :: Parser [Maybe Type]
parseTypeElements :: Parser [Maybe Type]
parseTypeElements = do
  [Maybe Type]
types <- ParseError -> Parser (Maybe Type) -> Parser [Maybe Type]
forall a. ParseError -> Parser a -> Parser [a]
parseChildrenWithLocalName ParseError
"type" Parser (Maybe Type)
parseTypeInfo
  [Type]
arrays <- ParseError -> Parser Type -> Parser [Type]
forall a. ParseError -> Parser a -> Parser [a]
parseChildrenWithLocalName ParseError
"array" Parser Type
parseArrayInfo
  [Maybe Type] -> Parser [Maybe Type]
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return ([Maybe Type]
types [Maybe Type] -> [Maybe Type] -> [Maybe Type]
forall a. [a] -> [a] -> [a]
++ (Type -> Maybe Type) -> [Type] -> [Maybe Type]
forall a b. (a -> b) -> [a] -> [b]
map Type -> Maybe Type
forall a. a -> Maybe a
Just [Type]
arrays)

-- | Find the C name for the current element.
queryCType :: Parser (Maybe Text)
queryCType :: Parser (Maybe ParseError)
queryCType = GIRXMLNamespace -> Name -> Parser (Maybe ParseError)
queryAttrWithNamespace GIRXMLNamespace
CGIRNS Name
"type"

-- | Parse the C type for the current node.
parseCType :: Parser Text
parseCType :: Parser ParseError
parseCType = GIRXMLNamespace -> Name -> Parser ParseError
getAttrWithNamespace GIRXMLNamespace
CGIRNS Name
"type"

-- | Find the children giving the C type for the element.
parseCTypeNameElements :: Parser [Text]
parseCTypeNameElements :: Parser [ParseError]
parseCTypeNameElements = do
  [Maybe ParseError]
types <- ParseError
-> Parser (Maybe ParseError) -> Parser [Maybe ParseError]
forall a. ParseError -> Parser a -> Parser [a]
parseChildrenWithLocalName ParseError
"type" Parser (Maybe ParseError)
queryCType
  [Maybe ParseError]
arrays <- ParseError
-> Parser (Maybe ParseError) -> Parser [Maybe ParseError]
forall a. ParseError -> Parser a -> Parser [a]
parseChildrenWithLocalName ParseError
"array" Parser (Maybe ParseError)
queryCType
  [ParseError] -> Parser [ParseError]
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return ([Maybe ParseError] -> [ParseError]
forall a. [Maybe a] -> [a]
catMaybes ([Maybe ParseError]
types [Maybe ParseError] -> [Maybe ParseError] -> [Maybe ParseError]
forall a. [a] -> [a] -> [a]
++ [Maybe ParseError]
arrays))

-- | Try to find a type node, but do not error out if it is not
-- found. This _does_ give an error if more than one type node is
-- found, or if the type name is "none".
queryType :: Parser (Maybe Type)
queryType :: Parser (Maybe Type)
queryType = Parser [Maybe Type]
parseTypeElements Parser [Maybe Type]
-> ([Maybe Type] -> Parser (Maybe Type)) -> Parser (Maybe Type)
forall a b.
ReaderT ParseContext (Except ParseError) a
-> (a -> ReaderT ParseContext (Except ParseError) b)
-> ReaderT ParseContext (Except ParseError) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
            [Just Type
e] -> Maybe Type -> Parser (Maybe Type)
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return (Type -> Maybe Type
forall a. a -> Maybe a
Just Type
e)
            [] -> Maybe Type -> Parser (Maybe Type)
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Type
forall a. Maybe a
Nothing
            [Maybe Type
Nothing] -> ParseError -> Parser (Maybe Type)
forall a. ParseError -> Parser a
parseError (ParseError -> Parser (Maybe Type))
-> ParseError -> Parser (Maybe Type)
forall a b. (a -> b) -> a -> b
$ ParseError
"Unexpected \"none\" type."
            [Maybe Type]
_ -> ParseError -> Parser (Maybe Type)
forall a. ParseError -> Parser a
parseError (ParseError -> Parser (Maybe Type))
-> ParseError -> Parser (Maybe Type)
forall a b. (a -> b) -> a -> b
$ ParseError
"Found more than one type for the element."

-- | Parse the type of a node (which will be described by a child node
-- named "type" or "array").
parseType :: Parser Type
parseType :: Parser Type
parseType = Parser [Maybe Type]
parseTypeElements Parser [Maybe Type] -> ([Maybe Type] -> Parser Type) -> Parser Type
forall a b.
ReaderT ParseContext (Except ParseError) a
-> (a -> ReaderT ParseContext (Except ParseError) b)
-> ReaderT ParseContext (Except ParseError) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
            [Just Type
e] -> Type -> Parser Type
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return Type
e
            [] -> ParseError -> Parser Type
forall a. ParseError -> Parser a
parseError (ParseError -> Parser Type) -> ParseError -> Parser Type
forall a b. (a -> b) -> a -> b
$ ParseError
"Did not find a type for the element."
            [Maybe Type
Nothing] -> ParseError -> Parser Type
forall a. ParseError -> Parser a
parseError (ParseError -> Parser Type) -> ParseError -> Parser Type
forall a b. (a -> b) -> a -> b
$ ParseError
"Unexpected \"none\" type."
            [Maybe Type]
_ -> ParseError -> Parser Type
forall a. ParseError -> Parser a
parseError (ParseError -> Parser Type) -> ParseError -> Parser Type
forall a b. (a -> b) -> a -> b
$ ParseError
"Found more than one type for the element."

-- | Like `parseType`, but allow for @none@, returned as `Nothing`.
parseOptionalType :: Parser (Maybe Type)
parseOptionalType :: Parser (Maybe Type)
parseOptionalType =
    Parser [Maybe Type]
parseTypeElements Parser [Maybe Type]
-> ([Maybe Type] -> Parser (Maybe Type)) -> Parser (Maybe Type)
forall a b.
ReaderT ParseContext (Except ParseError) a
-> (a -> ReaderT ParseContext (Except ParseError) b)
-> ReaderT ParseContext (Except ParseError) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
           [Maybe Type
e] -> Maybe Type -> Parser (Maybe Type)
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Type
e
           [] -> ParseError -> Parser (Maybe Type)
forall a. ParseError -> Parser a
parseError (ParseError -> Parser (Maybe Type))
-> ParseError -> Parser (Maybe Type)
forall a b. (a -> b) -> a -> b
$ ParseError
"Did not find a type for the element."
           [Maybe Type]
_ -> ParseError -> Parser (Maybe Type)
forall a. ParseError -> Parser a
parseError (ParseError -> Parser (Maybe Type))
-> ParseError -> Parser (Maybe Type)
forall a b. (a -> b) -> a -> b
$ ParseError
"Found more than one type for the element."

-- | Parse the C-type associated to the element, if found.
queryElementCType :: Parser (Maybe Text)
queryElementCType :: Parser (Maybe ParseError)
queryElementCType = Parser [ParseError]
parseCTypeNameElements Parser [ParseError]
-> ([ParseError] -> Parser (Maybe ParseError))
-> Parser (Maybe ParseError)
forall a b.
ReaderT ParseContext (Except ParseError) a
-> (a -> ReaderT ParseContext (Except ParseError) b)
-> ReaderT ParseContext (Except ParseError) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
             [ParseError
ctype] -> Maybe ParseError -> Parser (Maybe ParseError)
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return (ParseError -> Maybe ParseError
forall a. a -> Maybe a
Just ParseError
ctype)
             [] -> Maybe ParseError -> Parser (Maybe ParseError)
forall a. a -> ReaderT ParseContext (Except ParseError) a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe ParseError
forall a. Maybe a
Nothing
             [ParseError]
_ -> ParseError -> Parser (Maybe ParseError)
forall a. ParseError -> Parser a
parseError (ParseError -> Parser (Maybe ParseError))
-> ParseError -> Parser (Maybe ParseError)
forall a b. (a -> b) -> a -> b
$ ParseError
"Found more than one type for the element."