{-# LANGUAGE FlexibleInstances    #-}
{-# LANGUAGE PatternSynonyms      #-}
{-# LANGUAGE Trustworthy          #-}
{-# LANGUAGE TypeSynonymInstances #-}

{-# OPTIONS_GHC -fno-warn-orphans #-}

module Language.Sexp
  (
  -- * Parse and print
    decode
  , decodeMany
  , encode
  , format
  -- * Type
  , Sexp
  , pattern Atom
  , pattern Number
  , pattern Symbol
  , pattern String
  , pattern ParenList
  , pattern BracketList
  , pattern BraceList
  , pattern Modified
  -- ** Internal types
  , SexpF (..)
  , Atom (..)
  , Prefix (..)
  ) where

import Data.ByteString.Lazy.Char8 (ByteString, unpack)
import Data.Text (Text)
import Data.Scientific (Scientific)

import Language.Sexp.Types
import Language.Sexp.Parser (parseSexp_, parseSexps_)
import Language.Sexp.Lexer  (lexSexp)
import qualified Language.Sexp.Pretty as Internal
import qualified Language.Sexp.Encode as Internal

type Sexp = Fix SexpF

instance {-# OVERLAPPING #-} Show Sexp where
  show :: Sexp -> String
show = ByteString -> String
unpack (ByteString -> String) -> (Sexp -> ByteString) -> Sexp -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Sexp -> ByteString
encode

-- | Deserialise a 'Sexp' from a string
decode :: ByteString -> Either String Sexp
decode :: ByteString -> Either String Sexp
decode = (Fix (Compose (LocatedBy Position) SexpF) -> Sexp)
-> Either String (Fix (Compose (LocatedBy Position) SexpF))
-> Either String Sexp
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Fix (Compose (LocatedBy Position) SexpF) -> Sexp
forall (f :: * -> *) p.
Functor f =>
Fix (Compose (LocatedBy p) f) -> Fix f
stripLocation (Either String (Fix (Compose (LocatedBy Position) SexpF))
 -> Either String Sexp)
-> (ByteString
    -> Either String (Fix (Compose (LocatedBy Position) SexpF)))
-> ByteString
-> Either String Sexp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [LocatedBy Position Token]
-> Either String (Fix (Compose (LocatedBy Position) SexpF))
parseSexp_ ([LocatedBy Position Token]
 -> Either String (Fix (Compose (LocatedBy Position) SexpF)))
-> (ByteString -> [LocatedBy Position Token])
-> ByteString
-> Either String (Fix (Compose (LocatedBy Position) SexpF))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Position -> ByteString -> [LocatedBy Position Token]
lexSexp (String -> Int -> Int -> Position
Position String
"<string>" Int
1 Int
0)

-- | Deserialise potentially multiple 'Sexp' from a string
decodeMany :: ByteString -> Either String [Sexp]
decodeMany :: ByteString -> Either String [Sexp]
decodeMany = ([Fix (Compose (LocatedBy Position) SexpF)] -> [Sexp])
-> Either String [Fix (Compose (LocatedBy Position) SexpF)]
-> Either String [Sexp]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Fix (Compose (LocatedBy Position) SexpF) -> Sexp)
-> [Fix (Compose (LocatedBy Position) SexpF)] -> [Sexp]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Fix (Compose (LocatedBy Position) SexpF) -> Sexp
forall (f :: * -> *) p.
Functor f =>
Fix (Compose (LocatedBy p) f) -> Fix f
stripLocation) (Either String [Fix (Compose (LocatedBy Position) SexpF)]
 -> Either String [Sexp])
-> (ByteString
    -> Either String [Fix (Compose (LocatedBy Position) SexpF)])
-> ByteString
-> Either String [Sexp]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [LocatedBy Position Token]
-> Either String [Fix (Compose (LocatedBy Position) SexpF)]
parseSexps_ ([LocatedBy Position Token]
 -> Either String [Fix (Compose (LocatedBy Position) SexpF)])
-> (ByteString -> [LocatedBy Position Token])
-> ByteString
-> Either String [Fix (Compose (LocatedBy Position) SexpF)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Position -> ByteString -> [LocatedBy Position Token]
lexSexp (String -> Int -> Int -> Position
Position String
"<string>" Int
1 Int
0)

-- | Serialise a 'Sexp' into a compact string
encode :: Sexp -> ByteString
encode :: Sexp -> ByteString
encode = Sexp -> ByteString
Internal.encode

-- | Serialise a 'Sexp' into a pretty-printed string
format :: Sexp -> ByteString
format :: Sexp -> ByteString
format = Sexp -> ByteString
Internal.format

----------------------------------------------------------------------

pattern Atom :: Atom -> Sexp
pattern $bAtom :: Atom -> Sexp
$mAtom :: forall r. Sexp -> (Atom -> r) -> (Void# -> r) -> r
Atom a = Fix (AtomF a)

pattern Number :: Scientific -> Sexp
pattern $bNumber :: Scientific -> Sexp
$mNumber :: forall r. Sexp -> (Scientific -> r) -> (Void# -> r) -> r
Number a = Fix (AtomF (AtomNumber a))

pattern Symbol :: Text -> Sexp
pattern $bSymbol :: Text -> Sexp
$mSymbol :: forall r. Sexp -> (Text -> r) -> (Void# -> r) -> r
Symbol a = Fix (AtomF (AtomSymbol a))

pattern String :: Text -> Sexp
pattern $bString :: Text -> Sexp
$mString :: forall r. Sexp -> (Text -> r) -> (Void# -> r) -> r
String a = Fix (AtomF (AtomString a))

pattern ParenList :: [Sexp] -> Sexp
pattern $bParenList :: [Sexp] -> Sexp
$mParenList :: forall r. Sexp -> ([Sexp] -> r) -> (Void# -> r) -> r
ParenList ls = Fix (ParenListF ls)

pattern BracketList :: [Sexp] -> Sexp
pattern $bBracketList :: [Sexp] -> Sexp
$mBracketList :: forall r. Sexp -> ([Sexp] -> r) -> (Void# -> r) -> r
BracketList ls = Fix (BracketListF ls)

pattern BraceList :: [Sexp] -> Sexp
pattern $bBraceList :: [Sexp] -> Sexp
$mBraceList :: forall r. Sexp -> ([Sexp] -> r) -> (Void# -> r) -> r
BraceList ls = Fix (BraceListF ls)

pattern Modified :: Prefix -> Sexp -> Sexp
pattern $bModified :: Prefix -> Sexp -> Sexp
$mModified :: forall r. Sexp -> (Prefix -> Sexp -> r) -> (Void# -> r) -> r
Modified q s = Fix (ModifiedF q s)