-- | The combinators of this library are all pairs of functions going in
-- opposite directions. These pairs are called /cassettes/, sporting two tracks
-- (the two functions), one of which is read in one direction, the other of
-- which (accessed by flipping the cassette) is read in the opposite direction.
--
-- = __Example__
--
-- Consider the data type for abstract syntax trees of the λ-calculus:
--
-- >>> :{
--   type Ident = String
--   data Term where
--     Var :: Ident -> Term
--     Abs :: Ident -> Term -> Term
--     App :: Term -> Term -> Term
--   deriving instance Show Term
--   makePrisms ''Term
-- :}
--
-- Given a few constructor-wrapping prisms (generated by @makePrisms@ from the
-- lens library or otherwise) and lifting them to cassette /leads/ (the
-- definitions are mechanical), ...
--
-- >>> :{
--   varL = prismL _Var
--   absL = prismL _Abs . pairL
--   appL = prismL _App . pairL
-- :}
--
-- ... the concrete syntax for terms of the λ-calculus can be defined
-- as follows:
--
-- >>> :{
--   term :: PP Term
--   term =
--     varL --> ident <>
--     absL --> char '^' . ident . char '.' . optSpace . term <>
--     appL --> parens (term . sepSpace . term)
--   parens p = char '(' . p . char ')'
--   ident = consL --> letter . many alphaNum
-- :}
--
-- From this single specification, we can extract a parser, using
-- 'parse', and also a pretty printer, using 'pretty'.
--
-- >>> parse term "^x. (x x)"
-- Just (Abs "x" (App (Var "x") (Var "x")))
--
-- >>> pretty term (Abs "x" (App (Var "x") (Var "x")))
-- Just "^x. (x x)"
--
-- = Grammar specifications
--
-- Specifications are built from primitive and derived combinators, which affect
-- the input string in some way. For each constructor of each datatype, we need
-- to write a /lead/, which is a pair of a construction function and
-- a destruction function. Leads are pure combinators that do not affect the
-- input string. By convention, we suffix their name with "L". A number of leads
-- for standard data types are defined in the "Text.Cassette.Lead" module.

module Text.Cassette (module X) where

import Prelude hiding ((.))
import Text.Cassette.Char as X
import Text.Cassette.Combinator as X
import Text.Cassette.Lead as X
import Text.Cassette.Number as X
import Text.Cassette.Prim as X

-- $setup
-- >>> :seti -XStandaloneDeriving -XGADTSyntax
-- >>> import Control.Category
-- >>> import Control.Lens.TH