Interpolation (empty) → 0.1
raw patch · 4 files changed
+176/−0 lines, 4 filesdep +basedep +sybdep +template-haskellsetup-changed
Dependencies added: base, syb, template-haskell
Files
- Data/String/Interpolation.hs +132/−0
- Interpolation.cabal +18/−0
- LICENSE +24/−0
- Setup.hs +2/−0
+ Data/String/Interpolation.hs view
@@ -0,0 +1,132 @@+{-# LANGUAGE QuasiQuotes,TemplateHaskell,DeriveDataTypeable #-}+module Data.String.Interpolation(str) where+import Language.Haskell.TH as TH+import Language.Haskell.TH.Quote+import Data.Data+import Data.Maybe+import Data.Char+import Data.List(intercalate)++quoteExprExp :: String -> TH.ExpQ+-- | Quasiquote 'str' implements multiline strings with interpolation.+-- Interpolating a value of parameter a into the string is done by $a$+-- and interpolating anything with instance Show is $:a$.+--+-- Repetitive patterns can be made by # symbol using the following syntax: +--+-- @+-- \#\<var\> in \<list\>: \<interpolated string\> (|\<interpolated string\>)\#+-- @+-- +-- Where (|\<interpolated string\>) denotes optional separator for the +-- elements.+-- +--+-- Example:+-- +-- @+-- \#i in myList: this is $i$|--\#+-- @+-- +-- Which will evaluate to @ 1--2--3 @ given myList of [1,2,3]+-- +-- +-- Multiline indentation is handled by aligning on smallest un-empty+-- line after the first.+--+-- Pattern matching is not supported. +--++str :: QuasiQuoter+str = QuasiQuoter quoteExprExp undefined+--+quoteExprExp s = psToStringE (parParse $ norming s)+--++psToStringE :: PieceString -> TH.Q TH.Exp+psToStringE [] = TH.stringE ""+psToStringE (x:xs) = TH.infixE (Just $ sbitToExp x)+ ([| (++) |])+ (Just $ psToStringE xs)++sbitToExp :: StringBits -> ExpQ+sbitToExp (Str x) = TH.stringE x +sbitToExp (Var x) = (TH.varE (TH.mkName x))+sbitToExp (SVar x) = TH.appE (TH.varE (TH.mkName "show"))+ (TH.varE (TH.mkName x))++sbitToExp (RepVar varName lstName rep sep) + = [|intercalate $(sepr) (map $(lam) $(lstN))|]+ where+ sepr = psToStringE (fromMaybe [Str ""] sep)+ lam = TH.lamE [varN] (psToStringE rep)+ varN = TH.varP $ TH.mkName varName+ lstN = TH.varE $ TH.mkName lstName++type PieceString = [StringBits]+data StringBits = Str String | Var String | SVar String+ | RepVar String String + PieceString (Maybe PieceString)+ deriving (Eq,Ord,Show,Typeable,Data)++-- Split to string into pieces. This needs proper error messages.+-- Perhaps parsec?+parParse :: [Char] -> [StringBits]+parParse [] = []++parParse ('$':'$':s) = Str "$":parParse s -- Parse escapes+parParse ('#':'#':s) = Str "#":parParse s++parParse ('$':':':s) = SVar (takeWhile (/='$') s) -- Parse antiquotes+ :parParse (drop 1 (dropWhile (/='$') s))+parParse ('$':s) = Var (takeWhile (/='$') s)+ :parParse (drop 1 (dropWhile (/='$') s))++parParse ('#':s) = let (bind,exprS) = break (==':') s+ (hasSep,expr,sepS) = takeRep $ drop 1 exprS+ (sep,restS) = break (=='#') $ sepS+ rest = drop 1 restS+ [varName,"in",listName] = words bind+ in if hasSep + then RepVar varName listName + (parParse expr) (Just $ parParse sep) + : parParse rest+ else RepVar varName listName + (parParse expr) (Nothing) + : parParse sepS++parParse s = Str (takeWhile (notIn "$#") s)+ : parParse (dropWhile (notIn "$#") s) ++notIn :: (Eq a) => [a] -> a -> Bool+notIn s x =not $ elem x s ++takeRep :: String -> (Bool,String,String)+takeRep x = takeRep' x []++takeRep' :: String -> String -> (Bool,String,String)+takeRep' [] _ = error "Repetition template does not end"+takeRep' ('|':'|':s) acc = takeRep' s ('|':acc)+takeRep' ('|':s) acc = (True,reverse acc,s)+takeRep' ('#':s) acc = (False,reverse acc,s)+takeRep' (r:s) acc = takeRep' s (r:acc)+++-- Normalize the indentation to match second line++norming :: String -> String+norming = unlines . norming' . lines++norming':: [String] -> [String]+norming' [] = []+norming' (l:lst) = l:map (drop (n)) lst+ where + n = minimumD 0 $ map (length . takeWhile (==' ') ) + $ (filter (not.isEmpty) lst)+ isEmpty = all (isSpace)+++minimumD :: (Ord a) => a -> [a] -> a+minimumD d [] = d+minimumD _ x = minimum x+
+ Interpolation.cabal view
@@ -0,0 +1,18 @@+Name: Interpolation+Version: 0.1+Description: This package adds quasiquoter for multiline + strings, interpolation and simple templating.+ Handy for text generation.+Category: Text+Synopsis: Multiline strings, interpolation and templating.+License: OtherLicense+License-file: LICENSE+Author: Ville Tirronen+Maintainer: aleator@gmail.com+Build-Type: Simple+Cabal-Version: >=1.2++Library+ Build-Depends: base, syb, template-haskell+ Exposed-modules: Data.String.Interpolation+ ghc-options: -Wall
+ LICENSE view
@@ -0,0 +1,24 @@+++The MIT License++Copyright (c) 2009 Ville Tirronen++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 OR COPYRIGHT HOLDERS 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,2 @@+import Distribution.Simple+main = defaultMain