{-|
  Module:    HaskHOL.Core.Ext.QQ
  Copyright: (c) The University of Kansas 2013
  LICENSE:   BSD3

  Maintainer:  ecaustin@ittc.ku.edu
  Stability:   unstable
  Portability: unknown

  This module defines a mechanism for compile time quasi-quoting of 'HOLTerm's.
  The 'baseQuoter' method constructs a theory specific quasi-quoter that parses
  'HOLTerm's at the expression level using 'toHTm'.  An example, 'base' is 
  provided to demonstrate how this process works.

  Additionally, a specialized quasi-quoter for 'String's is provided that
  escapes special characters and trims white-space.  This can be helpful when
  expressing 'HOLTerm's as 'String's, i.e. @\"\\ x . x\"@.
-}
module HaskHOL.Core.Ext.QQ
    ( baseQuoter  -- :: Typeable thry => HOLContext thry -> QuasiQuoter
    , base        -- :: QuasiQuoter
    , str         -- :: QuasiQuoter
    ) where

import HaskHOL.Core.Lib
import HaskHOL.Core.State
import HaskHOL.Core.Parser
import HaskHOL.Core.Ext.Protected

{-
  We require some Template Haskell primitives that shouldn't be exposed outside
  of this module, i.e. runIO
-}
import Language.Haskell.TH
import Language.Haskell.TH.Quote
import Language.Haskell.TH.Syntax (Lift(..))

-- Only used here, not really necessary to include in Core.Lib
import Data.Char (isSpace)

{-|
  This is the base quasi-quoter for the HaskHOL system.  When provided with a
  theory context value, it constucts a theory specific quasi-quoter that parses
  a 'String' as a term, protecting and lifting the result.

  Note that, at this point in time, we only allowing quoting at the expression
  level.
-}
baseQuoter :: Typeable thry => HOLContext thry -> QuasiQuoter
baseQuoter ctxt = QuasiQuoter quoteBaseExps nothing nothing nothing
    where quoteBaseExps x =
              liftProtectedExp =<< 
                (runIO . evalHOLCtxt (liftM (protect ctxt) $ toHTm x) $ ctxt)
          nothing _ = fail "quoting here not supported"

{-| 
  An instance of 'baseQuoter' for the core theory context, 'ctxtBase'.
  Example:

  > [base| x = y |]

  will parse the provided string and construct the 'HOLTerm' @x = y@ at compile
  time.  Note that this term is protected, such that it has to be accessed via
  'serve'.  This is advantageous in computations that may be run many times, 
  for example:

  > do tm <- serve [base| x = y |]
  >    ...

  will parse the term exactly once, only checking the @thry@ tag of the
  computation for each evaluation.  Conversely,

  > do tm <- toHTm "x = y"
  >    ...

  will parse the term for every evaluation of that computation.  Generally, the
  use of 'toHTm' is reserved for run time parsing and in larger computations
  that themselves are evaluated at copmile time to minimize the amount of work
  Template Haskell has to do.
-}
base :: QuasiQuoter
base = baseQuoter ctxtBase

{-|
  This is a specialized quasi-quoter for 'String's.  It can be used to strip
  white space and automatically escape special characters.  It is typically used
  in conjunction with 'toHTm' directly or indirectly.
-}
str :: QuasiQuoter
str = QuasiQuoter quoteStrExp nothing nothing nothing
    where quoteStrExp x = lift $ trim x
          trim = dropWhile isSpace . dropWhileEnd isSpace
          nothing _ = fail "quoting here not supported"