module Language.Lean.Internal.Name
  ( Name
  , anonymousName
  , nameAppend
  , nameAppendIndex
  , NameView(..)
  , nameView
  , nameToString
    
  , NamePtr
  , OutNamePtr
  , withName
  , ListName
  , ListNamePtr
  , OutListNamePtr
  , withListName
  ) where
import Control.Exception (assert, throw)
import Control.Lens (toListOf)
import Data.Char (isDigit)
import Data.String
import Foreign
import Foreign.C
import System.IO.Unsafe
import Language.Lean.List
import Language.Lean.Internal.Exception
import Language.Lean.Internal.Exception.Unsafe
import Language.Lean.Internal.String
newtype Name = Name (ForeignPtr Name)
withName :: Name -> (Ptr Name -> IO a) -> IO a
withName (Name fo) = withForeignPtr $! fo
type NamePtr = Ptr (Name)
type OutNamePtr = Ptr (NamePtr)
foreign import ccall unsafe "&lean_name_del"
  lean_name_del_ptr :: FunPtr (NamePtr -> IO ())
instance IsLeanValue Name (Ptr Name) where
  mkLeanValue v = Name <$> newForeignPtr lean_name_del_ptr v
instance Eq Name where
  (==) = lean_name_eq
lean_name_eq :: (Name) -> (Name) -> (Bool)
lean_name_eq a1 a2 =
  unsafePerformIO $
  (withName) a1 $ \a1' -> 
  (withName) a2 $ \a2' -> 
  let {res = lean_name_eq'_ a1' a2'} in
  let {res' = toBool res} in
  return (res')
instance Ord Name where
   x <= y = not (lean_name_quick_lt y x)
lean_name_quick_lt :: (Name) -> (Name) -> (Bool)
lean_name_quick_lt a1 a2 =
  unsafePerformIO $
  (withName) a1 $ \a1' -> 
  (withName) a2 $ \a2' -> 
  let {res = lean_name_quick_lt'_ a1' a2'} in
  let {res' = toBool res} in
  return (res')
nameToString :: Name -> String
nameToString nm = tryGetLeanValue $ lean_name_to_string nm
instance Show Name where
  show = show . nameToString
lean_name_to_string :: (Name) -> (Ptr CString) -> (OutExceptionPtr) -> IO ((Bool))
lean_name_to_string a1 a2 a3 =
  (withName) a1 $ \a1' -> 
  let {a2' = id a2} in 
  let {a3' = id a3} in 
  lean_name_to_string'_ a1' a2' a3' >>= \res ->
  let {res' = toBool res} in
  return (res')
anonymousName :: Name
anonymousName = tryGetLeanValue lean_name_mk_anonymous
nameAppend :: Name -> String -> Name
nameAppend pre r = tryGetLeanValue (lean_name_mk_str pre r)
nameAppendIndex :: Name -> Word32 -> Name
nameAppendIndex pre i = tryGetLeanValue (lean_name_mk_idx pre i)
lean_name_mk_anonymous :: (OutNamePtr) -> (OutExceptionPtr) -> IO ((Bool))
lean_name_mk_anonymous a1 a2 =
  let {a1' = id a1} in 
  let {a2' = id a2} in 
  lean_name_mk_anonymous'_ a1' a2' >>= \res ->
  let {res' = toBool res} in
  return (res')
lean_name_mk_str :: (Name) -> (String) -> (OutNamePtr) -> (OutExceptionPtr) -> IO ((Bool))
lean_name_mk_str a1 a2 a3 a4 =
  (withName) a1 $ \a1' -> 
  withLeanStringPtr a2 $ \a2' -> 
  let {a3' = id a3} in 
  let {a4' = id a4} in 
  lean_name_mk_str'_ a1' a2' a3' a4' >>= \res ->
  let {res' = toBool res} in
  return (res')
lean_name_mk_idx :: (Name) -> (Word32) -> (OutNamePtr) -> (OutExceptionPtr) -> IO ((Bool))
lean_name_mk_idx a1 a2 a3 a4 =
  (withName) a1 $ \a1' -> 
  let {a2' = fromIntegral a2} in 
  let {a3' = id a3} in 
  let {a4' = id a4} in 
  lean_name_mk_idx'_ a1' a2' a3' a4' >>= \res ->
  let {res' = toBool res} in
  return (res')
data NameView
   = AnonymousName
     
   | StringName Name String
     
   | IndexName Name Word32
     
  deriving (Show)
nameView :: Name -> NameView
nameView nm =
  if lean_name_is_anonymous nm then
    AnonymousName
  else if lean_name_is_str nm then do
    StringName (tryGetLeanValue $ lean_name_get_prefix nm)
               (tryGetLeanValue $ lean_name_get_str nm)
  else assert (lean_name_is_idx nm) $ do
    IndexName (tryGetLeanValue $ lean_name_get_prefix nm)
              (tryGetLeanValue $ lean_name_get_idx nm)
lean_name_is_anonymous :: (Name) -> (Bool)
lean_name_is_anonymous a1 =
  unsafePerformIO $
  (withName) a1 $ \a1' -> 
  let {res = lean_name_is_anonymous'_ a1'} in
  let {res' = toBool res} in
  return (res')
lean_name_is_str :: (Name) -> (Bool)
lean_name_is_str a1 =
  unsafePerformIO $
  (withName) a1 $ \a1' -> 
  let {res = lean_name_is_str'_ a1'} in
  let {res' = toBool res} in
  return (res')
lean_name_is_idx :: (Name) -> (Bool)
lean_name_is_idx a1 =
  unsafePerformIO $
  (withName) a1 $ \a1' -> 
  let {res = lean_name_is_idx'_ a1'} in
  let {res' = toBool res} in
  return (res')
lean_name_get_prefix :: (Name) -> (OutNamePtr) -> (OutExceptionPtr) -> IO ((Bool))
lean_name_get_prefix a1 a2 a3 =
  (withName) a1 $ \a1' -> 
  let {a2' = id a2} in 
  let {a3' = id a3} in 
  lean_name_get_prefix'_ a1' a2' a3' >>= \res ->
  let {res' = toBool res} in
  return (res')
lean_name_get_str :: (Name) -> (Ptr CString) -> (OutExceptionPtr) -> IO ((Bool))
lean_name_get_str a1 a2 a3 =
  (withName) a1 $ \a1' -> 
  let {a2' = id a2} in 
  let {a3' = id a3} in 
  lean_name_get_str'_ a1' a2' a3' >>= \res ->
  let {res' = toBool res} in
  return (res')
lean_name_get_idx :: (Name) -> (Ptr CUInt) -> (OutExceptionPtr) -> IO ((Bool))
lean_name_get_idx a1 a2 a3 =
  (withName) a1 $ \a1' -> 
  let {a2' = id a2} in 
  let {a3' = id a3} in 
  lean_name_get_idx'_ a1' a2' a3' >>= \res ->
  let {res' = toBool res} in
  return (res')
instance IsString Name where
  fromString = go anonymousName
    where
      go nm "" = nm
      go nm s  =
        case break (== '.') s of
          (h,'.':r) -> go (go' nm h) r
          (h,r)     -> assert (null r) (go' nm h)
      go' nm s@(c:_) | isDigit c =
        case reads s of
          [(i,"")] -> nameAppendIndex nm i
          _        -> throw $ leanKernelException msg
            where
              msg = "Identifiers cannot begin with a digit."
      go' _ "" = throw $ leanKernelException "Identifiers cannot be empty"
      go' nm s = nameAppend nm s
instance Monoid Name where
  mempty  = anonymousName
  mappend x y =
    case nameView y of
      AnonymousName   -> x
      StringName yn s -> mappend x yn `nameAppend` s
      IndexName  yn i -> mappend x yn `nameAppendIndex` i
newtype instance List Name = ListName (ForeignPtr (List Name))
type ListNamePtr = Ptr (ListName)
type OutListNamePtr = Ptr (ListNamePtr)
type ListName = List Name
withListName :: ListName -> (Ptr ListName -> IO a) -> IO a
withListName (ListName p) = withForeignPtr $! p
instance IsLeanValue (List Name) (Ptr (List Name)) where
  mkLeanValue = fmap ListName . newForeignPtr lean_list_name_del_ptr
foreign import ccall unsafe "&lean_list_name_del"
  lean_list_name_del_ptr :: FunPtr (ListNamePtr -> IO ())
instance Eq (List Name) where
  (==) = lean_list_name_eq
lean_list_name_eq :: (ListName) -> (ListName) -> (Bool)
lean_list_name_eq a1 a2 =
  unsafePerformIO $
  (withListName) a1 $ \a1' -> 
  (withListName) a2 $ \a2' -> 
  let {res = lean_list_name_eq'_ a1' a2'} in
  let {res' = toBool res} in
  return (res')
instance IsListIso (List Name) where
  nil = tryGetLeanValue $ lean_list_name_mk_nil
  h <| r = tryGetLeanValue $ lean_list_name_mk_cons h r
  listView l =
    if lean_list_name_is_cons l then
      tryGetLeanValue (lean_list_name_head l)
        :< tryGetLeanValue (lean_list_name_tail l)
    else
      Nil
lean_list_name_mk_nil :: (OutListNamePtr) -> (OutExceptionPtr) -> IO ((Bool))
lean_list_name_mk_nil a1 a2 =
  let {a1' = id a1} in 
  let {a2' = id a2} in 
  lean_list_name_mk_nil'_ a1' a2' >>= \res ->
  let {res' = toBool res} in
  return (res')
lean_list_name_mk_cons :: (Name) -> (ListName) -> (OutListNamePtr) -> (OutExceptionPtr) -> IO ((Bool))
lean_list_name_mk_cons a1 a2 a3 a4 =
  (withName) a1 $ \a1' -> 
  (withListName) a2 $ \a2' -> 
  let {a3' = id a3} in 
  let {a4' = id a4} in 
  lean_list_name_mk_cons'_ a1' a2' a3' a4' >>= \res ->
  let {res' = toBool res} in
  return (res')
lean_list_name_is_cons :: (ListName) -> (Bool)
lean_list_name_is_cons a1 =
  unsafePerformIO $
  (withListName) a1 $ \a1' -> 
  let {res = lean_list_name_is_cons'_ a1'} in
  let {res' = toBool res} in
  return (res')
lean_list_name_head :: (ListName) -> (OutNamePtr) -> (OutExceptionPtr) -> IO ((Bool))
lean_list_name_head a1 a2 a3 =
  (withListName) a1 $ \a1' -> 
  let {a2' = id a2} in 
  let {a3' = id a3} in 
  lean_list_name_head'_ a1' a2' a3' >>= \res ->
  let {res' = toBool res} in
  return (res')
lean_list_name_tail :: (ListName) -> (OutListNamePtr) -> (OutExceptionPtr) -> IO ((Bool))
lean_list_name_tail a1 a2 a3 =
  (withListName) a1 $ \a1' -> 
  let {a2' = id a2} in 
  let {a3' = id a3} in 
  lean_list_name_tail'_ a1' a2' a3' >>= \res ->
  let {res' = toBool res} in
  return (res')
instance IsList (List Name) where
  type Item ListName = Name
  fromList = fromListDefault
  toList = toListOf traverseList
instance Show (List Name) where
  showsPrec _ l = showList (toList l)
foreign import ccall unsafe "Language/Lean/Internal/Name.chs.h lean_name_eq"
  lean_name_eq'_ :: ((NamePtr) -> ((NamePtr) -> CInt))
foreign import ccall unsafe "Language/Lean/Internal/Name.chs.h lean_name_quick_lt"
  lean_name_quick_lt'_ :: ((NamePtr) -> ((NamePtr) -> CInt))
foreign import ccall unsafe "Language/Lean/Internal/Name.chs.h lean_name_to_string"
  lean_name_to_string'_ :: ((NamePtr) -> ((Ptr (Ptr CChar)) -> ((OutExceptionPtr) -> (IO CInt))))
foreign import ccall unsafe "Language/Lean/Internal/Name.chs.h lean_name_mk_anonymous"
  lean_name_mk_anonymous'_ :: ((OutNamePtr) -> ((OutExceptionPtr) -> (IO CInt)))
foreign import ccall unsafe "Language/Lean/Internal/Name.chs.h lean_name_mk_str"
  lean_name_mk_str'_ :: ((NamePtr) -> ((Ptr CChar) -> ((OutNamePtr) -> ((OutExceptionPtr) -> (IO CInt)))))
foreign import ccall unsafe "Language/Lean/Internal/Name.chs.h lean_name_mk_idx"
  lean_name_mk_idx'_ :: ((NamePtr) -> (CUInt -> ((OutNamePtr) -> ((OutExceptionPtr) -> (IO CInt)))))
foreign import ccall unsafe "Language/Lean/Internal/Name.chs.h lean_name_is_anonymous"
  lean_name_is_anonymous'_ :: ((NamePtr) -> CInt)
foreign import ccall unsafe "Language/Lean/Internal/Name.chs.h lean_name_is_str"
  lean_name_is_str'_ :: ((NamePtr) -> CInt)
foreign import ccall unsafe "Language/Lean/Internal/Name.chs.h lean_name_is_idx"
  lean_name_is_idx'_ :: ((NamePtr) -> CInt)
foreign import ccall unsafe "Language/Lean/Internal/Name.chs.h lean_name_get_prefix"
  lean_name_get_prefix'_ :: ((NamePtr) -> ((OutNamePtr) -> ((OutExceptionPtr) -> (IO CInt))))
foreign import ccall unsafe "Language/Lean/Internal/Name.chs.h lean_name_get_str"
  lean_name_get_str'_ :: ((NamePtr) -> ((Ptr (Ptr CChar)) -> ((OutExceptionPtr) -> (IO CInt))))
foreign import ccall unsafe "Language/Lean/Internal/Name.chs.h lean_name_get_idx"
  lean_name_get_idx'_ :: ((NamePtr) -> ((Ptr CUInt) -> ((OutExceptionPtr) -> (IO CInt))))
foreign import ccall unsafe "Language/Lean/Internal/Name.chs.h lean_list_name_eq"
  lean_list_name_eq'_ :: ((ListNamePtr) -> ((ListNamePtr) -> CInt))
foreign import ccall unsafe "Language/Lean/Internal/Name.chs.h lean_list_name_mk_nil"
  lean_list_name_mk_nil'_ :: ((OutListNamePtr) -> ((OutExceptionPtr) -> (IO CInt)))
foreign import ccall unsafe "Language/Lean/Internal/Name.chs.h lean_list_name_mk_cons"
  lean_list_name_mk_cons'_ :: ((NamePtr) -> ((ListNamePtr) -> ((OutListNamePtr) -> ((OutExceptionPtr) -> (IO CInt)))))
foreign import ccall unsafe "Language/Lean/Internal/Name.chs.h lean_list_name_is_cons"
  lean_list_name_is_cons'_ :: ((ListNamePtr) -> CInt)
foreign import ccall unsafe "Language/Lean/Internal/Name.chs.h lean_list_name_head"
  lean_list_name_head'_ :: ((ListNamePtr) -> ((OutNamePtr) -> ((OutExceptionPtr) -> (IO CInt))))
foreign import ccall unsafe "Language/Lean/Internal/Name.chs.h lean_list_name_tail"
  lean_list_name_tail'_ :: ((ListNamePtr) -> ((OutListNamePtr) -> ((OutExceptionPtr) -> (IO CInt))))