{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE LambdaCase #-}
module Language.LSP.Types.Utils
( rdrop
, makeSingletonFromJSON
, makeRegHelper
, makeExtendingDatatype
, lspOptions
, lspOptionsUntagged
) where
import Control.Monad
import Data.Aeson
import Data.List
import Language.Haskell.TH
rdrop :: Int -> [a] -> [a]
rdrop :: forall a. Int -> [a] -> [a]
rdrop Int
cnt = forall a. [a] -> [a]
reverse forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Int -> [a] -> [a]
drop Int
cnt forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> [a]
reverse
makeSingletonFromJSON :: Name -> Name -> Q [Dec]
makeSingletonFromJSON :: Name -> Name -> Q [Dec]
makeSingletonFromJSON Name
wrap Name
gadt = do
TyConI (DataD Cxt
_ Name
_ [TyVarBndr ()]
_ Maybe Kind
_ [Con]
cons [DerivClause]
_) <- Name -> Q Info
reify Name
gadt
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Name -> Con -> Q [Dec]
makeInst Name
wrap) [Con]
cons
makeInst :: Name -> Con -> Q [Dec]
makeInst :: Name -> Con -> Q [Dec]
makeInst Name
wrap (GadtC [Name
sConstructor] [BangType]
args Kind
t) = do
[Name]
ns <- forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM (forall (t :: * -> *) a. Foldable t => t a -> Int
length [BangType]
args) (forall (m :: * -> *). Quote m => String -> m Name
newName String
"x")
let wrappedPat :: Q Pat
wrappedPat = forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat
conP Name
wrap [forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat
conP Name
sConstructor (forall a b. (a -> b) -> [a] -> [b]
map forall (m :: * -> *). Quote m => Name -> m Pat
varP [Name]
ns)]
unwrappedE :: Q Exp
unwrappedE = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Exp -> Exp -> Exp
AppE (Name -> Exp
ConE Name
sConstructor) (forall a b. (a -> b) -> [a] -> [b]
map Name -> Exp
VarE [Name]
ns)
[d| instance FromJSON $(pure t) where
parseJSON = parseJSON >=> \case
$wrappedPat -> pure $unwrappedE
_ -> mempty
|]
makeInst Name
wrap (ForallC [TyVarBndr Specificity]
_ Cxt
_ Con
con) = Name -> Con -> Q [Dec]
makeInst Name
wrap Con
con
makeInst Name
_ Con
_ = forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"makeInst only defined for GADT constructors"
makeRegHelper :: Name -> DecsQ
makeRegHelper :: Name -> Q [Dec]
makeRegHelper Name
regOptTypeName = do
Just Name
sMethodTypeName <- String -> Q (Maybe Name)
lookupTypeName String
"SMethod"
Just Name
fromClientName <- String -> Q (Maybe Name)
lookupValueName String
"FromClient"
TyConI (DataD Cxt
_ Name
_ [TyVarBndr ()]
_ Maybe Kind
_ [Con]
allCons [DerivClause]
_) <- Name -> Q Info
reify Name
sMethodTypeName
let isConsFromClient :: Con -> Q Bool
isConsFromClient (GadtC [Name]
_ [BangType]
_ (AppT Kind
_ Kind
method)) = Kind -> Q Bool
isMethodFromClient Kind
method
isConsFromClient Con
_ = forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
isMethodFromClient :: Type -> Q Bool
isMethodFromClient :: Kind -> Q Bool
isMethodFromClient (PromotedT Name
method) = do
DataConI Name
_ Kind
typ Name
_ <- Name -> Q Info
reify Name
method
case Kind
typ of
AppT (AppT Kind
_ (PromotedT Name
n)) Kind
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Name
n forall a. Eq a => a -> a -> Bool
== Name
fromClientName
Kind
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
isMethodFromClient Kind
_ = forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Didn't expect this type of Method!"
[Con]
cons <- forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM Con -> Q Bool
isConsFromClient [Con]
allCons
let conNames :: [Name]
conNames = forall a b. (a -> b) -> [a] -> [b]
map (\(GadtC [Name
name] [BangType]
_ Kind
_) -> Name
name) [Con]
cons
helperName :: Name
helperName = String -> Name
mkName String
"regHelper"
mkClause :: Name -> m Clause
mkClause Name
name = do
Name
x <- forall (m :: * -> *). Quote m => String -> m Name
newName String
"x"
forall (m :: * -> *).
Quote m =>
[m Pat] -> m Body -> [m Dec] -> m Clause
clause [ forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat
conP Name
name [], forall (m :: * -> *). Quote m => Name -> m Pat
varP Name
x ]
(forall (m :: * -> *). Quote m => m Exp -> m Body
normalB (forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
x))
[]
regOptTcon :: Q Kind
regOptTcon = forall (m :: * -> *). Quote m => Name -> m Kind
conT Name
regOptTypeName
Dec
fun <- forall (m :: * -> *). Quote m => Name -> [m Clause] -> m Dec
funD Name
helperName (forall a b. (a -> b) -> [a] -> [b]
map forall {m :: * -> *}. Quote m => Name -> m Clause
mkClause [Name]
conNames)
Dec
typSig <- forall (m :: * -> *). Quote m => Name -> m Kind -> m Dec
sigD Name
helperName forall a b. (a -> b) -> a -> b
$
[t| forall m x. $(conT sMethodTypeName) m
-> (Show ($regOptTcon m) => ToJSON ($regOptTcon m) => FromJSON ($regOptTcon m) => x)
-> x |]
forall (m :: * -> *) a. Monad m => a -> m a
return [Dec
typSig, Dec
fun]
makeExtendingDatatype :: String -> [Name] -> [(String, TypeQ)] -> DecsQ
makeExtendingDatatype :: String -> [Name] -> [(String, Q Kind)] -> Q [Dec]
makeExtendingDatatype String
datatypeNameStr [Name]
extends [(String, Q Kind)]
fields = do
[VarBangType]
extendFields <- forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [Name]
extends forall a b. (a -> b) -> a -> b
$ \Name
e -> do
TyConI (DataD Cxt
_ Name
_ [TyVarBndr ()]
_ Maybe Kind
_ [RecC Name
_ [VarBangType]
eFields] [DerivClause]
_) <- Name -> Q Info
reify Name
e
forall (m :: * -> *) a. Monad m => a -> m a
return [VarBangType]
eFields
let datatypeName :: Name
datatypeName = String -> Name
mkName String
datatypeNameStr
insts :: [Q Kind]
insts = [[t| Read |], [t| Show |], [t| Eq |]]
constructor :: Q Con
constructor = forall (m :: * -> *). Quote m => Name -> [m VarBangType] -> m Con
recC Name
datatypeName [Q VarBangType]
combinedFields
userFields :: [Q VarBangType]
userFields = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a b. (a -> b) -> [a] -> [b]
map [(String, Q Kind)]
fields forall a b. (a -> b) -> a -> b
$ \(String
s, Q Kind
typ) -> do
forall (m :: * -> *).
Quote m =>
Name -> m BangType -> m VarBangType
varBangType (String -> Name
mkName String
s) (forall (m :: * -> *). Quote m => m Bang -> m Kind -> m BangType
bangType (forall (m :: * -> *).
Quote m =>
m SourceUnpackedness -> m SourceStrictness -> m Bang
bang forall (m :: * -> *). Quote m => m SourceUnpackedness
noSourceUnpackedness forall (m :: * -> *). Quote m => m SourceStrictness
noSourceStrictness) Q Kind
typ)
combinedFields :: [Q VarBangType]
combinedFields = (forall a b. (a -> b) -> [a] -> [b]
map forall (f :: * -> *) a. Applicative f => a -> f a
pure [VarBangType]
extendFields) forall a. Semigroup a => a -> a -> a
<> [Q VarBangType]
userFields
derivs :: [Q DerivClause]
derivs = [forall (m :: * -> *).
Quote m =>
Maybe DerivStrategy -> [m Kind] -> m DerivClause
derivClause forall a. Maybe a
Nothing [Q Kind]
insts]
(\Dec
a -> [Dec
a]) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *).
Quote m =>
m Cxt
-> Name
-> [TyVarBndr ()]
-> Maybe Kind
-> [m Con]
-> [m DerivClause]
-> m Dec
dataD (forall (m :: * -> *). Quote m => [m Kind] -> m Cxt
cxt []) Name
datatypeName [] forall a. Maybe a
Nothing [Q Con
constructor] [Q DerivClause]
derivs
lspOptions :: Options
lspOptions :: Options
lspOptions = Options
defaultOptions { omitNothingFields :: Bool
omitNothingFields = Bool
True, fieldLabelModifier :: String -> String
fieldLabelModifier = String -> String
modifier }
where
modifier :: String -> String
modifier :: String -> String
modifier String
"_xdata" = String
"data"
modifier String
"_xtype" = String
"type"
modifier String
xs = forall a. Int -> [a] -> [a]
drop Int
1 String
xs
lspOptionsUntagged :: Options
lspOptionsUntagged :: Options
lspOptionsUntagged = Options
lspOptions { sumEncoding :: SumEncoding
sumEncoding = SumEncoding
UntaggedValue }