{-# LANGUAGE TemplateHaskell, QuasiQuotes, ParallelListComp #-} -- | Template module Data.Array.Repa.Stencil.Template (stencil2) where import Data.Array.Repa.Index import Language.Haskell.TH import Language.Haskell.TH.Quote import qualified Data.List as List -- | QuasiQuoter for producing a static stencil defintion. -- -- A definition like -- -- @ -- [stencil2| 0 1 0 -- 1 0 1 -- 0 1 0 |] -- @ -- -- Is converted to: -- -- @ -- makeStencil2 (Z:.3:.3) -- (\\ix -> case ix of -- Z :. -1 :. 0 -> Just 1 -- Z :. 0 :. -1 -> Just 1 -- Z :. 0 :. 1 -> Just 1 -- Z :. 1 :. 0 -> Just 1 -- _ -> Nothing) -- @ -- stencil2 :: QuasiQuoter stencil2 = QuasiQuoter { quoteExp = parseStencil2 , quotePat = undefined , quoteType = undefined , quoteDec = undefined } -- | Parse a stencil definition. -- TODO: make this more robust. parseStencil2 :: String -> Q Exp parseStencil2 str = let -- Determine the extent of the stencil based on the layout. -- TODO: make this more robust. In particular, handle blank -- lines at the start of the definition. line1 : _ = lines str sizeX = fromIntegral $ length $ lines str sizeY = fromIntegral $ length $ words line1 -- TODO: this probably doesn't work for stencils who's extents are even. minX = negate (sizeX `div` 2) minY = negate (sizeY `div` 2) maxX = sizeX `div` 2 maxY = sizeY `div` 2 -- List of coefficients for the stencil. coeffs = (List.map read $ words str) :: [Integer] in makeStencil2' sizeX sizeY $ filter (\(_, _, v) -> v /= 0) $ [ (fromIntegral y, fromIntegral x, fromIntegral v) | y <- [minX, minX + (1 :: Integer) .. maxX] , x <- [minY, minY + (1 :: Integer) .. maxY] | v <- coeffs ] makeStencil2' :: Integer -> Integer -> [(Integer, Integer, Integer)] -> Q Exp makeStencil2' sizeX sizeY coeffs = do ix' <- newName "ix" z' <- [p| Z |] coeffs' <- newName "coeffs" let fnCoeffs = LamE [VarP ix'] $ CaseE (VarE (mkName "ix")) $ [ Match (InfixP (InfixP z' (mkName ":.") (LitP (IntegerL oy))) (mkName ":.") (LitP (IntegerL ox))) (NormalB $ ConE (mkName "Just") `AppE` LitE (IntegerL v)) [] | (oy, ox, v) <- coeffs ] ++ [Match WildP (NormalB $ ConE (mkName "Nothing")) []] return $ AppE (VarE (mkName "makeStencil2") `AppE` (LitE (IntegerL sizeX)) `AppE` (LitE (IntegerL sizeY))) $ LetE [ PragmaD (InlineP (mkName "coeffs") Inline FunLike (BeforePhase 0)) , ValD (VarP coeffs') (NormalB fnCoeffs) [] ] (VarE (mkName "coeffs"))