{-# Language TemplateHaskell #-}

-- | The core subset of the libary interface. "Data.Ruin" offers more.
--
-- The basic idea of this module is that anonymous records are only
-- used to emulate named function arguments. Thus, this module
-- provides very little in the way of creating records; it expects
-- that you'll declare and build your record types as usual.
--
-- The most solid use case for this module is a data type for parsing
-- the command-line.
--
-- [Step 1] Define a record type for each command.
--
-- [Step 2] Define a sum type where each constructor contains only the
-- corresponding command record type.
--
-- [Step 3] Define a command-line parser for each record type using
-- 'rtoA'.
--
-- [Step 4] Combine those parser using 'rupA'.

module Data.Ruin.Core (
  -- * Records
  (:@),
  dub,
  undub,

  -- * Accessing parts of records
  rpat,

  -- * Building records
  Build,
  rna,
  rnaA,

  -- * Pure Combinators
  (<@),
  rfrom,
  rsym,
  rup,

  -- * 'Applicative' Combinators
  rtoA,
  rupA,

  -- * Conveniences

  -- ** Avoid unused selectors
  NoWarnUnusedTopBind(..),

  -- ** Splice
  makeRecords,
  ) where

import Data.Ruin.All
import Data.Ruin.Internal
import Data.Ruin.QQ hiding (rna,rnaA)
import Data.Ruin.QQ.Parser (QQ(..),pQQ)
import Data.Ruin.TH

import qualified Language.Haskell.TH as TH
import           Language.Haskell.TH.Quote (QuasiQuoter(..))
import           Text.Parsec (parse)

-- | 'rna' is like 'rpat', but it also works for expressions. All of
-- the sugar is supported in the dual way.
rna :: QuasiQuoter
rna = QuasiQuoter (pars' expQQ) (pars patQQ) nope nope
  where
  nope = fail "The `rna' quasiquoter only creates expressions or patterns."

-- | 'rnaA' is like 'rna', but it only works for expressions and it
-- only works inside an 'Applicative'.
rnaA :: QuasiQuoter
rnaA = QuasiQuoter (pars' expQQA) nope nope nope
  where
  nope = fail "The `rnaA' quasiquoter only creates expressions."

pars' :: (QQ -> TH.Q a) -> String -> TH.Q a
pars' k s = either (fail . show) k' $ parse pQQ "rna quasiquote" s
  where
  k' qq@(MkQQ Just{} _) = k qq
  k' _ = fail "The Data.Ruin.Core quasiquoters require a typename when used as expressions."