How can Haskell quasiquotation be used for replacing tokens on the Haskell level?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import Language.Haskell.Meta.Parse -- from haskell-src-meta
import Language.Haskell.TH.Quote   -- from template-haskell obviously

myedsl :: QuasiQuoter
myedsl = QuasiQuoter { quoteExp = myedslExpr }

myedslExpr :: String -> Q Exp
myedslExpr = return . transform . either error id . parseExp
-- TODO The above code calls `error` on failure; it might be better to do
-- something else

-- Do the actual code transformation here
transform :: Exp -> Exp

-- Transform any variable that starts and ends with '.' into the variable
-- without the '.'s
transform (VarE name)
  | let base = nameBase name
    in (not . null . tail $ base) -- Name is longer than 1 char
       && head base == '.'        -- Name starts with '.'
       && last base == '.'        -- Name ends with '.'
  = VarE . mkName       -- Create a new variable
    . maybe id          -- in the same module as the old variable
      sepPeriod
      (nameModule name)
    . tail . init       -- with the first and last characters removed
    . nameBase $ name   -- from the base name of the old variable
    -- TODO The above code will fail if the variable has a qualified
    -- module (e.g. `EDSL..%.`)
  where
    sepPeriod a b = a ++ "." ++ b

-- If the expression isn't a variable, you have to visits any child
-- expressions that might exist. Here I show the example for AppE, but
-- there are many more
transform (AppE e1 e2) = AppE (transform e1) (transform e2)
-- ... TODOother constructors such as InfixE, UInfixE, ParensE, LamE, ...

-- There are some expressions that don't need rewriting
transform expr = expr