/Text/Peggy/CodeGen/TH.hs

https://github.com/tanakh/Peggy · Haskell · 311 lines · 257 code · 42 blank · 12 comment · 33 complexity · c02542fce3d2fb664cd69884933969ae MD5 · raw file

  1. {-# LANGUAGE TemplateHaskell, TupleSections, FlexibleContexts #-}
  2. module Text.Peggy.CodeGen.TH (
  3. genDecs,
  4. genQQ,
  5. ) where
  6. import Control.Applicative
  7. import Control.Monad
  8. import qualified Data.HashTable.ST.Basic as HT
  9. import Data.List
  10. import qualified Data.ListLike as LL
  11. import Data.Maybe
  12. import Data.Typeable ()
  13. import Language.Haskell.Meta
  14. import Language.Haskell.TH
  15. import Language.Haskell.TH.Syntax
  16. import Language.Haskell.TH.Quote
  17. import Text.Peggy.Prim
  18. import Text.Peggy.Syntax
  19. import Text.Peggy.SrcLoc
  20. import Text.Peggy.Normalize
  21. import Text.Peggy.LeftRec
  22. genQQ :: Syntax -> (String, String) -> Q [Dec]
  23. genQQ syn (qqName, parserName) = do
  24. sig <- sigD (mkName qqName) (conT ''QuasiQuoter)
  25. dat <- valD (varP $ mkName qqName) (normalB con) []
  26. return [sig, dat]
  27. where
  28. con = do
  29. e <- [| \str -> do
  30. loc <- location
  31. case parse $(varE $ mkName parserName) (SrcPos (loc_filename loc) 0 (fst $ loc_start loc) (snd $ loc_start loc)) str of
  32. Left err -> error $ show err
  33. Right a -> a
  34. |]
  35. u <- [| undefined |]
  36. recConE 'QuasiQuoter [ return ('quoteExp, e)
  37. , return ('quoteDec, u)
  38. , return ('quotePat, u)
  39. , return ('quoteType, u)
  40. ]
  41. genDecs :: Syntax -> Q [Dec]
  42. genDecs = generate . normalize . removeLeftRecursion
  43. generate :: Syntax -> Q [Dec]
  44. generate defs = do
  45. tblTypName <- newName "MemoTable"
  46. tblDatName <- newName "MemoTable"
  47. ps <- parsers tblTypName
  48. sequence $ [ defTbl tblTypName tblDatName
  49. , instTbl tblTypName tblDatName
  50. ] ++ ps
  51. where
  52. n = length defs
  53. defTbl :: Name -> Name -> DecQ
  54. defTbl tblTypName tblDatName = do
  55. s <- newName "s"
  56. str <- newName "str"
  57. dataD (cxt []) tblTypName [PlainTV str, PlainTV s] [con s str] []
  58. where
  59. con s str = recC tblDatName $ map toMem defs where
  60. toMem (Definition nont typ _) = do
  61. let tt | isExp nont = [t| ExpQ |]
  62. | otherwise = parseType' typ
  63. t <- [t| HT.HashTable $(varT s) Int
  64. (Result $(varT str) $tt) |]
  65. return (mkName $ "tbl_" ++nont, NotStrict, t)
  66. instTbl :: Name -> Name -> DecQ
  67. instTbl tblTypName tblDatName = do
  68. str <- newName "str"
  69. instanceD (cxt []) (conT ''MemoTable `appT` (conT tblTypName `appT` varT str))
  70. [ valD (varP 'newTable) (normalB body) [] ]
  71. where
  72. body = do
  73. names <- replicateM n (newName "t")
  74. doE $ map (\name -> bindS (varP name) [| HT.new |]) names
  75. ++ [ noBindS $ appsE [varE 'return, appsE $ conE tblDatName : map varE names]]
  76. parsers tblName = concat <$> mapM (gen tblName) defs
  77. isExp name = isJust $ find f defs where
  78. f (Definition nont typ _)
  79. | nont == name && head (words typ) == "Exp" = True
  80. | otherwise = False
  81. gen tblName (Definition nont typ e)
  82. | isExp nont = return $
  83. [ genSig tblName nont [t| ExpQ |]
  84. , funD (mkName nont)
  85. [clause [] (normalB [| memo $(varE $ mkName $ "tbl_" ++ nont) $ $(genP True e) |]) []]]
  86. | otherwise = return $
  87. [ genSig tblName nont (parseType' typ)
  88. , funD (mkName nont)
  89. [clause [] (normalB [| memo $(varE $ mkName $ "tbl_" ++ nont) $ $(genP False e) |]) []]]
  90. genSig tblName name typ = do
  91. str <- newName "str"
  92. s <- newName "s"
  93. sigD (mkName name) $
  94. forallT [PlainTV str, PlainTV s]
  95. (cxt [classP ''LL.ListLike [varT str, conT ''Char]]) $
  96. conT ''Parser `appT`
  97. (conT tblName `appT` varT str) `appT`
  98. varT str `appT`
  99. varT s `appT`
  100. typ
  101. -- Generate Parser
  102. genP :: Bool -> Expr -> ExpQ
  103. genP isE e = case (isE, e) of
  104. (False, Terminals False False str) ->
  105. [| string str |]
  106. (True, Terminals False False str) ->
  107. [| lift <$> string str |]
  108. (False, TerminalSet rs) ->
  109. [| satisfy $(genRanges rs) |]
  110. (True, TerminalSet rs) ->
  111. [| lift <$> satisfy $(genRanges rs) |]
  112. (False, TerminalCmp rs) ->
  113. [| satisfy $ not . $(genRanges rs) |]
  114. (True, TerminalCmp rs) ->
  115. [| lift <$> (satisfy $ not . $(genRanges rs)) |]
  116. (False, TerminalAny) ->
  117. [| anyChar |]
  118. (True, TerminalAny) ->
  119. [| lift <$> anyChar |]
  120. (False, NonTerminal nont) ->
  121. if isExp nont then error $ "value cannot contain exp: " ++ nont
  122. else [| $(varE $ mkName nont) |]
  123. (True, NonTerminal nont) ->
  124. if isExp nont
  125. then [| $(varE $ mkName nont) |]
  126. else [| lift <$> $(varE $ mkName nont) |]
  127. (False, Primitive name) ->
  128. [| $(varE $ mkName name) |]
  129. (True, Primitive name) ->
  130. [| lift <$> $(varE $ mkName name) |]
  131. (False, Empty) ->
  132. [| return () |]
  133. (True, Empty) ->
  134. [| lift <$> return () |]
  135. (False, Many f) ->
  136. [| many $(genP isE f) |]
  137. (True, Many f) ->
  138. [| do eQs <- many $(genP isE f); return $ listE eQs |]
  139. (False, Some f) ->
  140. [| some $(genP isE f) |]
  141. (True, Some f) ->
  142. [| do eQs <- some $(genP isE f); return $ listE eQs |]
  143. (False, Optional f) ->
  144. [| optional $(genP isE f) |]
  145. (True, Optional f) ->
  146. [| do eQm <- optional $(genP isE f); case eQm of Nothing -> lift Nothing; Just q -> do ee <- q; lift (Just ee) |]
  147. (False, And f) ->
  148. [| expect $(genP isE f) |]
  149. (True, And f) ->
  150. [| lift () <$ expect $(genP isE f) |]
  151. (False, Not f) ->
  152. [| unexpect $(genP isE f) |]
  153. (True, Not f) ->
  154. [| lift () <$ unexpect $(genP isE f) |]
  155. (_, Token f) ->
  156. [| token $(varE skip) $(varE delimiter) ( $(genP isE f) ) |]
  157. -- simply, ignoreing result value
  158. (False, Named "_" f) ->
  159. [| () <$ $(genP isE f) |]
  160. (True, Named "_" f) ->
  161. [| () <$ $(genP isE f) |]
  162. (_, Named {}) -> error "named expr must has semantic."
  163. (False, Choice es) ->
  164. foldl1 (\a b -> [| $a <|> $b |]) $ map (genP isE) es
  165. (True, Choice es) ->
  166. [| $(foldl1 (\a b -> [| $a <|> $b |]) $ map (genP isE) es) |]
  167. -- Semancit Code
  168. -- Generates a Normal, value constructing code.
  169. -- It cannot has anti-quotes, values dependent on anti-quotes.
  170. (False, Semantic (Sequence es) cf) -> do
  171. -- TODO: make it syntax-sugar
  172. let needSt = hasPos cf || hasSpan cf
  173. needEd = hasSpan cf
  174. st = if needSt then [bindS (varP $ mkName stName) [| getPos |]] else []
  175. ed = if needEd then [bindS (varP $ mkName edName) [| getPos |]] else []
  176. doE $ st ++ genBinds 1 es ++ ed ++ [ noBindS [| return $(genCF isE cf) |] ]
  177. -- Generates a Exp constructing code.
  178. -- It can contain anti-quotes.
  179. -- Anti-quoted value must be Normal values.
  180. (True, Semantic (Sequence es) cf) -> do
  181. bs <- sequence $ genBinds 1 es
  182. let vn = length $ filter isBind bs
  183. let gcf = genCF isE (ccf vn)
  184. doE $ map return bs ++
  185. [ noBindS [| return $ foldl appE (return $(lift =<< gcf)) $(eQnames vn) |]]
  186. where
  187. ccf 0 = cf
  188. ccf nn = [Snippet $ "\\" ++ unwords (names nn ++ qames nn) ++ " -> ("] ++ cf ++ [Snippet ")"]
  189. eQnames nn =
  190. listE $ [ [| lift $(varE (mkName $ var i)) |] | i <- [1..nn]] ++
  191. [ if hasAQ i cf
  192. then [| varE $ mkName $(varE $ mkName $ var i) |]
  193. else [| litE $ integerL 0 |]
  194. | i <- [1..nn]]
  195. names nn = map var [1..nn]
  196. qames nn = map qar [1..nn]
  197. _ ->
  198. error $ "internal compile error: " ++ show e
  199. where
  200. genBinds _ [] = []
  201. genBinds ix (f:fs) = case f of
  202. Named "_" g ->
  203. noBindS (genP isE g) :
  204. genBinds ix fs
  205. Named name g ->
  206. bindS (asP (mkName name) $ varP $ mkName (var ix)) (genP isE g) :
  207. genBinds (ix+1) fs
  208. _ | shouldBind f ->
  209. bindS (varP $ mkName $ var ix) (genP isE f) :
  210. genBinds (ix+1) fs
  211. _ ->
  212. noBindS (genP isE f) :
  213. genBinds ix fs
  214. genRanges :: [CharRange] -> ExpQ
  215. genRanges rs =
  216. let c = mkName "c" in
  217. lamE [varP c] $ foldl1 (\a b -> [| $a || $b |]) $ map (genRange c) rs
  218. genRange :: Name -> CharRange -> ExpQ
  219. genRange c (CharRange l h) =
  220. [| l <= $(varE c) && $(varE c) <= h |]
  221. genRange c (CharOne v) =
  222. [| $(varE c) == v |]
  223. genCF isE cf =
  224. case parsed of
  225. Left _ ->
  226. error $ "code fragment parse error: " ++ scf
  227. Right ret ->
  228. return ret
  229. where
  230. parsed = parseExp scf
  231. scf = concatMap toStr cf
  232. toStr (Snippet str) = str
  233. toStr (Argument a) = var a
  234. toStr (AntiArgument nn)
  235. | not isE = error "Anti-quoter is not allowed in non-AQ parser"
  236. | otherwise = qar nn
  237. toStr ArgPos = "(LocPos " ++ stName ++ ")"
  238. toStr ArgSpan = "(LocSpan " ++ stName ++ " " ++ edName ++ ")"
  239. hasAQ x cf = not . null $ filter (isAQ x) cf where
  240. isAQ i (AntiArgument j) = i == j
  241. isAQ _ _ = False
  242. hasPos = any (==ArgPos)
  243. hasSpan = any (==ArgSpan)
  244. isBind (BindS _ _) = True
  245. isBind _ = False
  246. skip = mkName "skip"
  247. delimiter = mkName "delimiter"
  248. var nn = "v" ++ show (nn :: Int)
  249. qar nn = "q" ++ show (nn :: Int)
  250. stName = "st_Pos"
  251. edName = "ed_Pos"
  252. parseExp' str =
  253. case parseExp str of
  254. Left _ ->
  255. error $ "code fragment parse error: " ++ str
  256. Right ret ->
  257. return ret
  258. parseType' typ =
  259. case parseType typ of
  260. Left err -> error $ "type parse error :" ++ typ ++ ", " ++ err
  261. Right t -> case t of
  262. -- GHC.Unit.()/GHC.Tuple.() is not a type name. Is it a bug of haskell-src-meta?
  263. -- Use (TupleT 0) insted.
  264. ConT con | show con == "GHC.Unit.()" ->
  265. return $ TupleT 0
  266. ConT con | show con == "GHC.Tuple.()" ->
  267. return $ TupleT 0
  268. _ ->
  269. return t