{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}

module TestQQDefs where

import Data.String
import Language.Haskell.TH.Quote


sq :: QuasiQuoter
sq = qqExtractor 1 "\n****"

sq_f = quoteFile sq
sq2_f = quoteFile $ qqExtractor 2 "\n****"
sq3_f = quoteFile $ qqExtractor 3 "\n****"

uq :: QuasiQuoter
uq = qqExtractor 1 "\n____"

uq_f = quoteFile uq
uq2_f = quoteFile $ qqExtractor 2 "\n____"
uq3_f = quoteFile $ qqExtractor 3 "\n____"

qqExtractor idx sep = QuasiQuoter (extractor idx sep)
                      (error "no patterns supported")
                      (error "no types supported")
                      (error "no declarations supported")

-- extractor :: String -> String -> QState
extractor idx sep s =
  case inSeps idx sep $ filter (/= '\r') s of
    Post a -> [|fromString a|]
    Pre n _ -> error $ "No starting line found for block " <> show n
    MatchLine n -> error $ "Only starting line found for block " <> show n
    Pass n _ -> error $ "No ending line found for block " <> show n

data QState = Pre Int String | MatchLine Int | Pass Int String | Post String

inSeps :: Int -> String -> String -> QState
inSeps idx sep =
  let sepl = length sep
      nxtC :: QState -> Char -> QState
      nxtC (Pre n p) c = let p' = c : p
                             l = length p'
                         in if reverse p' == take l sep
                            then if l == sepl then MatchLine n else Pre n p'
                            else Pre n $ take (sepl-1) p'
      nxtC p@(MatchLine n) c = if '\n' == c then Pass n "" else p
      nxtC (Pass n s) c = let s' = c : s
                              sl = reverse $ take sepl s'
                          in if sl == sep
                             then if n == 1
                                  then Post (reverse $ drop (sepl-1) s')
                                  else Pre (n - 1) ""
                             else Pass n s'
      nxtC (Post s) _ = Post s
    in foldl nxtC (Pre idx "")
