{-# LANGUAGE TemplateHaskell, TypeSynonymInstances, FlexibleInstances,
UndecidableInstances, OverlappingInstances, MultiParamTypeClasses,
IncoherentInstances
#-}
module Text.InterpolatedString.Perl6 (qq, qc, q, ShowQ(..)) where
import qualified Language.Haskell.TH as TH
import Language.Haskell.TH.Quote
import Language.Haskell.Meta.Parse
import GHC.Exts (IsString(..))
import Data.Monoid (Monoid(..))
import Data.ByteString.Char8 as Strict (ByteString, unpack)
import Data.ByteString.Lazy.Char8 as Lazy (ByteString, unpack)
import Data.Text as T (Text, unpack)
import Data.Text.Lazy as LazyT(Text, unpack)
import Data.Char (isAlpha, isAlphaNum)
class ShowQ a where
showQ :: a -> String
instance ShowQ Char where
showQ :: Char -> String
showQ = (Char -> String -> String
forall a. a -> [a] -> [a]
:[])
instance ShowQ String where
showQ :: String -> String
showQ = String -> String
forall a. a -> a
id
instance ShowQ Strict.ByteString where
showQ :: ByteString -> String
showQ = ByteString -> String
Strict.unpack
instance ShowQ Lazy.ByteString where
showQ :: ByteString -> String
showQ = ByteString -> String
Lazy.unpack
instance ShowQ T.Text where
showQ :: Text -> String
showQ = Text -> String
T.unpack
instance ShowQ LazyT.Text where
showQ :: Text -> String
showQ = Text -> String
LazyT.unpack
instance Show a => ShowQ a where
showQ :: a -> String
showQ = a -> String
forall a. Show a => a -> String
show
class QQ a string where
toQQ :: a -> string
instance IsString s => QQ s s where
toQQ :: s -> s
toQQ = s -> s
forall a. a -> a
id
instance (ShowQ a, IsString s) => QQ a s where
toQQ :: a -> s
toQQ = String -> s
forall a. IsString a => String -> a
fromString (String -> s) -> (a -> String) -> a -> s
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. ShowQ a => a -> String
showQ
data StringPart = Literal String | AntiQuote String deriving Int -> StringPart -> String -> String
[StringPart] -> String -> String
StringPart -> String
(Int -> StringPart -> String -> String)
-> (StringPart -> String)
-> ([StringPart] -> String -> String)
-> Show StringPart
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [StringPart] -> String -> String
$cshowList :: [StringPart] -> String -> String
show :: StringPart -> String
$cshow :: StringPart -> String
showsPrec :: Int -> StringPart -> String -> String
$cshowsPrec :: Int -> StringPart -> String -> String
Show
unQC :: String -> String -> [StringPart]
unQC String
a [] = [String -> StringPart
Literal (String -> String
forall a. [a] -> [a]
reverse String
a)]
unQC String
a (Char
'\\':Char
x:String
xs) = String -> String -> [StringPart]
unQC (Char
xChar -> String -> String
forall a. a -> [a] -> [a]
:String
a) String
xs
unQC String
a (Char
'\\':[]) = String -> String -> [StringPart]
unQC (Char
'\\'Char -> String -> String
forall a. a -> [a] -> [a]
:String
a) []
unQC String
a (Char
'}':String
xs) = String -> StringPart
AntiQuote (String -> String
forall a. [a] -> [a]
reverse String
a) StringPart -> [StringPart] -> [StringPart]
forall a. a -> [a] -> [a]
: String -> String -> [StringPart]
parseQC [] String
xs
unQC String
a (Char
x:String
xs) = String -> String -> [StringPart]
unQC (Char
xChar -> String -> String
forall a. a -> [a] -> [a]
:String
a) String
xs
parseQC :: String -> String -> [StringPart]
parseQC String
a [] = [String -> StringPart
Literal (String -> String
forall a. [a] -> [a]
reverse String
a)]
parseQC String
a (Char
'\\':Char
'\\':String
xs) = String -> String -> [StringPart]
parseQC (Char
'\\'Char -> String -> String
forall a. a -> [a] -> [a]
:String
a) String
xs
parseQC String
a (Char
'\\':Char
'{':String
xs) = String -> String -> [StringPart]
parseQC (Char
'{'Char -> String -> String
forall a. a -> [a] -> [a]
:String
a) String
xs
parseQC String
a (Char
'\\':[]) = String -> String -> [StringPart]
parseQC (Char
'\\'Char -> String -> String
forall a. a -> [a] -> [a]
:String
a) []
parseQC String
a (Char
'{':String
xs) = String -> StringPart
Literal (String -> String
forall a. [a] -> [a]
reverse String
a) StringPart -> [StringPart] -> [StringPart]
forall a. a -> [a] -> [a]
: String -> String -> [StringPart]
unQC [] String
xs
parseQC String
a (Char
x:String
xs) = String -> String -> [StringPart]
parseQC (Char
xChar -> String -> String
forall a. a -> [a] -> [a]
:String
a) String
xs
unQQ :: String -> String -> [StringPart]
unQQ String
a [] = [String -> StringPart
Literal (String -> String
forall a. [a] -> [a]
reverse String
a)]
unQQ String
a (Char
'\\':Char
x:String
xs) = String -> String -> [StringPart]
unQQ (Char
xChar -> String -> String
forall a. a -> [a] -> [a]
:String
a) String
xs
unQQ String
a (Char
'\\':[]) = String -> String -> [StringPart]
unQQ (Char
'\\'Char -> String -> String
forall a. a -> [a] -> [a]
:String
a) []
unQQ String
a (Char
'}':String
xs) = String -> StringPart
AntiQuote (String -> String
forall a. [a] -> [a]
reverse String
a) StringPart -> [StringPart] -> [StringPart]
forall a. a -> [a] -> [a]
: String -> String -> [StringPart]
parseQQ [] String
xs
unQQ String
a (Char
x:String
xs) = String -> String -> [StringPart]
unQQ (Char
xChar -> String -> String
forall a. a -> [a] -> [a]
:String
a) String
xs
parseQQ :: String -> String -> [StringPart]
parseQQ String
a [] = [String -> StringPart
Literal (String -> String
forall a. [a] -> [a]
reverse String
a)]
parseQQ String
a (Char
'\\':Char
x:String
xs) = String -> String -> [StringPart]
parseQQ (Char
xChar -> String -> String
forall a. a -> [a] -> [a]
:String
a) String
xs
parseQQ String
a (Char
'\\':[]) = String -> String -> [StringPart]
parseQQ (Char
'\\'Char -> String -> String
forall a. a -> [a] -> [a]
:String
a) []
parseQQ String
a (Char
'$':Char
x:String
xs) | Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'_' Bool -> Bool -> Bool
|| Char -> Bool
isAlpha Char
x =
String -> StringPart
Literal (String -> String
forall a. [a] -> [a]
reverse String
a) StringPart -> [StringPart] -> [StringPart]
forall a. a -> [a] -> [a]
: String -> StringPart
AntiQuote (Char
xChar -> String -> String
forall a. a -> [a] -> [a]
:String
pre) StringPart -> [StringPart] -> [StringPart]
forall a. a -> [a] -> [a]
: String -> String -> [StringPart]
parseQQ [] String
post
where
(String
pre, String
post) = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
span Char -> Bool
isIdent String
xs
parseQQ String
a (Char
'{':String
xs) = String -> StringPart
Literal (String -> String
forall a. [a] -> [a]
reverse String
a) StringPart -> [StringPart] -> [StringPart]
forall a. a -> [a] -> [a]
: String -> String -> [StringPart]
unQQ [] String
xs
parseQQ String
a (Char
x:String
xs) = String -> String -> [StringPart]
parseQQ (Char
xChar -> String -> String
forall a. a -> [a] -> [a]
:String
a) String
xs
isIdent :: Char -> Bool
isIdent Char
'_' = Bool
True
isIdent Char
'\'' = Bool
True
isIdent Char
x = Char -> Bool
isAlphaNum Char
x
makeExpr :: [StringPart] -> ExpQ
makeExpr [] = [| mempty |]
makeExpr ((Literal String
a):[StringPart]
xs) = ExpQ -> ExpQ -> ExpQ
TH.appE [| mappend (fromString a) |]
(ExpQ -> ExpQ) -> ExpQ -> ExpQ
forall a b. (a -> b) -> a -> b
$ [StringPart] -> ExpQ
makeExpr [StringPart]
xs
makeExpr ((AntiQuote String
a):[StringPart]
xs) = ExpQ -> ExpQ -> ExpQ
TH.appE [| mappend (toQQ $(reify a)) |]
(ExpQ -> ExpQ) -> ExpQ -> ExpQ
forall a b. (a -> b) -> a -> b
$ [StringPart] -> ExpQ
makeExpr [StringPart]
xs
reify :: String -> ExpQ
reify String
s =
case String -> Either String Exp
parseExp String
s of
Left String
s -> Bool -> String -> Q ()
TH.report Bool
True String
s Q () -> ExpQ -> ExpQ
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> [| mempty |]
Right Exp
e -> Exp -> ExpQ
forall (m :: * -> *) a. Monad m => a -> m a
return Exp
e
qq :: QuasiQuoter
qq :: QuasiQuoter
qq = (String -> ExpQ)
-> (String -> Q Pat)
-> (String -> Q Type)
-> (String -> Q [Dec])
-> QuasiQuoter
QuasiQuoter ([StringPart] -> ExpQ
makeExpr ([StringPart] -> ExpQ)
-> (String -> [StringPart]) -> String -> ExpQ
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> [StringPart]
parseQQ [] (String -> [StringPart])
-> (String -> String) -> String -> [StringPart]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
filter (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'\r'))
(String -> String -> Q Pat
forall a. HasCallStack => String -> a
error String
"Cannot use qq as a pattern")
(String -> String -> Q Type
forall a. HasCallStack => String -> a
error String
"Cannot use qq as a type")
(String -> String -> Q [Dec]
forall a. HasCallStack => String -> a
error String
"Cannot use qq as a dec")
qc :: QuasiQuoter
qc :: QuasiQuoter
qc = (String -> ExpQ)
-> (String -> Q Pat)
-> (String -> Q Type)
-> (String -> Q [Dec])
-> QuasiQuoter
QuasiQuoter ([StringPart] -> ExpQ
makeExpr ([StringPart] -> ExpQ)
-> (String -> [StringPart]) -> String -> ExpQ
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> [StringPart]
parseQC [] (String -> [StringPart])
-> (String -> String) -> String -> [StringPart]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
filter (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'\r'))
(String -> String -> Q Pat
forall a. HasCallStack => String -> a
error String
"Cannot use qc as a pattern")
(String -> String -> Q Type
forall a. HasCallStack => String -> a
error String
"Cannot use qc as a type")
(String -> String -> Q [Dec]
forall a. HasCallStack => String -> a
error String
"Cannot use qc as a dec")
q :: QuasiQuoter
q :: QuasiQuoter
q = (String -> ExpQ)
-> (String -> Q Pat)
-> (String -> Q Type)
-> (String -> Q [Dec])
-> QuasiQuoter
QuasiQuoter ((\String
a -> [|fromString a|]) (String -> ExpQ) -> (String -> String) -> String -> ExpQ
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
filter (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'\r'))
(String -> String -> Q Pat
forall a. HasCallStack => String -> a
error String
"Cannot use q as a pattern")
(String -> String -> Q Type
forall a. HasCallStack => String -> a
error String
"Cannot use q as a type")
(String -> String -> Q [Dec]
forall a. HasCallStack => String -> a
error String
"Cannot use q as a dec")