on master help sign in
* updated elm QuasiQuoter for variable interpolation
fd1b410Vincent Ambo
elm/Elm.cabal+7−3
@@ -1,6 +1,6 @@
1
1
2Name: Elm
2Name: Elm
3−Version: 0.1.1.8
3+Version: 0.1.2
4Synopsis: The Elm language module.
4Synopsis: The Elm language module.
5Description: Elm aims to make client-side web-development more pleasant.
5Description: Elm aims to make client-side web-development more pleasant.
6 It is a statically/strongly typed, functional reactive
6 It is a statically/strongly typed, functional reactive
@@ -64,7 +64,8 @@ Library
64 Language.Elm.CompileToJS,
64 Language.Elm.CompileToJS,
65 Language.Elm.ExtractNoscript,
65 Language.Elm.ExtractNoscript,
66 Language.Elm.Initialize,
66 Language.Elm.Initialize,
67− Language.Elm.GenerateHtml
67+ Language.Elm.GenerateHtml,
68+ Language.Elm.Quasi
68 Hs-Source-Dirs: src, src/Parse, src/Types
69 Hs-Source-Dirs: src, src/Parse, src/Types
69 other-modules: Ast,
70 other-modules: Ast,
70 Guid,
71 Guid,
@@ -91,4 +92,7 @@ Library
91 blaze-html == 0.5.0.*,
92 blaze-html == 0.5.0.*,
92 blaze-markup == 0.5.1.*,
93 blaze-markup == 0.5.1.*,
93 deepseq,
94 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 #-}
2{- | This module re-exports the modules necessary for compiling Elm code into the
1{- | This module re-exports the modules necessary for compiling Elm code into the
3 respective HTML, JS and CSS code.
2 respective HTML, JS and CSS code.
4
3
@@ -19,35 +18,4 @@ import Language.Elm.CompileToJS
19import Language.Elm.ExtractNoscript
18import Language.Elm.ExtractNoscript
20import Language.Elm.Initialize
19import Language.Elm.Initialize
21import Language.Elm.GenerateHtml
20import Language.Elm.GenerateHtml
22−import Language.Haskell.TH
21+import Language.Elm.Quasi
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
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