interpolatedstring-perl6 (empty) → 0.1
raw patch · 5 files changed
+178/−0 lines, 5 filesdep +basedep +haskell-src-metadep +template-haskellbuild-type:Customsetup-changed
Dependencies added: base, haskell-src-meta, template-haskell
Files
- LICENSE +18/−0
- Setup.hs +6/−0
- interpolatedstring-perl6.cabal +21/−0
- src/Text/InterpolatedString/Perl6.hs +98/−0
- tests/Test.hs +35/−0
+ LICENSE view
@@ -0,0 +1,18 @@+Copyright 2009 by Audrey Tang++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to+deal in the Software without restriction, including without limitation the+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or+sell copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:+ +The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.+ +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL+THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ 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-perl6.cabal view
@@ -0,0 +1,21 @@+Name: interpolatedstring-perl6+Version: 0.1+License: BSD3+License-file: LICENSE+Category: Data+Author: Audrey Tang+Copyright: Audrey Tang+Maintainer: Audrey Tang <audreyt@audreyt.org>+Stability: unstable+Cabal-Version: >= 1.2+Build-Depends: base+Build-Type: Custom+Synopsis: QuasiQuoter for Perl6-style multi-line interpolated strings.+Description: QuasiQuoter for Perl6-style multi-line interpolated strings.+Data-Files: tests/Test.hs++library+ extensions: TemplateHaskell, TypeSynonymInstances, FlexibleInstances, UndecidableInstances, OverlappingInstances+ build-depends: base < 5, template-haskell, haskell-src-meta+ hs-source-dirs: src+ exposed-modules: Text.InterpolatedString.Perl6
+ src/Text/InterpolatedString/Perl6.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE TemplateHaskell, TypeSynonymInstances, FlexibleInstances, UndecidableInstances, OverlappingInstances #-} + +-- | QuasiQuoter for interpolated strings using Perl 6 syntax. +-- +-- The "q" form does one thing and does it well: It contains a multi-line string with +-- no interpolation at all: +-- +-- @ +-- {-# LANGUAGE QuasiQuotes, ExtendedDefaultRules #-} +-- import Text.InterpolatedString.Perl6 (q) +-- foo :: String +-- foo = [$q| +-- +-- Well here is a +-- multi-line string! +-- +-- |] +-- @ +-- +-- The "qc" form interpolates curly braces: Expressions inside {} will be +-- directly interpolated if it's a String, or have 'show' called if it is not. +-- +-- Escaping of '{' is done with backslash. +-- +-- For interpolating numeric expressions without an explicit type signature, +-- use the ExtendedDefaultRules language pragma, as shown below: +-- +-- @ +-- {-# LANGUAGE QuasiQuotes, ExtendedDefaultRules #-} +-- import Text.InterpolatedString.Perl6 (qc) +-- bar :: String +-- bar = [$qc| Well {\"hello\" ++ \" there\"} {6 * 7} |] +-- @ +-- +-- bar will have the value \" Well hello there 42 \". +-- +-- If you want control over how 'show' works on your types, define a custom +-- 'ShowQ' instance: +-- +-- @ +-- import Text.InterpolatedString.Perl6 (qc, ShowQ(..)) +-- instance ShowQ ByteString where +-- showQ = unpack +-- @ +-- +-- That way you interpolate bytestrings will not result in double quotes or +-- character escapes. +-- +module Text.InterpolatedString.Perl6 (qc, q, ShowQ(..)) where + +import qualified Language.Haskell.TH as TH +import Language.Haskell.TH.Quote +import Language.Haskell.Meta.Parse + +class Show a => ShowQ a where + showQ :: a -> String + +instance ShowQ Char where + showQ = (:[]) + +instance ShowQ String where + showQ = id + +instance (Show a) => ShowQ a where + showQ = show + +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 [| (++) (showQ $(reify a)) |] $ makeExpr xs + +reify s = + case parseExp s of + Left s -> TH.report True s >> [| "" |] + Right e -> return e + +-- | QuasiQuoter for interpolating Haskell values into a string literal. The pattern portion is undefined. +qc :: QuasiQuoter +qc = QuasiQuoter (makeExpr . parseStr [] . filter (/= '\r')) + $ error "Cannot use qc as a pattern" + +q :: QuasiQuoter +q = QuasiQuoter ((\a -> [|a|]) . filter (/= '\r')) + $ error "Cannot use q as a pattern" +
+ tests/Test.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE QuasiQuotes, ExtendedDefaultRules #-}++module Main where++import Text.InterpolatedString.Perl6+import Test.HUnit++data Foo = Foo Int String deriving Show++t1 = "字元"++testEmpty = assertBool "" ([$qc||] == "")+testCharLiteral = assertBool "" ([$qc|{1+2}|] == "3")+testString = assertBool "" ([$qc|a string {t1} is here|] == "a string 字元 is here")+testEscape = assertBool "" ([$qc|#\{}|] == "#{}" && [$qc|\{}|] == "{}")+testComplex = assertBool "" ([$qc|+ 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 "Character Literal" $ TestCase testCharLiteral+ , TestLabel "String Variable" $ TestCase testString+ , TestLabel "Escape Sequences" $ TestCase testEscape+ , TestLabel "Complex Expression" $ TestCase testComplex+ ]++main = runTestTT tests+