{-# LANGUAGE CPP #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE ExistentialQuantification #-}
module Text.Shakespeare.I18N
( mkMessage
, mkMessageFor
, mkMessageVariant
, RenderMessage (..)
, ToMessage (..)
, SomeMessage (..)
, Lang
) where
import Language.Haskell.TH.Syntax hiding (makeRelativeToProject)
import Control.Applicative ((<$>))
import Control.Monad (filterM, forM)
import Data.Text (Text, pack, unpack)
import System.Directory
import Data.FileEmbed (makeRelativeToProject)
import Data.Maybe (catMaybes)
import Data.List (isSuffixOf, sortBy, foldl')
import qualified Data.Map as Map
import qualified Data.ByteString as S
import Data.Text.Encoding (decodeUtf8)
import Data.Char (isSpace, toLower, toUpper)
import Data.Ord (comparing)
import Text.Shakespeare.Base (Deref (..), Ident (..), parseHash, derefToExp)
import Text.ParserCombinators.Parsec (parse, many, eof, many1, noneOf, (<|>))
import Control.Arrow ((***))
import Data.Monoid (mempty, mappend)
import qualified Data.Text as T
import Data.String (IsString (fromString))
class ToMessage a where
toMessage :: a -> Text
instance ToMessage Text where
toMessage :: Text -> Text
toMessage = Text -> Text
forall a. a -> a
id
instance ToMessage String where
toMessage :: String -> Text
toMessage = String -> Text
Data.Text.pack
class RenderMessage master message where
renderMessage :: master
-> [Lang]
-> message
-> Text
instance RenderMessage master Text where
renderMessage :: master -> [Text] -> Text -> Text
renderMessage master
_ [Text]
_ = Text -> Text
forall a. a -> a
id
type Lang = Text
mkMessage :: String
-> FilePath
-> Lang
-> Q [Dec]
mkMessage :: String -> String -> Text -> Q [Dec]
mkMessage String
dt String
folder Text
lang =
Bool
-> String
-> String
-> String
-> String
-> String
-> Text
-> Q [Dec]
mkMessageCommon Bool
True String
"Msg" String
"Message" String
dt String
dt String
folder Text
lang
mkMessageFor :: String
-> String
-> FilePath
-> Lang
-> Q [Dec]
mkMessageFor :: String -> String -> String -> Text -> Q [Dec]
mkMessageFor String
master String
dt String
folder Text
lang = Bool
-> String
-> String
-> String
-> String
-> String
-> Text
-> Q [Dec]
mkMessageCommon Bool
False String
"" String
"" String
master String
dt String
folder Text
lang
mkMessageVariant :: String
-> String
-> FilePath
-> Lang
-> Q [Dec]
mkMessageVariant :: String -> String -> String -> Text -> Q [Dec]
mkMessageVariant String
master String
dt String
folder Text
lang = Bool
-> String
-> String
-> String
-> String
-> String
-> Text
-> Q [Dec]
mkMessageCommon Bool
False String
"Msg" String
"Message" String
master String
dt String
folder Text
lang
mkMessageCommon :: Bool
-> String
-> String
-> String
-> String
-> FilePath
-> Lang
-> Q [Dec]
mkMessageCommon :: Bool
-> String
-> String
-> String
-> String
-> String
-> Text
-> Q [Dec]
mkMessageCommon Bool
genType String
prefix String
postfix String
master String
dt String
rawFolder Text
lang = do
String
folder <- String -> Q String
makeRelativeToProject String
rawFolder
[String]
files <- IO [String] -> Q [String]
forall (m :: * -> *) a. Quasi m => IO a -> m a
qRunIO (IO [String] -> Q [String]) -> IO [String] -> Q [String]
forall a b. (a -> b) -> a -> b
$ String -> IO [String]
getDirectoryContents String
folder
let files' :: [String]
files' = (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [String
".", String
".."]) [String]
files
([[String]]
filess, [(Text, [Def])]
contents) <- IO ([[String]], [(Text, [Def])]) -> Q ([[String]], [(Text, [Def])])
forall (m :: * -> *) a. Quasi m => IO a -> m a
qRunIO (IO ([[String]], [(Text, [Def])])
-> Q ([[String]], [(Text, [Def])]))
-> IO ([[String]], [(Text, [Def])])
-> Q ([[String]], [(Text, [Def])])
forall a b. (a -> b) -> a -> b
$ ([Maybe ([String], (Text, [Def]))]
-> ([[String]], [(Text, [Def])]))
-> IO [Maybe ([String], (Text, [Def]))]
-> IO ([[String]], [(Text, [Def])])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([([String], (Text, [Def]))] -> ([[String]], [(Text, [Def])])
forall a b. [(a, b)] -> ([a], [b])
unzip ([([String], (Text, [Def]))] -> ([[String]], [(Text, [Def])]))
-> ([Maybe ([String], (Text, [Def]))]
-> [([String], (Text, [Def]))])
-> [Maybe ([String], (Text, [Def]))]
-> ([[String]], [(Text, [Def])])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe ([String], (Text, [Def]))] -> [([String], (Text, [Def]))]
forall a. [Maybe a] -> [a]
catMaybes) (IO [Maybe ([String], (Text, [Def]))]
-> IO ([[String]], [(Text, [Def])]))
-> IO [Maybe ([String], (Text, [Def]))]
-> IO ([[String]], [(Text, [Def])])
forall a b. (a -> b) -> a -> b
$ (String -> IO (Maybe ([String], (Text, [Def]))))
-> [String] -> IO [Maybe ([String], (Text, [Def]))]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (String -> String -> IO (Maybe ([String], (Text, [Def])))
loadLang String
folder) [String]
files'
(([String] -> Q ()) -> [[String]] -> Q ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_(([String] -> Q ()) -> [[String]] -> Q ())
-> ((String -> Q ()) -> [String] -> Q ())
-> (String -> Q ())
-> [[String]]
-> Q ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(String -> Q ()) -> [String] -> Q ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_) String -> Q ()
addDependentFile [[String]]
filess
let contents' :: [(Text, [Def])]
contents' = Map Text [Def] -> [(Text, [Def])]
forall k a. Map k a -> [(k, a)]
Map.toList (Map Text [Def] -> [(Text, [Def])])
-> Map Text [Def] -> [(Text, [Def])]
forall a b. (a -> b) -> a -> b
$ ([Def] -> [Def] -> [Def]) -> [(Text, [Def])] -> Map Text [Def]
forall k a. Ord k => (a -> a -> a) -> [(k, a)] -> Map k a
Map.fromListWith [Def] -> [Def] -> [Def]
forall a. [a] -> [a] -> [a]
(++) [(Text, [Def])]
contents
[SDef]
sdef <-
case Text -> [(Text, [Def])] -> Maybe [Def]
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Text
lang [(Text, [Def])]
contents' of
Maybe [Def]
Nothing -> String -> Q [SDef]
forall a. HasCallStack => String -> a
error (String -> Q [SDef]) -> String -> Q [SDef]
forall a b. (a -> b) -> a -> b
$ String
"Did not find main language file: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Text -> String
unpack Text
lang
Just [Def]
def -> [Def] -> Q [SDef]
toSDefs [Def]
def
([Def] -> Q ()) -> [[Def]] -> Q ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ ([SDef] -> [Def] -> Q ()
checkDef [SDef]
sdef) ([[Def]] -> Q ()) -> [[Def]] -> Q ()
forall a b. (a -> b) -> a -> b
$ ((Text, [Def]) -> [Def]) -> [(Text, [Def])] -> [[Def]]
forall a b. (a -> b) -> [a] -> [b]
map (Text, [Def]) -> [Def]
forall a b. (a, b) -> b
snd [(Text, [Def])]
contents'
let mname :: Name
mname = String -> Name
mkName (String -> Name) -> String -> Name
forall a b. (a -> b) -> a -> b
$ String
dt String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
postfix
[Clause]
c1 <- ([[Clause]] -> [Clause]) -> Q [[Clause]] -> Q [Clause]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [[Clause]] -> [Clause]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat (Q [[Clause]] -> Q [Clause]) -> Q [[Clause]] -> Q [Clause]
forall a b. (a -> b) -> a -> b
$ ((Text, [Def]) -> Q [Clause]) -> [(Text, [Def])] -> Q [[Clause]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (String -> String -> (Text, [Def]) -> Q [Clause]
toClauses String
prefix String
dt) [(Text, [Def])]
contents'
[Clause]
c2 <- (SDef -> Q Clause) -> [SDef] -> Q [Clause]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (String -> String -> SDef -> Q Clause
sToClause String
prefix String
dt) [SDef]
sdef
Clause
c3 <- Q Clause
defClause
[Dec] -> Q [Dec]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Dec] -> Q [Dec]) -> [Dec] -> Q [Dec]
forall a b. (a -> b) -> a -> b
$
( if Bool
genType
then ((Cxt
-> Name
-> [TyVarBndr]
-> Maybe Kind
-> [Con]
-> [DerivClause]
-> Dec
DataD [] Name
mname [] Maybe Kind
forall a. Maybe a
Nothing ((SDef -> Con) -> [SDef] -> [Con]
forall a b. (a -> b) -> [a] -> [b]
map (String -> SDef -> Con
toCon String
dt) [SDef]
sdef) []) Dec -> [Dec] -> [Dec]
forall a. a -> [a] -> [a]
:)
else [Dec] -> [Dec]
forall a. a -> a
id)
[ Cxt -> Kind -> [Dec] -> Dec
instanceD
[]
(Name -> Kind
ConT ''RenderMessage Kind -> Kind -> Kind
`AppT` (Name -> Kind
ConT (Name -> Kind) -> Name -> Kind
forall a b. (a -> b) -> a -> b
$ String -> Name
mkName String
master) Kind -> Kind -> Kind
`AppT` Name -> Kind
ConT Name
mname)
[ Name -> [Clause] -> Dec
FunD (String -> Name
mkName String
"renderMessage") ([Clause] -> Dec) -> [Clause] -> Dec
forall a b. (a -> b) -> a -> b
$ [Clause]
c1 [Clause] -> [Clause] -> [Clause]
forall a. [a] -> [a] -> [a]
++ [Clause]
c2 [Clause] -> [Clause] -> [Clause]
forall a. [a] -> [a] -> [a]
++ [Clause
c3]
]
]
toClauses :: String -> String -> (Lang, [Def]) -> Q [Clause]
toClauses :: String -> String -> (Text, [Def]) -> Q [Clause]
toClauses String
prefix String
dt (Text
lang, [Def]
defs) =
(Def -> Q Clause) -> [Def] -> Q [Clause]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Def -> Q Clause
go [Def]
defs
where
go :: Def -> Q Clause
go Def
def = do
Name
a <- String -> Q Name
newName String
"lang"
(Pat
pat, Exp
bod) <- String -> String -> [String] -> [Content] -> Q (Pat, Exp)
mkBody String
dt (String
prefix String -> String -> String
forall a. [a] -> [a] -> [a]
++ Def -> String
constr Def
def) (((String, Maybe String) -> String)
-> [(String, Maybe String)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String, Maybe String) -> String
forall a b. (a, b) -> a
fst ([(String, Maybe String)] -> [String])
-> [(String, Maybe String)] -> [String]
forall a b. (a -> b) -> a -> b
$ Def -> [(String, Maybe String)]
vars Def
def) (Def -> [Content]
content Def
def)
Guard
guard <- (Exp -> Guard) -> Q Exp -> Q Guard
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Exp -> Guard
NormalG [|$(return $ VarE a) == pack $(lift $ unpack lang)|]
Clause -> Q Clause
forall (m :: * -> *) a. Monad m => a -> m a
return (Clause -> Q Clause) -> Clause -> Q Clause
forall a b. (a -> b) -> a -> b
$ [Pat] -> Body -> [Dec] -> Clause
Clause
[Pat
WildP, Name -> [Pat] -> Pat
conP (String -> Name
mkName String
":") [Name -> Pat
VarP Name
a, Pat
WildP], Pat
pat]
([(Guard, Exp)] -> Body
GuardedB [(Guard
guard, Exp
bod)])
[]
mkBody :: String
-> String
-> [String]
-> [Content]
-> Q (Pat, Exp)
mkBody :: String -> String -> [String] -> [Content] -> Q (Pat, Exp)
mkBody String
dt String
cs [String]
vs [Content]
ct = do
[(String, Name)]
vp <- (String -> Q (String, Name)) -> [String] -> Q [(String, Name)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM String -> Q (String, Name)
forall (m :: * -> *). Monad m => String -> m (String, Name)
go [String]
vs
let pat :: Pat
pat = Name -> [FieldPat] -> Pat
RecP (String -> Name
mkName String
cs) (((String, Name) -> FieldPat) -> [(String, Name)] -> [FieldPat]
forall a b. (a -> b) -> [a] -> [b]
map (String -> String -> Name
varName String
dt (String -> Name) -> (Name -> Pat) -> (String, Name) -> FieldPat
forall (a :: * -> * -> *) b c b' c'.
Arrow a =>
a b c -> a b' c' -> a (b, b') (c, c')
*** Name -> Pat
VarP) [(String, Name)]
vp)
let ct' :: [Content]
ct' = (Content -> Content) -> [Content] -> [Content]
forall a b. (a -> b) -> [a] -> [b]
map ([(String, Name)] -> Content -> Content
fixVars [(String, Name)]
vp) [Content]
ct
Exp
pack' <- [|Data.Text.pack|]
Exp
tomsg <- [|toMessage|]
let ct'' :: [Exp]
ct'' = (Content -> Exp) -> [Content] -> [Exp]
forall a b. (a -> b) -> [a] -> [b]
map (Exp -> Exp -> Content -> Exp
toH Exp
pack' Exp
tomsg) [Content]
ct'
Exp
mapp <- [|mappend|]
let app :: Exp -> Exp -> Exp
app Exp
a Exp
b = Maybe Exp -> Exp -> Maybe Exp -> Exp
InfixE (Exp -> Maybe Exp
forall a. a -> Maybe a
Just Exp
a) Exp
mapp (Exp -> Maybe Exp
forall a. a -> Maybe a
Just Exp
b)
Exp
e <-
case [Exp]
ct'' of
[] -> [|mempty|]
[Exp
x] -> Exp -> Q Exp
forall (m :: * -> *) a. Monad m => a -> m a
return Exp
x
(Exp
x:[Exp]
xs) -> Exp -> Q Exp
forall (m :: * -> *) a. Monad m => a -> m a
return (Exp -> Q Exp) -> Exp -> Q Exp
forall a b. (a -> b) -> a -> b
$ (Exp -> Exp -> Exp) -> Exp -> [Exp] -> Exp
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Exp -> Exp -> Exp
app Exp
x [Exp]
xs
(Pat, Exp) -> Q (Pat, Exp)
forall (m :: * -> *) a. Monad m => a -> m a
return (Pat
pat, Exp
e)
where
toH :: Exp -> Exp -> Content -> Exp
toH Exp
pack' Exp
_ (Raw String
s) = Exp
pack' Exp -> Exp -> Exp
`AppE` Exp -> Kind -> Exp
SigE (Lit -> Exp
LitE (String -> Lit
StringL String
s)) (Name -> Kind
ConT ''String)
toH Exp
_ Exp
tomsg (Var Deref
d) = Exp
tomsg Exp -> Exp -> Exp
`AppE` Scope -> Deref -> Exp
derefToExp [] Deref
d
go :: String -> m (String, Name)
go String
x = do
let y :: Name
y = String -> Name
mkName (String -> Name) -> String -> Name
forall a b. (a -> b) -> a -> b
$ Char
'_' Char -> String -> String
forall a. a -> [a] -> [a]
: String
x
(String, Name) -> m (String, Name)
forall (m :: * -> *) a. Monad m => a -> m a
return (String
x, Name
y)
fixVars :: [(String, Name)] -> Content -> Content
fixVars [(String, Name)]
vp (Var Deref
d) = Deref -> Content
Var (Deref -> Content) -> Deref -> Content
forall a b. (a -> b) -> a -> b
$ [(String, Name)] -> Deref -> Deref
fixDeref [(String, Name)]
vp Deref
d
fixVars [(String, Name)]
_ (Raw String
s) = String -> Content
Raw String
s
fixDeref :: [(String, Name)] -> Deref -> Deref
fixDeref [(String, Name)]
vp (DerefIdent (Ident String
i)) = Ident -> Deref
DerefIdent (Ident -> Deref) -> Ident -> Deref
forall a b. (a -> b) -> a -> b
$ String -> Ident
Ident (String -> Ident) -> String -> Ident
forall a b. (a -> b) -> a -> b
$ [(String, Name)] -> String -> String
fixIdent [(String, Name)]
vp String
i
fixDeref [(String, Name)]
vp (DerefBranch Deref
a Deref
b) = Deref -> Deref -> Deref
DerefBranch ([(String, Name)] -> Deref -> Deref
fixDeref [(String, Name)]
vp Deref
a) ([(String, Name)] -> Deref -> Deref
fixDeref [(String, Name)]
vp Deref
b)
fixDeref [(String, Name)]
_ Deref
d = Deref
d
fixIdent :: [(String, Name)] -> String -> String
fixIdent [(String, Name)]
vp String
i =
case String -> [(String, Name)] -> Maybe Name
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup String
i [(String, Name)]
vp of
Maybe Name
Nothing -> String
i
Just Name
y -> Name -> String
nameBase Name
y
sToClause :: String -> String -> SDef -> Q Clause
sToClause :: String -> String -> SDef -> Q Clause
sToClause String
prefix String
dt SDef
sdef = do
(Pat
pat, Exp
bod) <- String -> String -> [String] -> [Content] -> Q (Pat, Exp)
mkBody String
dt (String
prefix String -> String -> String
forall a. [a] -> [a] -> [a]
++ SDef -> String
sconstr SDef
sdef) (((String, String) -> String) -> [(String, String)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String, String) -> String
forall a b. (a, b) -> a
fst ([(String, String)] -> [String]) -> [(String, String)] -> [String]
forall a b. (a -> b) -> a -> b
$ SDef -> [(String, String)]
svars SDef
sdef) (SDef -> [Content]
scontent SDef
sdef)
Clause -> Q Clause
forall (m :: * -> *) a. Monad m => a -> m a
return (Clause -> Q Clause) -> Clause -> Q Clause
forall a b. (a -> b) -> a -> b
$ [Pat] -> Body -> [Dec] -> Clause
Clause
[Pat
WildP, Name -> [Pat] -> Pat
conP (String -> Name
mkName String
"[]") [], Pat
pat]
(Exp -> Body
NormalB Exp
bod)
[]
defClause :: Q Clause
defClause :: Q Clause
defClause = do
Name
a <- String -> Q Name
newName String
"sub"
Name
c <- String -> Q Name
newName String
"langs"
Name
d <- String -> Q Name
newName String
"msg"
Exp
rm <- [|renderMessage|]
Clause -> Q Clause
forall (m :: * -> *) a. Monad m => a -> m a
return (Clause -> Q Clause) -> Clause -> Q Clause
forall a b. (a -> b) -> a -> b
$ [Pat] -> Body -> [Dec] -> Clause
Clause
[Name -> Pat
VarP Name
a, Name -> [Pat] -> Pat
conP (String -> Name
mkName String
":") [Pat
WildP, Name -> Pat
VarP Name
c], Name -> Pat
VarP Name
d]
(Exp -> Body
NormalB (Exp -> Body) -> Exp -> Body
forall a b. (a -> b) -> a -> b
$ Exp
rm Exp -> Exp -> Exp
`AppE` Name -> Exp
VarE Name
a Exp -> Exp -> Exp
`AppE` Name -> Exp
VarE Name
c Exp -> Exp -> Exp
`AppE` Name -> Exp
VarE Name
d)
[]
conP :: Name -> [Pat] -> Pat
#if MIN_VERSION_template_haskell(2,18,0)
conP name = ConP name []
#else
conP :: Name -> [Pat] -> Pat
conP = Name -> [Pat] -> Pat
ConP
#endif
toCon :: String -> SDef -> Con
toCon :: String -> SDef -> Con
toCon String
dt (SDef String
c [(String, String)]
vs [Content]
_) =
Name -> [VarBangType] -> Con
RecC (String -> Name
mkName (String -> Name) -> String -> Name
forall a b. (a -> b) -> a -> b
$ String
"Msg" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
c) ([VarBangType] -> Con) -> [VarBangType] -> Con
forall a b. (a -> b) -> a -> b
$ ((String, String) -> VarBangType)
-> [(String, String)] -> [VarBangType]
forall a b. (a -> b) -> [a] -> [b]
map (String, String) -> VarBangType
go [(String, String)]
vs
where
go :: (String, String) -> VarBangType
go (String
n, String
t) = (String -> String -> Name
varName String
dt String
n, Bang
notStrict, Name -> Kind
ConT (Name -> Kind) -> Name -> Kind
forall a b. (a -> b) -> a -> b
$ String -> Name
mkName String
t)
varName :: String -> String -> Name
varName :: String -> String -> Name
varName String
a String
y =
String -> Name
mkName (String -> Name) -> String -> Name
forall a b. (a -> b) -> a -> b
$ [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String -> String
lower String
a, String
"Message", String -> String
upper String
y]
where
lower :: String -> String
lower (Char
x:String
xs) = Char -> Char
toLower Char
x Char -> String -> String
forall a. a -> [a] -> [a]
: String
xs
lower [] = []
upper :: String -> String
upper (Char
x:String
xs) = Char -> Char
toUpper Char
x Char -> String -> String
forall a. a -> [a] -> [a]
: String
xs
upper [] = []
checkDef :: [SDef] -> [Def] -> Q ()
checkDef :: [SDef] -> [Def] -> Q ()
checkDef [SDef]
x [Def]
y =
[SDef] -> [Def] -> Q ()
forall (m :: * -> *). Monad m => [SDef] -> [Def] -> m ()
go ((SDef -> SDef -> Ordering) -> [SDef] -> [SDef]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy ((SDef -> String) -> SDef -> SDef -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing SDef -> String
sconstr) [SDef]
x) ((Def -> Def -> Ordering) -> [Def] -> [Def]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy ((Def -> String) -> Def -> Def -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing Def -> String
constr) [Def]
y)
where
go :: [SDef] -> [Def] -> m ()
go [SDef]
_ [] = () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
go [] (Def
b:[Def]
_) = String -> m ()
forall a. HasCallStack => String -> a
error (String -> m ()) -> String -> m ()
forall a b. (a -> b) -> a -> b
$ String
"Extra message constructor: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Def -> String
constr Def
b
go (SDef
a:[SDef]
as) (Def
b:[Def]
bs)
| SDef -> String
sconstr SDef
a String -> String -> Bool
forall a. Ord a => a -> a -> Bool
< Def -> String
constr Def
b = [SDef] -> [Def] -> m ()
go [SDef]
as (Def
bDef -> [Def] -> [Def]
forall a. a -> [a] -> [a]
:[Def]
bs)
| SDef -> String
sconstr SDef
a String -> String -> Bool
forall a. Ord a => a -> a -> Bool
> Def -> String
constr Def
b = String -> m ()
forall a. HasCallStack => String -> a
error (String -> m ()) -> String -> m ()
forall a b. (a -> b) -> a -> b
$ String
"Extra message constructor: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Def -> String
constr Def
b
| Bool
otherwise = do
[(String, String)] -> [(String, Maybe String)] -> m ()
forall a a (m :: * -> *).
(Eq a, Eq a, Monad m) =>
[(a, a)] -> [(a, Maybe a)] -> m ()
go' (SDef -> [(String, String)]
svars SDef
a) (Def -> [(String, Maybe String)]
vars Def
b)
[SDef] -> [Def] -> m ()
go [SDef]
as [Def]
bs
go' :: [(a, a)] -> [(a, Maybe a)] -> m ()
go' ((a
an, a
at):[(a, a)]
as) ((a
bn, Maybe a
mbt):[(a, Maybe a)]
bs)
| a
an a -> a -> Bool
forall a. Eq a => a -> a -> Bool
/= a
bn = String -> m ()
forall a. HasCallStack => String -> a
error String
"Mismatched variable names"
| Bool
otherwise =
case Maybe a
mbt of
Maybe a
Nothing -> [(a, a)] -> [(a, Maybe a)] -> m ()
go' [(a, a)]
as [(a, Maybe a)]
bs
Just a
bt
| a
at a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
bt -> [(a, a)] -> [(a, Maybe a)] -> m ()
go' [(a, a)]
as [(a, Maybe a)]
bs
| Bool
otherwise -> String -> m ()
forall a. HasCallStack => String -> a
error String
"Mismatched variable types"
go' [] [] = () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
go' [(a, a)]
_ [(a, Maybe a)]
_ = String -> m ()
forall a. HasCallStack => String -> a
error String
"Mistmached variable count"
toSDefs :: [Def] -> Q [SDef]
toSDefs :: [Def] -> Q [SDef]
toSDefs = (Def -> Q SDef) -> [Def] -> Q [SDef]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Def -> Q SDef
toSDef
toSDef :: Def -> Q SDef
toSDef :: Def -> Q SDef
toSDef Def
d = do
[(String, String)]
vars' <- ((String, Maybe String) -> Q (String, String))
-> [(String, Maybe String)] -> Q [(String, String)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (String, Maybe String) -> Q (String, String)
go ([(String, Maybe String)] -> Q [(String, String)])
-> [(String, Maybe String)] -> Q [(String, String)]
forall a b. (a -> b) -> a -> b
$ Def -> [(String, Maybe String)]
vars Def
d
SDef -> Q SDef
forall (m :: * -> *) a. Monad m => a -> m a
return (SDef -> Q SDef) -> SDef -> Q SDef
forall a b. (a -> b) -> a -> b
$ String -> [(String, String)] -> [Content] -> SDef
SDef (Def -> String
constr Def
d) [(String, String)]
vars' (Def -> [Content]
content Def
d)
where
go :: (String, Maybe String) -> Q (String, String)
go (String
a, Just String
b) = (String, String) -> Q (String, String)
forall (m :: * -> *) a. Monad m => a -> m a
return (String
a, String
b)
go (String
a, Maybe String
Nothing) = String -> Q (String, String)
forall a. HasCallStack => String -> a
error (String -> Q (String, String)) -> String -> Q (String, String)
forall a b. (a -> b) -> a -> b
$ String
"Main language missing type for " String -> String -> String
forall a. [a] -> [a] -> [a]
++ (String, String) -> String
forall a. Show a => a -> String
show (Def -> String
constr Def
d, String
a)
data SDef = SDef
{ SDef -> String
sconstr :: String
, SDef -> [(String, String)]
svars :: [(String, String)]
, SDef -> [Content]
scontent :: [Content]
}
data Def = Def
{ Def -> String
constr :: String
, Def -> [(String, Maybe String)]
vars :: [(String, Maybe String)]
, Def -> [Content]
content :: [Content]
}
(</>) :: FilePath -> FilePath -> FilePath
String
path </> :: String -> String -> String
</> String
file = String
path String -> String -> String
forall a. [a] -> [a] -> [a]
++ Char
'/' Char -> String -> String
forall a. a -> [a] -> [a]
: String
file
loadLang :: FilePath -> FilePath -> IO (Maybe ([FilePath], (Lang, [Def])))
loadLang :: String -> String -> IO (Maybe ([String], (Text, [Def])))
loadLang String
folder String
file = do
let file' :: String
file' = String
folder String -> String -> String
</> String
file
Bool
isFile <- String -> IO Bool
doesFileExist String
file'
if Bool
isFile Bool -> Bool -> Bool
&& String
".msg" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isSuffixOf` String
file
then do
let lang :: Text
lang = String -> Text
pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String -> String
forall a. [a] -> [a]
reverse (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ Int -> String -> String
forall a. Int -> [a] -> [a]
drop Int
4 (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String -> String
forall a. [a] -> [a]
reverse String
file
[Def]
defs <- String -> IO [Def]
loadLangFile String
file'
Maybe ([String], (Text, [Def]))
-> IO (Maybe ([String], (Text, [Def])))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe ([String], (Text, [Def]))
-> IO (Maybe ([String], (Text, [Def]))))
-> Maybe ([String], (Text, [Def]))
-> IO (Maybe ([String], (Text, [Def])))
forall a b. (a -> b) -> a -> b
$ ([String], (Text, [Def])) -> Maybe ([String], (Text, [Def]))
forall a. a -> Maybe a
Just ([String
file'], (Text
lang, [Def]
defs))
else do
Bool
isDir <- String -> IO Bool
doesDirectoryExist String
file'
if Bool
isDir
then do
let lang :: Text
lang = String -> Text
pack String
file
([String]
files, [[Def]]
defs) <- [(String, [Def])] -> ([String], [[Def]])
forall a b. [(a, b)] -> ([a], [b])
unzip ([(String, [Def])] -> ([String], [[Def]]))
-> IO [(String, [Def])] -> IO ([String], [[Def]])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO [(String, [Def])]
loadLangDir String
file'
Maybe ([String], (Text, [Def]))
-> IO (Maybe ([String], (Text, [Def])))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe ([String], (Text, [Def]))
-> IO (Maybe ([String], (Text, [Def]))))
-> Maybe ([String], (Text, [Def]))
-> IO (Maybe ([String], (Text, [Def])))
forall a b. (a -> b) -> a -> b
$ ([String], (Text, [Def])) -> Maybe ([String], (Text, [Def]))
forall a. a -> Maybe a
Just ([String]
files, (Text
lang, [[Def]] -> [Def]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Def]]
defs))
else
Maybe ([String], (Text, [Def]))
-> IO (Maybe ([String], (Text, [Def])))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe ([String], (Text, [Def]))
forall a. Maybe a
Nothing
loadLangDir :: FilePath -> IO [(FilePath, [Def])]
loadLangDir :: String -> IO [(String, [Def])]
loadLangDir String
folder = do
[String]
paths <- (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String
folder String -> String -> String
</>) ([String] -> [String])
-> ([String] -> [String]) -> [String] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [String
".", String
".."]) ([String] -> [String]) -> IO [String] -> IO [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO [String]
getDirectoryContents String
folder
[String]
files <- (String -> IO Bool) -> [String] -> IO [String]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM String -> IO Bool
doesFileExist [String]
paths
[String]
dirs <- (String -> IO Bool) -> [String] -> IO [String]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM String -> IO Bool
doesDirectoryExist [String]
paths
[Maybe (String, [Def])]
langFiles <-
[String]
-> (String -> IO (Maybe (String, [Def])))
-> IO [Maybe (String, [Def])]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [String]
files ((String -> IO (Maybe (String, [Def])))
-> IO [Maybe (String, [Def])])
-> (String -> IO (Maybe (String, [Def])))
-> IO [Maybe (String, [Def])]
forall a b. (a -> b) -> a -> b
$ \String
file -> do
if String
".msg" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isSuffixOf` String
file
then do
[Def]
defs <- String -> IO [Def]
loadLangFile String
file
Maybe (String, [Def]) -> IO (Maybe (String, [Def]))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (String, [Def]) -> IO (Maybe (String, [Def])))
-> Maybe (String, [Def]) -> IO (Maybe (String, [Def]))
forall a b. (a -> b) -> a -> b
$ (String, [Def]) -> Maybe (String, [Def])
forall a. a -> Maybe a
Just (String
file, [Def]
defs)
else do
Maybe (String, [Def]) -> IO (Maybe (String, [Def]))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (String, [Def])
forall a. Maybe a
Nothing
[[(String, [Def])]]
langDirs <- (String -> IO [(String, [Def])])
-> [String] -> IO [[(String, [Def])]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM String -> IO [(String, [Def])]
loadLangDir [String]
dirs
[(String, [Def])] -> IO [(String, [Def])]
forall (m :: * -> *) a. Monad m => a -> m a
return ([(String, [Def])] -> IO [(String, [Def])])
-> [(String, [Def])] -> IO [(String, [Def])]
forall a b. (a -> b) -> a -> b
$ [Maybe (String, [Def])] -> [(String, [Def])]
forall a. [Maybe a] -> [a]
catMaybes [Maybe (String, [Def])]
langFiles [(String, [Def])] -> [(String, [Def])] -> [(String, [Def])]
forall a. [a] -> [a] -> [a]
++ [[(String, [Def])]] -> [(String, [Def])]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[(String, [Def])]]
langDirs
loadLangFile :: FilePath -> IO [Def]
loadLangFile :: String -> IO [Def]
loadLangFile String
file = do
ByteString
bs <- String -> IO ByteString
S.readFile String
file
let s :: String
s = Text -> String
unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ ByteString -> Text
decodeUtf8 ByteString
bs
[Def]
defs <- ([Maybe Def] -> [Def]) -> IO [Maybe Def] -> IO [Def]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Maybe Def] -> [Def]
forall a. [Maybe a] -> [a]
catMaybes (IO [Maybe Def] -> IO [Def]) -> IO [Maybe Def] -> IO [Def]
forall a b. (a -> b) -> a -> b
$ (String -> IO (Maybe Def)) -> [String] -> IO [Maybe Def]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (String -> IO (Maybe Def)
parseDef (String -> IO (Maybe Def))
-> (String -> String) -> String -> IO (Maybe Def)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
T.unpack (Text -> String) -> (String -> Text) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
T.strip (Text -> Text) -> (String -> Text) -> String -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack) ([String] -> IO [Maybe Def]) -> [String] -> IO [Maybe Def]
forall a b. (a -> b) -> a -> b
$ String -> [String]
lines String
s
[Def] -> IO [Def]
forall (m :: * -> *) a. Monad m => a -> m a
return [Def]
defs
parseDef :: String -> IO (Maybe Def)
parseDef :: String -> IO (Maybe Def)
parseDef String
"" = Maybe Def -> IO (Maybe Def)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Def
forall a. Maybe a
Nothing
parseDef (Char
'#':String
_) = Maybe Def -> IO (Maybe Def)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Def
forall a. Maybe a
Nothing
parseDef String
s =
case String
end of
Char
':':String
end' -> do
[Content]
content' <- ([Content] -> [Content]) -> IO [Content] -> IO [Content]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Content] -> [Content]
compress (IO [Content] -> IO [Content]) -> IO [Content] -> IO [Content]
forall a b. (a -> b) -> a -> b
$ String -> IO [Content]
parseContent (String -> IO [Content]) -> String -> IO [Content]
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
isSpace String
end'
case String -> [String]
words String
begin of
[] -> String -> IO (Maybe Def)
forall a. HasCallStack => String -> a
error (String -> IO (Maybe Def)) -> String -> IO (Maybe Def)
forall a b. (a -> b) -> a -> b
$ String
"Missing constructor: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s
(String
w:[String]
ws) -> Maybe Def -> IO (Maybe Def)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Def -> IO (Maybe Def)) -> Maybe Def -> IO (Maybe Def)
forall a b. (a -> b) -> a -> b
$ Def -> Maybe Def
forall a. a -> Maybe a
Just Def :: String -> [(String, Maybe String)] -> [Content] -> Def
Def
{ constr :: String
constr = String
w
, vars :: [(String, Maybe String)]
vars = (String -> (String, Maybe String))
-> [String] -> [(String, Maybe String)]
forall a b. (a -> b) -> [a] -> [b]
map String -> (String, Maybe String)
parseVar [String]
ws
, content :: [Content]
content = [Content]
content'
}
String
_ -> String -> IO (Maybe Def)
forall a. HasCallStack => String -> a
error (String -> IO (Maybe Def)) -> String -> IO (Maybe Def)
forall a b. (a -> b) -> a -> b
$ String
"Missing colon: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s
where
(String
begin, String
end) = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
break (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
':') String
s
data Content = Var Deref | Raw String
compress :: [Content] -> [Content]
compress :: [Content] -> [Content]
compress [] = []
compress (Raw String
a:Raw String
b:[Content]
rest) = [Content] -> [Content]
compress ([Content] -> [Content]) -> [Content] -> [Content]
forall a b. (a -> b) -> a -> b
$ String -> Content
Raw (String
a String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
b) Content -> [Content] -> [Content]
forall a. a -> [a] -> [a]
: [Content]
rest
compress (Content
x:[Content]
y) = Content
x Content -> [Content] -> [Content]
forall a. a -> [a] -> [a]
: [Content] -> [Content]
compress [Content]
y
parseContent :: String -> IO [Content]
parseContent :: String -> IO [Content]
parseContent String
s =
(ParseError -> IO [Content])
-> ([Content] -> IO [Content])
-> Either ParseError [Content]
-> IO [Content]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (String -> IO [Content]
forall a. HasCallStack => String -> a
error (String -> IO [Content])
-> (ParseError -> String) -> ParseError -> IO [Content]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParseError -> String
forall a. Show a => a -> String
show) [Content] -> IO [Content]
forall (m :: * -> *) a. Monad m => a -> m a
return (Either ParseError [Content] -> IO [Content])
-> Either ParseError [Content] -> IO [Content]
forall a b. (a -> b) -> a -> b
$ Parsec String () [Content]
-> String -> String -> Either ParseError [Content]
forall s t a.
Stream s Identity t =>
Parsec s () a -> String -> s -> Either ParseError a
parse Parsec String () [Content]
forall u. ParsecT String u Identity [Content]
go String
s String
s
where
go :: ParsecT String u Identity [Content]
go = do
[Content]
x <- ParsecT String u Identity Content
-> ParsecT String u Identity [Content]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many ParsecT String u Identity Content
forall u. ParsecT String u Identity Content
go'
ParsecT String u Identity ()
forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
eof
[Content] -> ParsecT String u Identity [Content]
forall (m :: * -> *) a. Monad m => a -> m a
return [Content]
x
go' :: ParsecT String u Identity Content
go' = (String -> Content
Raw (String -> Content)
-> ParsecT String u Identity String
-> ParsecT String u Identity Content
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` ParsecT String u Identity Char -> ParsecT String u Identity String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 (String -> ParsecT String u Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf String
"#")) ParsecT String u Identity Content
-> ParsecT String u Identity Content
-> ParsecT String u Identity Content
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ((Either String Deref -> Content)
-> ParsecT String u Identity (Either String Deref)
-> ParsecT String u Identity Content
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((String -> Content)
-> (Deref -> Content) -> Either String Deref -> Content
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> Content
Raw Deref -> Content
Var) ParsecT String u Identity (Either String Deref)
forall a. UserParser a (Either String Deref)
parseHash)
parseVar :: String -> (String, Maybe String)
parseVar :: String -> (String, Maybe String)
parseVar String
s =
case (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
break (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'@') String
s of
(String
x, Char
'@':String
y) -> (String
x, String -> Maybe String
forall a. a -> Maybe a
Just String
y)
(String, String)
_ -> (String
s, Maybe String
forall a. Maybe a
Nothing)
data SomeMessage master = forall msg. RenderMessage master msg => SomeMessage msg
instance IsString (SomeMessage master) where
fromString :: String -> SomeMessage master
fromString = Text -> SomeMessage master
forall master msg.
RenderMessage master msg =>
msg -> SomeMessage master
SomeMessage (Text -> SomeMessage master)
-> (String -> Text) -> String -> SomeMessage master
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack
instance master ~ master' => RenderMessage master (SomeMessage master') where
renderMessage :: master -> [Text] -> SomeMessage master' -> Text
renderMessage master
a [Text]
b (SomeMessage msg
msg) = master -> [Text] -> msg -> Text
forall master message.
RenderMessage master message =>
master -> [Text] -> message -> Text
renderMessage master
a [Text]
b msg
msg
notStrict :: Bang
notStrict :: Bang
notStrict = SourceUnpackedness -> SourceStrictness -> Bang
Bang SourceUnpackedness
NoSourceUnpackedness SourceStrictness
NoSourceStrictness
instanceD :: Cxt -> Type -> [Dec] -> Dec
instanceD :: Cxt -> Kind -> [Dec] -> Dec
instanceD = Maybe Overlap -> Cxt -> Kind -> [Dec] -> Dec
InstanceD Maybe Overlap
forall a. Maybe a
Nothing