packages feed

interpolatedstring-perl6 0.1 → 0.2

raw patch · 3 files changed

+59/−21 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Text.InterpolatedString.Perl6: qq :: QuasiQuoter

Files

interpolatedstring-perl6.cabal view
@@ -1,5 +1,5 @@ Name:          interpolatedstring-perl6-Version:       0.1+Version:       0.2 License:       BSD3 License-file:  LICENSE Category:      Data@@ -10,8 +10,8 @@ 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.+Synopsis:      QuasiQuoter for Perl6-style multi-line interpolated strings with "q", "qq" and "qc" support.+Description:   QuasiQuoter for Perl6-style multi-line interpolated strings with "q", "qq" and "qc" support. Data-Files:    tests/Test.hs  library
src/Text/InterpolatedString/Perl6.hs view
@@ -2,8 +2,8 @@ 
 -- | 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:
+-- The "q" form does one thin and does it well: It contains a multi-line string with
+-- no interpolation at all:
 --
 -- @
 -- {-# LANGUAGE QuasiQuotes, ExtendedDefaultRules #-}
@@ -20,10 +20,10 @@ -- 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.
+-- Escapin of '{' is done with backslash.
 --
--- For interpolating numeric expressions without an explicit type signature,
--- use the ExtendedDefaultRules language pragma, as shown below:
+-- For interpolatin numeric expressions without an explicit type signature,
+-- use the ExtendedDefaultRules lanuage pragma, as shown below:
 --
 -- @
 -- {-# LANGUAGE QuasiQuotes, ExtendedDefaultRules #-}
@@ -46,11 +46,23 @@ -- That way you interpolate bytestrings will not result in double quotes or
 -- character escapes.
 --
-module Text.InterpolatedString.Perl6 (qc, q, ShowQ(..)) where
+-- The "qq" form adds to the "qc" form with a simple shorthand: '$foo' means '{foo}',
+-- namely interpolating a single variable into the string.
+--
+-- @
+-- {-# LANGUAGE QuasiQuotes, ExtendedDefaultRules #-}
+-- import Text.InterpolatedString.Perl6 (qq)
+-- baz :: String
+-- baz = [$qc| Hello, $who |]
+--     where
+--     who = "World"
+-- @
+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 Data.Char (isAlpha, isAlphaNum)
 
 class Show a => ShowQ a where
     showQ :: a -> String
@@ -66,18 +78,38 @@ 
 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
+unQC a []          = [Literal (reverse a)]
+unQC a ('\\':x:xs) = unQC (x:a) xs
+unQC a ('\\':[])   = unQC ('\\':a) []
+unQC a ('}':xs)    = AntiQuote (reverse a) : parseQC [] xs
+unQC a (x:xs)      = unQC (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
+parseQC a []           = [Literal (reverse a)]
+parseQC a ('\\':x:xs)  = parseQC (x:a) xs
+parseQC a ('\\':[])    = parseQC ('\\':a) []
+parseQC a ('{':xs)     = Literal (reverse a) : unQC [] xs
+parseQC a (x:xs)       = parseQC (x:a) xs
 
+unQQ a []          = [Literal (reverse a)]
+unQQ a ('\\':x:xs) = unQC (x:a) xs
+unQQ a ('\\':[])   = unQC ('\\':a) []
+unQQ a ('}':xs)    = AntiQuote (reverse a) : parseQQ [] xs
+unQQ a (x:xs)      = unQC (x:a) xs
+
+parseQQ a []           = [Literal (reverse a)]
+parseQQ a ('\\':x:xs)  = parseQQ (x:a) xs
+parseQQ a ('\\':[])    = parseQQ ('\\':a) []
+parseQQ a ('$':x:xs) | x == '_' || isAlpha x =
+    Literal (reverse a) : AntiQuote (x:pre) : parseQQ [] post
+    where
+    (pre, post) = span isIdent xs
+parseQQ a ('{':xs)     = Literal (reverse a) : unQC [] xs
+parseQQ a (x:xs)       = parseQQ (x:a) xs
+
+isIdent '_'  = True
+isIdent '\'' = True
+isIdent x    = isAlphaNum x
+
 makeExpr [] = [| "" |]
 makeExpr ((Literal a):xs)   = TH.appE [| (++) a |] $ makeExpr xs
 makeExpr ((AntiQuote a):xs) = TH.appE [| (++) (showQ $(reify a)) |] $ makeExpr xs
@@ -87,9 +119,13 @@         Left s  -> TH.report True s >> [| "" |]
         Right e ->  return e
 
--- | QuasiQuoter for interpolating Haskell values into a string literal. The pattern portion is undefined.
+-- | QuasiQuoter for interpolatin Haskell values into a string literal. The pattern portion is undefined.
+qq :: QuasiQuoter
+qq = QuasiQuoter (makeExpr . parseQQ [] . filter (/= '\r'))
+    $ error "Cannot use qq as a pattern"
+
 qc :: QuasiQuoter
-qc = QuasiQuoter (makeExpr . parseStr [] . filter (/= '\r'))
+qc = QuasiQuoter (makeExpr . parseQC [] . filter (/= '\r'))
     $ error "Cannot use qc as a pattern"
 
 q :: QuasiQuoter
tests/Test.hs view
@@ -12,6 +12,7 @@ testEmpty       = assertBool "" ([$qc||] == "") testCharLiteral = assertBool "" ([$qc|{1+2}|] == "3") testString      = assertBool "" ([$qc|a string {t1} is here|] == "a string 字元 is here")+testVariable    = assertBool "" ([$qq|a string $t1 is here|] == "a string 字元 is here") testEscape      = assertBool "" ([$qc|#\{}|] == "#{}" && [$qc|\{}|] == "{}") testComplex     = assertBool "" ([$qc|         ok@@ -27,6 +28,7 @@     [ TestLabel "Empty String" $ TestCase testEmpty     , TestLabel "Character Literal" $ TestCase testCharLiteral     , TestLabel "String Variable" $ TestCase testString+    , TestLabel "Dollar Variable" $ TestCase testVariable     , TestLabel "Escape Sequences" $ TestCase testEscape     , TestLabel "Complex Expression" $ TestCase testComplex     ]