packages feed

antiquoter 0.1.0.0 → 0.1.1.0

raw patch · 5 files changed

+186/−57 lines, 5 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Language.Haskell.AntiQuoter.Base: (<<>>) :: AntiQuoter q -> AntiQuoter q -> AntiQuoter q
+ Language.Haskell.AntiQuoter.Base: noAntiQuoter :: AntiQuoter q

Files

antiquoter.cabal view
@@ -1,17 +1,19 @@ name:           antiquoter-version:        0.1.0.0+version:        0.1.1.0 synopsis:       Combinator library for quasi- and anti-quoting. description:    A combinator library to improve the building of anti-quoters.-                Especially aimed at making user extensible antiquoters and-                removing copy-and-paste programming from their definition.+                Especially aimed at removing copy-and-paste programming from+                their definition. Other antiquoting related features could be+                included in the future.                 .                 The modules are                 .-                * "Language.Haskell.AntiQuoter.Base" basic type aliases for-                  building antiquoters.+                * "Language.Haskell.AntiQuoter.Base" basic types for building+                   antiquoters. It also contains the most detailed example of+                   the basic usage.                 .                 * "Language.Haskell.AntiQuoter.ExpPat" making antiquoters which-                  can result in expressions as well as patters. Therefore only+                  can antiquote both expressions and patters. Therefore only                   one antiquoter has to be defined in stead of two.                 .                 * "Language.Haskell.AntiQuoter.Combinators" more useful@@ -28,7 +30,7 @@ build-type:     Simple  cabal-version:  >=1.8-tested-with:    GHC == 7.4.1, GHC == 7.6.2+tested-with:    GHC==7.4.1, GHC==7.6.2  library   exposed-modules:
src/Language/Haskell/AntiQuoter.hs view
@@ -1,3 +1,5 @@+{- | Simple reexport of all modules hiding the exports marked as internal.+-} module Language.Haskell.AntiQuoter (      module Language.Haskell.AntiQuoter.Base,
src/Language/Haskell/AntiQuoter/Base.hs view
@@ -1,17 +1,97 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE RankNTypes #-}--- | Base module for `AntiQuoter`s, which transform parsed syntax into--- template-haskell syntax to make `QuasiQuoter`s.+{- | Base module for `AntiQuoter`s, defining some basic type-aliases and and+combinators for antiquoting.++To for examples in the documentation of this library the following data+types defining the untyped lambda calculus syntax:++@+data Expr+    = VarE Var+    | Lam  Var Expr+    | App  Expr Expr+    | AntiExpr String+    deriving (Typeable, Data)+data Var+    = Var     String+    | AntiVar String+    deriving (Typeable, Data)+@++(note: the idea for using lambda calculus comes from the original paper on+quasi-quoting <http://www.eecs.harvard.edu/~mainland/ghc-quasiquoting/mainland07quasiquoting.pdf>)++A simple quasi-quoter without support for antiquoting can be defined by:++@+lExp = QuasiQuoter+    { quoteExp  = dataToExpQ (const Nothing) . parseExpr+    , quotePat  = dataToPatQ (const Nothing) . parseExpr+    , quoteType = error \"No type quoter\"+    , quoteDec  = error \"No declaration quoter\"+    }+parseExpr :: String -> Expr+parseExpr = undefined -- implementation omitted+@++Now to add antiquoting it is needed to treat the AntiExpr and AntiVar+constructors as special and translate them ourselves. This introduces an+@`AntiQuoterPass` e p@, which is a specific translation rule from source syntax+@e@ to template haskell type @p@. In the example this can be used to defined:++@+antiExprE :: AntiQuoterPass Expr Exp+antiExprE (AntiExpr s) = Just . varE $ mkName s+antiExprE _            = Nothing+antiVarE :: AntiQuoterPass Var Exp+antiVarE (AntiVar s) = Just . varE $ mkName s+antiVarE _           = Nothing++antiExprP :: AntiQuoterPass Expr Pat+antiExprP (AntiExpr s) = Just . varP $ mkName s+antiExprP _            = Nothing+antiVarP :: AntiQuoterPass Var Pat+antiVarP (AntiVar s) = Just . varP $ mkName s+antiVarP _           = Nothing+@++Both rules should be used when antiquoting as an exception to the base case+(using the default translation, @const Nothing@). Which can be done using+@(`<>>`)@, creating an `AntiQuoter`. Where an `AntiQuoter` represents a+combination of `AntiQuoterPass`es which can be used to antiquote multiple+datatypes. In the example this would result in++@+lExp = QuasiQuoter+    { quoteExp  = dataToExpQ antiE . parseExpr+    , quotePat  = dataToPatQ antiP . parseExpr+    , quoteType = error \"No type quoter\"+    , quoteDec  = error \"No declaration quoter\"+    }+    where+        antiE :: AntiQuoter Exp+        antiE = antiExprE \<>> antiVarE \<>> const Nothing+        antiP :: AntiQuoter Pat+        antiP = antiExprP \<>> antiVarP \<>> const Nothing+@++Two little improvements could be made, @const Nothing@ could be replaced by+`noAntiQuoter` and the building of the `QuasiQuoter` could be simplified by+using `mkQuasiQuoter`.+-} module Language.Haskell.AntiQuoter.Base(     -- * AntiQuoters     AntiQuoterPass,     AntiQuoter,-    mkQuasiQuoter,     AQResult,-    fromPass, (<<>), (<>>),+    -- ** Using AntiQuoters+    mkQuasiQuoter,+    fromPass,+    noAntiQuoter, (<<>>),+    (<<>), (<>>),     -- ** Convenience reexport     -- | WARNING: when combining AntiQuoter(Pass)es using `extQ` only the-    -- WARNING: when combining AntiQuoter(Pass)es using `extQ` only the     -- last (rightmost) pass will be used for any source type. The `<<>`     -- and `<>>` don't suffer from this problem.     extQ,@@ -24,37 +104,66 @@ import Language.Haskell.TH import Language.Haskell.TH.Quote -infixl 1 <<>+infixl 1 <<>,<<>> infixr 2 <>> --- | Result of an `AntiQuoterPass`+-- | A single antiquotation for a specific source type. Usually @e@ is a type+-- from the parsed language and @q@ is the target type (usually `Pat` or+-- `Exp`). A @Just result@ indicates that the input should be antiquoted into+-- @result@ while @Nothing@ indicates that there is no special antiquotation.+type AntiQuoterPass e q = e -> Maybe (Q q)+-- Note, `AQResult` is not used as that would lead to too unclear code and+-- documentation.++-- | Result of an `AntiQuoterPass` (AntiQuoterPass e q = e -> AQResult q).+-- This type-alias is mostly used for combinators which only provides the+-- result of the antiquotation and the usecase (thus the pattern to match)+-- should be filled in by the user.+--+-- See `AntiQuoterPass` on what @Nothing@ and @Just@ mean. type AQResult q = Maybe (Q q)  -- | Wrapper for `AQResult`, needed for the typechecker. newtype WrappedAQResult q = AQRW { unAQRW :: AQResult q } --- | A single quotation pass possibly transforming an @e@ into a @q@.-type AntiQuoterPass e q = e -> Maybe (Q q) --- | An `AntiQuoter` is the combination of several `AntiQuoterPass`es, trying--- each of them in order until one passes.+-- | An `AntiQuoter` is the combination of several `AntiQuoterPass`es, which+-- could have different source types. In the example the+-- @AntiQuoterPass Expr Exp@ and @AntiQuoterPass Var Exp@ were combined into+-- a single @AntiQuoter Exp@, which antiquoted both @Expr@ and @Pat@. type AntiQuoter q = forall e. Typeable e => AntiQuoterPass e q  -- | Create an `AntiQuoter` from an single pass. fromPass :: Typeable e => AntiQuoterPass e q -> AntiQuoter q fromPass aqp = mkQ Nothing aqp --- | Combine an existing `AntiQuoter` with an extra pass, where the extra pass--- is tried if the current quoter fails.+-- | An `AnitQuoter` that does no antiquoting by only return Nothing,+--+-- > noAntiQuoter = const Nothing+--+noAntiQuoter :: AntiQuoter q+noAntiQuoter = const Nothing++-- | Create an `AntiQuoter` by combining an `AntiQuoter` and an+-- `AntiQuoterPass`. This is left biased, see (`<<>>`). (<<>) :: Typeable e => AntiQuoter q -> AntiQuoterPass e q -> AntiQuoter q-aq <<> aqp = \e -> aq e `mplus` fromPass aqp e--- | Like `<>>` with flipped arguments, but also trying the extra pass before--- the quoter.+aq <<> aqp = aq <<>> fromPass aqp+-- | Create an `AntiQuoter` by combining an `AntiQuoterPass` and an+-- `AntiQuoter`. This is left biased, see (`<<>>`). (<>>) :: Typeable e => AntiQuoterPass e q -> AntiQuoter q -> AntiQuoter q-aqp <>> aq = \e -> fromPass aqp e `mplus` aq e+aqp <>> aq = fromPass aqp <<>> aq +-- | Combines two `AntiQuoter`s with the same result. It is left biased, thus+-- if the first antiquoter returns @Just result@ that is used, otherwise the+-- second AntiQuoter is tried.+-- Together with `noAntiQuoter` this forms a monoid, but as AntiQuoter is a+-- type synonyme no instance is declared.+(<<>>) :: AntiQuoter q -> AntiQuoter q -> AntiQuoter q+aq1 <<>> aq2 = \e -> aq1 e `mplus` aq2 e+ -- | Create an QuasiQuoter for expressions and patterns from a parser and two--- antiquoters.+-- antiquoters. The quasiquoter from the example could also have been+-- constructed by using @mkQuasiQuoter (return . parse) antiE antiP @. mkQuasiQuoter :: Data a     => (String -> Q a)     -> AntiQuoter Exp
src/Language/Haskell/AntiQuoter/Combinators.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE RankNTypes #-}--- | Several combinators for `AntiQuoters`.+-- | Several combinators for `AntiQuoters`, mainly `EP` related. module Language.Haskell.AntiQuoter.Combinators(     -- * Lifted constructors.     varQ, conQ, litQ, tupQ, listQ,@@ -16,17 +16,22 @@ import Language.Haskell.AntiQuoter.Base import Language.Haskell.AntiQuoter.ExpPat +-- | Generalized `varE`/`varP`. varQ :: EP q => Name -> Q q varQ = return . var +-- | Generalized `conP` or combination of `conE` and `appE`. conQ :: EP q => Name -> [Q q] -> Q q conQ n = fmap (con n) . sequence +-- | Generalized `litE`/`litP`. litQ :: EP q => Lit -> Q q litQ = return . lit  tupQ, listQ :: EP q => [Q q] -> Q q+-- | Generalized `tupE`/`tupP`. tupQ  = fmap tup  . sequence+-- | Generalized `listE`/`listP`. listQ = fmap list . sequence  -- | Uses/Binds a variable of the given name.
src/Language/Haskell/AntiQuoter/ExpPat.hs view
@@ -1,38 +1,48 @@--- | Tools for writing one `AntiQuoter` which can be used for both expressions--- and patterns, thereby reducing copy-and-paste programming.------ For example in the original paper on quasi quoting <http://www.eecs.harvard.edu/~mainland/ghc-quasiquoting/mainland07quasiquoting.pdf>--- antiquoting is demonstrated by defining the following antiquoters:------ @--- antiVarE :: Var -> Maybe ExpQ--- antiVarE (AV v ) = Just $ varE $ mkName v--- antiVarE _ = Nothing--- antiVarP :: Var -> Maybe PatQ--- antiVarP (AV v ) = Just $ varP $ mkName v--- antiVarP _ = Nothing--- @------ and a simmilar pair for antiquoting variables. The problem is that the--- definition for the pattern antiquoter is almost a duplicate of the one for--- expressions. This similarity between antiquoting expressions and patterns--- is captured in the `EP` class which can be used to write antiquoters which--- can yield both expressions and patterns. Using the combinators defined on--- top of this class (see "Language.Haskell.AntiQuoter.Combinators") the--- example can be rewritten as------ @--- antiVar :: EP q => Var ->  Maybe (Q q) -- equivalent to antiVar :: EPAntiQuoterPass Var--- antiVar (AV v) = Just $ varQ $ mkName v--- antiVar _      = Nothing--- @- {-# LANGUAGE RankNTypes #-}+{- | `Exp` and `Pat` are for most part used in simmilar fashion. Most+AntiQuoter(Pass)es have to be written for both datatypes and their+implementation is more or less identical in structure. To reduce copy-and-paste+programming it would be best if it would only need one AntiQuoter(Pass) that+works on both `Exp` and `Pat`.++This module defines the `EP` typeclass expressing the similarity between `Exp`+and `Pat` and some basic functions to use them with `AntiQuoterPass`es. The+"Language.Haskell.AntiQuoter.Combinators" defines the combinator functions on+top of these functions, which are probably more suitable for users.+++As an example of the problem take the antiquoters in+"Language.Haskell.AntiQuoter.Base" where there are two AntiQuoterPasses for+each source type, for Var they are++@+antiVarE :: AntiQuoterPass Var Exp+antiVarE (AV v ) = Just $ varE $ mkName v+antiVarE _ = Nothing+antiVarP :: AntiQuoterPass Var Pat+antiVarP (AV v ) = Just $ varP $ mkName v+antiVarP _ = Nothing+@++The problem is that the definition for the pattern antiquoter is almost a+duplicate of the one for expressions. This similarity between antiquoting+expressions and patterns is captured in the `EP` class which can be used to+write antiquoters which an yield both expressions and patterns. Using the+combinators defined on top of this class (see+"Language.Haskell.AntiQuoter.Combinators") the example can be rewritten as++@+antiVar :: EP q => AntiQuoterPass Var q -- equivalent to antiVar :: EPAntiQuoterPass Var+antiVar (AV v) = Just $ varQ $ mkName v+antiVar _      = Nothing+@+-} module Language.Haskell.AntiQuoter.ExpPat (      -- * Template syntax class     EP(..), EPAntiQuoter, EPAntiQuoterPass,     mkEPQuasiQuoter,+    -- ** Low level functions used when the result for `Exp` and `Pat` differs.     epPass, epPass', epPass'',     epResult, epValue, epPure, @@ -78,12 +88,13 @@     -> QuasiQuoter mkEPQuasiQuoter parse aq = mkQuasiQuoter parse aq aq --- | An `AntiQuoter` that works for `Exp` and `Pat`s.+-- | An `AntiQuoter` that works for `Exp` and `Pat` results. type EPAntiQuoter       = forall q. EP q => AntiQuoter q+-- | An `AntiQuoterPass` that works for `Exp` and `Pat` results. type EPAntiQuoterPass e = forall q. EP q => AntiQuoterPass e q  -- | Combine two `AntiQuoterPass`es, one for expression context and another for--- pattern context, into a single pass for an expression of patter context.+-- pattern context, into a single pass which can be used in both contexts. epPass :: Typeable e => AntiQuoterPass e Exp -> AntiQuoterPass e Pat     -> EPAntiQuoterPass e epPass pe pp = \e -> epResult (pe e) (pp e)