xref: /freebsd-src/contrib/libucl/haskell/hucl.hs (revision 242b24828472137ec4411826b86e753d49bd2c39)
1*273c26a3SBaptiste Daroussin{-# LANGUAGE ForeignFunctionInterface #-}
2*273c26a3SBaptiste Daroussin
3*273c26a3SBaptiste Daroussin-- an example UCL FFI module:
4*273c26a3SBaptiste Daroussin-- uses the Object Model from Messagepack to emit
5*273c26a3SBaptiste Daroussin--
6*273c26a3SBaptiste Daroussin
7*273c26a3SBaptiste Daroussinmodule Data.UCL ( unpack ) where
8*273c26a3SBaptiste Daroussinimport Foreign.C
9*273c26a3SBaptiste Daroussinimport Foreign.Ptr
10*273c26a3SBaptiste Daroussinimport System.IO.Unsafe ( unsafePerformIO )
11*273c26a3SBaptiste Daroussinimport qualified Data.Text as T
12*273c26a3SBaptiste Daroussinimport qualified Data.Vector as V
13*273c26a3SBaptiste Daroussinimport qualified Data.MessagePack as MSG
14*273c26a3SBaptiste Daroussin
15*273c26a3SBaptiste Daroussintype ParserHandle = Ptr ()
16*273c26a3SBaptiste Daroussintype UCLObjectHandle = Ptr ()
17*273c26a3SBaptiste Daroussintype UCLIterHandle = Ptr ()
18*273c26a3SBaptiste Daroussintype UCLEmitterType = CInt
19*273c26a3SBaptiste Daroussintype ErrorString = String
20*273c26a3SBaptiste Daroussin
21*273c26a3SBaptiste Daroussin
22*273c26a3SBaptiste Daroussinforeign import ccall "ucl_parser_new" ucl_parser_new :: CInt -> ParserHandle
23*273c26a3SBaptiste Daroussinforeign import ccall "ucl_parser_add_string" ucl_parser_add_string :: ParserHandle -> CString -> CUInt -> IO Bool
24*273c26a3SBaptiste Daroussinforeign import ccall "ucl_parser_add_file" ucl_parser_add_file :: ParserHandle -> CString -> IO Bool
25*273c26a3SBaptiste Daroussinforeign import ccall "ucl_parser_get_object" ucl_parser_get_object :: ParserHandle -> UCLObjectHandle
26*273c26a3SBaptiste Daroussinforeign import ccall "ucl_parser_get_error" ucl_parser_get_error :: ParserHandle -> CString
27*273c26a3SBaptiste Daroussin
28*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_iterate_new" ucl_object_iterate_new :: UCLObjectHandle -> UCLIterHandle
29*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_iterate_safe" ucl_object_iterate_safe :: UCLIterHandle -> Bool -> UCLObjectHandle
30*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_type" ucl_object_type :: UCLObjectHandle -> CUInt
31*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_key" ucl_object_key :: UCLObjectHandle -> CString
32*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_toint" ucl_object_toint :: UCLObjectHandle -> CInt
33*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_todouble" ucl_object_todouble :: UCLObjectHandle -> CDouble
34*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_tostring" ucl_object_tostring :: UCLObjectHandle -> CString
35*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_toboolean" ucl_object_toboolean :: UCLObjectHandle -> Bool
36*273c26a3SBaptiste Daroussin
37*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_emit" ucl_object_emit :: UCLObjectHandle -> UCLEmitterType -> CString
38*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_emit_len" ucl_object_emit_len :: UCLObjectHandle -> UCLEmitterType -> Ptr CSize -> IO CString
39*273c26a3SBaptiste Daroussin
40*273c26a3SBaptiste Daroussintype UCL_TYPE = CUInt
41*273c26a3SBaptiste Daroussinucl_OBJECT :: UCL_TYPE
42*273c26a3SBaptiste Daroussinucl_OBJECT = 0
43*273c26a3SBaptiste Daroussinucl_ARRAY :: UCL_TYPE
44*273c26a3SBaptiste Daroussinucl_ARRAY = 1
45*273c26a3SBaptiste Daroussinucl_INT :: UCL_TYPE
46*273c26a3SBaptiste Daroussinucl_INT = 2
47*273c26a3SBaptiste Daroussinucl_FLOAT :: UCL_TYPE
48*273c26a3SBaptiste Daroussinucl_FLOAT = 3
49*273c26a3SBaptiste Daroussinucl_STRING :: UCL_TYPE
50*273c26a3SBaptiste Daroussinucl_STRING = 4
51*273c26a3SBaptiste Daroussinucl_BOOLEAN :: UCL_TYPE
52*273c26a3SBaptiste Daroussinucl_BOOLEAN = 5
53*273c26a3SBaptiste Daroussinucl_TIME :: UCL_TYPE
54*273c26a3SBaptiste Daroussinucl_TIME = 6
55*273c26a3SBaptiste Daroussinucl_USERDATA :: UCL_TYPE
56*273c26a3SBaptiste Daroussinucl_USERDATA = 7
57*273c26a3SBaptiste Daroussinucl_NULL :: UCL_TYPE
58*273c26a3SBaptiste Daroussinucl_NULL = 8
59*273c26a3SBaptiste Daroussin
60*273c26a3SBaptiste Daroussinucl_emit_json           :: UCLEmitterType
61*273c26a3SBaptiste Daroussinucl_emit_json         = 0
62*273c26a3SBaptiste Daroussinucl_emit_json_compact   :: UCLEmitterType
63*273c26a3SBaptiste Daroussinucl_emit_json_compact = 1 :: UCLEmitterType
64*273c26a3SBaptiste Daroussinucl_emit_msgpack        :: UCLEmitterType
65*273c26a3SBaptiste Daroussinucl_emit_msgpack      = 4 :: UCLEmitterType
66*273c26a3SBaptiste Daroussin
67*273c26a3SBaptiste Daroussinucl_parser_parse_string_pure :: String -> Either UCLObjectHandle ErrorString
68*273c26a3SBaptiste Daroussinucl_parser_parse_string_pure s = unsafePerformIO $ do
69*273c26a3SBaptiste Daroussin    cs <- newCString s
70*273c26a3SBaptiste Daroussin    let p = ucl_parser_new 0x4
71*273c26a3SBaptiste Daroussin    didParse <- ucl_parser_add_string p cs (toEnum $ length s)
72*273c26a3SBaptiste Daroussin    if didParse
73*273c26a3SBaptiste Daroussin    then return $ Left $ ucl_parser_get_object p
74*273c26a3SBaptiste Daroussin    else Right <$> peekCString ( ucl_parser_get_error p)
75*273c26a3SBaptiste Daroussin
76*273c26a3SBaptiste Daroussinucl_parser_add_file_pure :: String -> Either UCLObjectHandle ErrorString
77*273c26a3SBaptiste Daroussinucl_parser_add_file_pure s = unsafePerformIO $ do
78*273c26a3SBaptiste Daroussin    cs <- newCString s
79*273c26a3SBaptiste Daroussin    let p = ucl_parser_new 0x4
80*273c26a3SBaptiste Daroussin    didParse <- ucl_parser_add_file p cs
81*273c26a3SBaptiste Daroussin    if didParse
82*273c26a3SBaptiste Daroussin    then return $ Left $ ucl_parser_get_object p
83*273c26a3SBaptiste Daroussin    else Right <$> peekCString ( ucl_parser_get_error p)
84*273c26a3SBaptiste Daroussin
85*273c26a3SBaptiste Daroussinunpack :: MSG.MessagePack a => String -> Either a ErrorString
86*273c26a3SBaptiste Daroussinunpack s = case ucl_parser_parse_string_pure s of
87*273c26a3SBaptiste Daroussin    (Right err) -> Right err
88*273c26a3SBaptiste Daroussin    (Left obj)  -> case MSG.fromObject (ucl_to_msgpack_object obj) of
89*273c26a3SBaptiste Daroussin        Nothing  -> Right "MessagePack fromObject Error"
90*273c26a3SBaptiste Daroussin        (Just a) -> Left a
91*273c26a3SBaptiste Daroussin
92*273c26a3SBaptiste Daroussinucl_to_msgpack_object :: UCLObjectHandle -> MSG.Object
93*273c26a3SBaptiste Daroussinucl_to_msgpack_object o = toMsgPackObj (ucl_object_type o) o
94*273c26a3SBaptiste Daroussin    where
95*273c26a3SBaptiste Daroussin        toMsgPackObj n obj
96*273c26a3SBaptiste Daroussin            |n==ucl_OBJECT   = MSG.ObjectMap $ uclObjectToVector obj
97*273c26a3SBaptiste Daroussin            |n==ucl_ARRAY    = MSG.ObjectArray undefined
98*273c26a3SBaptiste Daroussin            |n==ucl_INT      = MSG.ObjectInt $ fromEnum $ ucl_object_toint obj
99*273c26a3SBaptiste Daroussin            |n==ucl_FLOAT    = MSG.ObjectDouble $ realToFrac $ ucl_object_todouble obj
100*273c26a3SBaptiste Daroussin            |n==ucl_STRING   = MSG.ObjectStr $ T.pack $ unsafePerformIO $ peekCString $ ucl_object_tostring obj
101*273c26a3SBaptiste Daroussin            |n==ucl_BOOLEAN  = MSG.ObjectBool $ ucl_object_toboolean obj
102*273c26a3SBaptiste Daroussin            |n==ucl_TIME     = error "time undefined"
103*273c26a3SBaptiste Daroussin            |n==ucl_USERDATA = error "userdata undefined"
104*273c26a3SBaptiste Daroussin            |n==ucl_NULL     = error "null undefined"
105*273c26a3SBaptiste Daroussin            |otherwise = error "\"Unknown Type\" Error"
106*273c26a3SBaptiste Daroussin
107*273c26a3SBaptiste DaroussinuclObjectToVector :: UCLObjectHandle -> V.Vector (MSG.Object,MSG.Object)
108*273c26a3SBaptiste DaroussinuclObjectToVector o = iterateObject (ucl_object_iterate_safe iter True ) iter V.empty
109*273c26a3SBaptiste Daroussin    where
110*273c26a3SBaptiste Daroussin        iter = ucl_object_iterate_new o
111*273c26a3SBaptiste Daroussin        iterateObject obj it vec = if ucl_object_type obj == ucl_NULL
112*273c26a3SBaptiste Daroussin            then vec
113*273c26a3SBaptiste Daroussin            else iterateObject (ucl_object_iterate_safe it True) it (V.snoc vec ( getUclKey obj , ucl_to_msgpack_object obj))
114*273c26a3SBaptiste Daroussin        getUclKey obj = MSG.ObjectStr $ T.pack $ unsafePerformIO $ peekCString $ ucl_object_key obj
115*273c26a3SBaptiste Daroussin
116*273c26a3SBaptiste DaroussinuclArrayToVector :: UCLObjectHandle -> V.Vector MSG.Object
117*273c26a3SBaptiste DaroussinuclArrayToVector o = iterateArray (ucl_object_iterate_safe iter True ) iter V.empty
118*273c26a3SBaptiste Daroussin    where
119*273c26a3SBaptiste Daroussin        iter = ucl_object_iterate_new o
120*273c26a3SBaptiste Daroussin        iterateArray obj it vec = if ucl_object_type obj == ucl_NULL
121*273c26a3SBaptiste Daroussin            then vec
122*273c26a3SBaptiste Daroussin            else iterateArray (ucl_object_iterate_safe it True) it (V.snoc vec (ucl_to_msgpack_object obj))
123*273c26a3SBaptiste Daroussin
124