interpolatedstring-qq (empty) → 0.1
raw patch · 5 files changed
+136/−0 lines, 5 filesdep +basedep +haskell-src-metadep +template-haskellbuild-type:Customsetup-changed
Dependencies added: base, haskell-src-meta, template-haskell
Files
- LICENSE +26/−0
- Setup.hs +6/−0
- interpolatedstring-qq.cabal +21/−0
- src/Text/InterpolatedString/QQ.hs +48/−0
- tests/Test.hs +35/−0
+ LICENSE view
@@ -0,0 +1,26 @@+Copyright (c) Erik Charlebois. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The names of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,6 @@+import Distribution.Simple +import System.Cmd(system) + +main = defaultMainWithHooks $ simpleUserHooks { runTests = runElfTests } + +runElfTests a b pd lb = system "runhaskell -i./src ./tests/Test.hs" >> return ()
+ interpolatedstring-qq.cabal view
@@ -0,0 +1,21 @@+Name: interpolatedstring-qq +Version: 0.1 +License: BSD3 +License-file: LICENSE +Category: Data +Author: Erik Charlebois +Copyright: Erik Charlebois +Maintainer: Erik Charlebois <erikcharlebois@gmail.com> +Stability: unstable +Cabal-Version: >= 1.2 +Build-Depends: base +Build-Type: Custom +Synopsis: QuasiQuoter for Ruby-style multi-line interpolated strings. +Description: QuasiQuoter for Ruby-style multi-line interpolated strings. +Data-Files: tests/Test.hs + +library + extensions: TemplateHaskell + build-depends: base, template-haskell, haskell-src-meta + hs-source-dirs: src + exposed-modules: Text.InterpolatedString.QQ
+ src/Text/InterpolatedString/QQ.hs view
@@ -0,0 +1,48 @@+{-# 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 +
+ tests/Test.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE QuasiQuotes #-}++module Main where++import Text.InterpolatedString.QQ+import Test.HUnit++data Foo = Foo Int String deriving Show++t1 = "value"++testEmpty = assertBool "" ([$istr||] == "")+testNumLiteral = assertBool "" ([$istr|#{3}|] == "3")+testString = assertBool "" ([$istr|a string #{t1} is here|] == "a string value is here")+testEscape = assertBool "" ([$istr|#\{}|] == "#{}" && [$istr|\#{}|] == "#{}")+testComplex = assertBool "" ([$istr|+ ok+#{Foo 4 "Great!" : [Foo 3 "Scott!"]}+ then+|] == ("\n" +++ " ok\n" +++ "[Foo 4 \"Great!\",Foo 3 \"Scott!\"]\n" +++ " then\n"))+++tests = TestList+ [ TestLabel "Empty String" $ TestCase testEmpty+ , TestLabel "Number Literal" $ TestCase testNumLiteral+ , TestLabel "String Variable" $ TestCase testString+ , TestLabel "Escape Sequences" $ TestCase testEscape+ , TestLabel "Complex Expression" $ TestCase testComplex+ ]++main = runTestTT tests+