{-# LANGUAGE TemplateHaskell #-} -- | QuasiQuoter for interpolated strings using Ruby syntax. Expressions inside #{} will have -- 'show' called. Multi-line strings are supported. Escaping of '#' and '{' is done with backslash. -- -- @ -- v :: String -- v = [$istr| well \#{\"hello\" ++ \" there\"} \#{6*7}] -- @ -- -- v will have the value \" well hello there 42\" module Text.InterpolatedString.QQ (istr) where import qualified Language.Haskell.TH as TH import Language.Haskell.TH.Quote import Language.Haskell.Meta.Parse data StringPart = Literal String | AntiQuote String deriving Show parseHaskell a [] = [Literal (reverse a)] parseHaskell a ('\\':x:xs) = parseHaskell (x:a) xs parseHaskell a ('\\':[]) = parseHaskell ('\\':a) [] parseHaskell a ('}':xs) = AntiQuote (reverse a) : parseStr [] xs parseHaskell a (x:xs) = parseHaskell (x:a) xs parseStr a [] = [Literal (reverse a)] parseStr a ('\\':x:xs) = parseStr (x:a) xs parseStr a ('\\':[]) = parseStr ('\\':a) [] parseStr a ('#':'{':xs) = Literal (reverse a) : parseHaskell [] xs parseStr a (x:xs) = parseStr (x:a) xs makeExpr [] = [| "" |] makeExpr ((Literal a):xs) = TH.appE [| (++) a |] (makeExpr xs) makeExpr ((AntiQuote a):xs) = TH.appE [| (++) (trimQuotes (show $(reifyStringToHaskell a))) |] (makeExpr xs) trimQuotes s = reverse $ dropWhile (== '"') $ reverse $ dropWhile (== '"') s reifyStringToHaskell s = case parseExp s of Left s -> TH.report True s >> [| "" |] Right e -> return e rstrExp s = makeExpr $ parseStr [] $ filter (/= '\r') s -- | QuasiQuoter for interpolating Haskell values into a string literal. The pattern portion is undefined. istr :: QuasiQuoter istr = QuasiQuoter rstrExp undefined