{-# LANGUAGE QuasiQuotes, TemplateHaskell, ScopedTypeVariables,
    OverloadedStrings #-}
{-|
  Module      : Language.ANTLR4.FileOpener
  Description : Quasiquoter for reading files by name at compile time
  Copyright   : (c) Karl Cronburg, 2018
  License     : BSD3
  Maintainer  : karl@cs.tufts.edu
  Stability   : experimental
  Portability : POSIX

  Just do the following. It'll make sense:

  @
    foo = id
    file_contents = [open| test/file.foo |]
  @
-}
module Language.ANTLR4.FileOpener (
  -- * File opening quasiquoter
    open
  ) where
import qualified Language.Haskell.TH as TH
import Language.Haskell.TH.Syntax (Exp(..), addDependentFile)
import Language.Haskell.TH.Quote (QuasiQuoter(..))

import Data.Text (strip, splitOn, pack, unpack)

-- | A quasiquoter for opening a file on disk, reading its contents, and running
--   a function by the same name as the file extension. e.g.:
--
-- @
--   foo = id
--   file_contents = [open| test/file.foo |]
-- @
--
-- @foo@ gets called on the contents of files with the extension @.foo@.
open :: QuasiQuoter
open = QuasiQuoter
  { quoteExp  = openExp
  , quotePat  = error "parse pattern"
  , quoteType = error "parse type"
  , quoteDec  = error "parse decl?"
  }

-- | Reads a file and runs a function with the name of the file extension,
--   returning the result for use by a quasiquoter.
openExp :: String -> TH.Q TH.Exp
openExp s = let
    fn  = unpack $ strip $ pack s
    ext = unpack $ last $ splitOn "." $ pack fn
  in do
    file_contents <- TH.runIO (readFile fn)
    addDependentFile fn
    [| $(return $ TH.VarE $ TH.mkName ext) file_contents |]