on master help sign in
* updated elm QuasiQuoter for variable interpolation

The elm QuasiQuoter now supports variable interpolation using the ^{..} syntax. An updated elm-yesod example will follow soon. Version bumped to 0.1.2 because this is a rather significant change, thanks to mikeplus64 for the QuasiQuoter he wrote that I could have a look at while writing ours.

commitfd1b410ea45635a1b430128d74572c38e77b1e1d authorVincent Ambo <v.ambo@me.com> dateTue 29 May 2012, 02:48 (14 years ago) parent3bd18e1
3 files changed+101−36
elm/Elm.cabal+7−3 elm/src/Language/Elm.hs+1−33 elm/src/Language/Elm/Quasi.hs+93
elm/Elm.cabal+7−3
@@ -1,6 +1,6 @@
11
22Name: Elm
3−Version: 0.1.1.8
3+Version: 0.1.2
44Synopsis: The Elm language module.
55Description: Elm aims to make client-side web-development more pleasant.
66 It is a statically/strongly typed, functional reactive
@@ -64,7 +64,8 @@ Library
6464 Language.Elm.CompileToJS,
6565 Language.Elm.ExtractNoscript,
6666 Language.Elm.Initialize,
67− Language.Elm.GenerateHtml
67+ Language.Elm.GenerateHtml,
68+ Language.Elm.Quasi
6869 Hs-Source-Dirs: src, src/Parse, src/Types
6970 other-modules: Ast,
7071 Guid,
@@ -91,4 +92,7 @@ Library
9192 blaze-html == 0.5.0.*,
9293 blaze-markup == 0.5.1.*,
9394 deepseq,
94− template-haskell
95+ template-haskell,
96+ haskell-src-meta == 0.5.*,
97+ text,
98+ attoparsec == 0.10.*
elm/src/Language/Elm.hs+1−33
@@ -1,4 +1,3 @@
1−{-# LANGUAGE QuasiQuotes, TemplateHaskell #-}
21{- | This module re-exports the modules necessary for compiling Elm code into the
32 respective HTML, JS and CSS code.
43
@@ -19,35 +18,4 @@ import Language.Elm.CompileToJS
1918import Language.Elm.ExtractNoscript
2019import Language.Elm.Initialize
2120import Language.Elm.GenerateHtml
22−import Language.Haskell.TH
23−import Language.Haskell.TH.Quote
24−
25−{- | This QuasiQuoter allows for literal embedding of elm source code within
26− Haskell files. It is not responsible for the actual compilation Process.
27− Usage:
28−
29− @
30− elmPage = [elm|
31− main = image \"someImage.jpg\"
32− |]
33− @
34−
35− How the elm code is compiled depends on how you intend to use it.
36− Example uses are the included 'generateHtml' function as well as the
37− "Language.Elm.Yesod" module.
38−-}
39−elm :: QuasiQuoter
40−elm = QuasiQuoter {quoteExp = \s -> [|s|] }
41−
42−{- | elmFile is a quoteFile wrapper around the 'elm' QuasiQuoter and allows for
43− external elm source files to be embedded.
44− Usage:
45−
46− @
47− [elmFile|elm-source/page.elm|]
48− @
49−
50− Please note that no spaces should be added before and after the filename.
51−-}
52−elmFile :: QuasiQuoter
53−elmFile = quoteFile elm
21+import Language.Elm.Quasi
elm/src/Language/Elm/Quasi.hsnew file+93
@@ -0,0 +1,93 @@
1+{-# LANGUAGE TemplateHaskell, OverloadedStrings #-}
2+{-# OPTIONS_GHC -fno-warn-missing-fields #-}
3+
4+module Language.Elm.Quasi (elm, elmFile) where
5+
6+import Language.Haskell.TH.Quote
7+import Language.Haskell.TH
8+import Language.Haskell.Meta (parseExp)
9+
10+import Data.Attoparsec.Text
11+import Data.Text as T (Text, pack, unpack, strip)
12+
13+{- | This QuasiQuoter allows for literal embedding of elm source code within
14+ Haskell files. It is not responsible for the actual compilation Process.
15+ Usage:
16+
17+ @
18+ elmPage = [elm|
19+ main = image \"someImage.jpg\"
20+ |]
21+ @
22+
23+ It also allows for simple variable interpolation using the ^{...} syntax.
24+ This is intended for e.g. embedding pre-rendered type-safe URLs.
25+ All interpolated variables must be a member of the Show typeclass. This
26+ is not tested with more complicated expressions, so it is recommended to
27+ restrict usage of interpolation to pre-calculated variables.
28+
29+ Example:
30+
31+ > let google = "http://google.com"
32+ > in [elm|
33+ > main = text $ link ^{google} (toText "Google")
34+ > |]
35+
36+
37+ How the elm code is compiled depends on how you intend to use it.
38+ Example uses are the included 'generateHtml' function as well as the
39+ "Language.Elm.Yesod" module.
40+-}
41+elm :: QuasiQuoter
42+elm = QuasiQuoter
43+ { quoteExp = \s ->
44+ let chunks = flip map (getQChunks s) $ \c ->
45+ case c of
46+ S t -> [| t |]
47+ E t -> let Right e = parseExp t in appE [| show |] (return e)
48+ in appE [| concat |] (listE chunks)
49+ }
50+
51+{- | elmFile is a quoteFile wrapper around the 'elm' QuasiQuoter and allows for
52+ external elm source files to be embedded.
53+ Usage:
54+
55+ @
56+ [elmFile|elm-source/page.elm|]
57+ @
58+
59+ Please note that no spaces should be added before and after the filename.
60+-}
61+elmFile :: QuasiQuoter
62+elmFile = quoteFile elm
63+
64+data QChunk =
65+ S String -- ^ A literal string
66+ | E String -- ^ An expression (must be of the Show typeclass)
67+ deriving (Show, Eq)
68+
69+
70+{- thanks to mikeplus64 for providing an example QuasiQuoter that I could look at while writing this :) -}
71+getQChunks :: String -> [QChunk]
72+getQChunks si = let i = T.pack si
73+ Right m = parseOnly parser (strip i) in m
74+ where
75+ parser = go []
76+
77+ go s = do
78+ txt <- takeTill (== '^')
79+ evt <- choice [expression, fmap (S . T.unpack) takeText]
80+ end <- atEnd
81+ if end
82+ then return $ filter (not . blank) $ reverse (evt:(S . T.unpack) txt:s)
83+ else go (evt:(S . T.unpack) txt:s)
84+
85+ blank (S "") = True
86+ blank (E "") = True
87+ blank _ = False
88+
89+ expression = do
90+ string "^{"
91+ expr <- takeTill (== '}')
92+ char '}'
93+ return $ (E . T.unpack) expr