derive-2.6.3/0000755000000000000000000000000013140114216011157 5ustar0000000000000000derive-2.6.3/Setup.hs0000644000000000000000000000005613140114216012614 0ustar0000000000000000import Distribution.Simple main = defaultMain derive-2.6.3/README.md0000644000000000000000000002536013140114216012444 0ustar0000000000000000# Derive [![Hackage version](https://img.shields.io/hackage/v/derive.svg?label=Hackage)](https://hackage.haskell.org/package/derive) [![Build Status](https://img.shields.io/travis/ndmitchell/derive.svg)](https://travis-ci.org/ndmitchell/derive) Data.Derive is a library and a tool for deriving instances for Haskell programs. It is designed to work with custom derivations, SYB and Template Haskell mechanisms. The tool requires GHC, but the generated code is portable to all compilers. We see this tool as a competitor to DrIFT. This document proceeds as follows: * Obtaining and Installing Data.Derive * Supported Derivations * Using the Derive Program * Using Template Haskell Derivations * Writing a New Derivation ### Acknowledgements Thanks to everyone who has submitted patches and given assistance, including: Twan van Laarhoven, Spencer Janssen, Andrea Vezzosi, Samuel Bronson, Joel Raymont, Benedikt Huber, Stefan O'Rear, Robin Green, Bertram Felgenhauer. ## Obtaining and Installing Data.Derive Installation follows the standard pattern of any Haskell library or program, type cabal update to update your local hackage database, then cabal install derive to install Derive. ## Supported Derivations Data.Derive is not limited to any prebuild set of derivations, see later for howto add your own. Out of the box, we provide instances for the following libraries. * **[Arbitrary](http://hackage.haskell.org/packages/archive/QuickCheck/latest/doc/html/Test-QuickCheck.html#t%3AArbitrary)** - from the library [QuickCheck](http://hackage.haskell.org/package/QuickCheck) * **[ArbitraryOld](http://hackage.haskell.org/packages/archive/QuickCheck/1.2.0.0/doc/html/Test-QuickCheck.html#t%3AArbitraryOld)** - from the library [QuickCheck-1.2.0.0](http://hackage.haskell.org/package/QuickCheck-1.2.0.0) * **[Arities](http://hackage.haskell.org/packages/archive/derive/latest/doc/html/Data-Derive-Class-Arities.html#t%3AArities)** - from the library [derive](http://hackage.haskell.org/package/derive) * **[Binary](http://hackage.haskell.org/packages/archive/binary/latest/doc/html/Data-Binary.html#t%3ABinary)** - from the library [binary](http://hackage.haskell.org/package/binary) * **[BinaryDefer](http://hackage.haskell.org/packages/archive/binarydefer/latest/doc/html/Data-Binary-Defer.html#t%3ABinaryDefer)** - from the library [binarydefer](http://hackage.haskell.org/package/binarydefer) * **[Bounded](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#t%3ABounded)** - from the library [base](http://hackage.haskell.org/package/base) * **[DataAbstract](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Data.html#t%3ADataAbstract)** - from the library [base](http://hackage.haskell.org/package/base) * **[Default](http://hackage.haskell.org/packages/archive/derive/latest/doc/html/Data-Derive-Class-Default.html#t%3ADefault)** - from the library [derive](http://hackage.haskell.org/package/derive) * **[EnumCyclic](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#t%3AEnum)** - from the library [base](http://hackage.haskell.org/package/base) * **[Fold](http://hackage.haskell.org/packages/archive/derive/latest/doc/html/Data-Derive-Fold.html)** * **[From](http://hackage.haskell.org/packages/archive/derive/latest/doc/html/Data-Derive-From.html)** * **[Has](http://hackage.haskell.org/packages/archive/derive/latest/doc/html/Data-Derive-Has.html)** * **[Is](http://hackage.haskell.org/packages/archive/derive/latest/doc/html/Data-Derive-Is.html)** * **[JSON](http://hackage.haskell.org/packages/archive/json/latest/doc/html/Text-JSON.html#t%3AJSON)** - from the library [json](http://hackage.haskell.org/package/json) * **[LazySet](http://hackage.haskell.org/packages/archive/derive/latest/doc/html/Data-Derive-LazySet.html)** * **[Lens](http://hackage.haskell.org/packages/archive/data/lens/doc/html/Data-Lens-Common.html#t%3ALens)** - from the library [data-lens](http://hackage.haskell.org/package/data-lens) * **[Monoid](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Monoid.html#t%3AMonoid)** - from the library [base](http://hackage.haskell.org/package/base) * **[NFData](http://hackage.haskell.org/packages/archive/deepseq/latest/doc/html/Control-DeepSeq.html#t%3ANFData)** - from the library [deepseq](http://hackage.haskell.org/package/deepseq) * **[Ref](http://hackage.haskell.org/packages/archive/derive/latest/doc/html/Data-Derive-Ref.html)** * **[Serial](http://hackage.haskell.org/packages/archive/smallcheck/latest/doc/html/Test-SmallCheck.html#t%3ASerial)** - from the library [smallcheck](http://hackage.haskell.org/package/smallcheck) * **[Serialize](http://hackage.haskell.org/packages/archive/cereal/latest/doc/html/Data-Serialize.html#t%3ASerialize)** - from the library [cereal](http://hackage.haskell.org/package/cereal) * **[Set](http://hackage.haskell.org/packages/archive/derive/latest/doc/html/Data-Derive-Set.html)** * **[UniplateDirect](http://hackage.haskell.org/packages/archive/uniplate/latest/doc/html/Data-Generics-Uniplate-Direct.html#t%3AUniplateDirect)** - from the library [uniplate](http://hackage.haskell.org/package/uniplate) * **[UniplateTypeable](http://hackage.haskell.org/packages/archive/uniplate/latest/doc/html/Data-Generics-Uniplate-Typeable.html#t%3AUniplateTypeable)** - from the library [uniplate](http://hackage.haskell.org/package/uniplate) * **[Update](http://hackage.haskell.org/packages/archive/derive/latest/doc/html/Data-Derive-Update.html)** ## Using the Derive program Let's imagine we've defined a data type: data Color = RGB Int Int Int | CMYK Int Int Int Int deriving (Eq, Show) Now we wish to extend this to derive Binary and change to defining Eq using our library. To do this we simply add to the deriving clause. data Color = RGB Int Int Int | CMYK Int Int Int Int deriving (Show {-! Eq, Binary !-}) Or alternatively write: {-! deriving instance Eq Color deriving instance Binary Color !-} Now running derive on the program containing this code will generate appropriate instances. How do you combine these instances back into the code? There are various mechanisms supported. ### Appending to the module One way is to append the text to the bottom of the module, this can be done by passing the --append flag. If this is done, Derive will generate the required instances and place them at the bottom of the file, along with a checksum. Do not modify these instances. ### As a GHC preprocessor To use Derive as a GHC preprocessor, add the following line at the top of the source file: {-# OPTIONS_GHC -F -pgmFderive -optF-F #-} This instructs GHC to apply a preprocessor (-F), and to use the preprocessor derive -F. ### Using CPP One way is to use CPP. Ensure your compiler is set up for compiling with the C Pre Processor. For example: {-# LANGUAGE CPP #-} {-# OPTIONS_DERIVE --output=file.h #-} module ModuleName where #include "file.h" ### Side-by-side Modules If you had Colour.Type, and wished to place the Binary instance in Colour.Binary, this can be done with: {-# OPTIONS_DERIVE --output=Binary.hs --module=Colour.Binary --import #-} Here you ask for the output to go to a particular file, give a specific module name and import this module. This will only work if the data structure is exported non-abstractly. ## Using Template Haskell Derivations One of Derive's advantages over DrIFT is support for Template Haskell (abbreviated TH). Derive can be invoked automatically during the compilation process, and transparently supports deriving across module boundaries. The main disadvantage of TH-based deriving is that it is only portable to compilers that support TH; currently that is GHC only. To use the TH deriving system, with the same example as before: {-# LANGUAGE TemplateHaskell #-} import Data.DeriveTH import Data.Binary data Color = RGB Int Int Int | CMYK Int Int Int Int deriving (Show) $( derive makeEq ''Color ) $( derive makeBinary ''Color ) We need to tell the compiler to insert the instance using the TH splice construct, $( ... ) (the spaces are optional). The splice causes the compiler to run the function derive (exported from Data.DeriveTH), passing arguments makeFooBar and ''Color. The second argument deserves more explanation; it is a quoted symbol, somewhat like a quoted symbol in Lisp and with deliberately similar syntax. (Two apostrophes are used to specify that this name is to be resolved as a type constructor; just 'Color would look for a data constructor named Color.) ## Writing a New Derivation There are two methods for writing a new derivation, guessing or coding. The guessing method is substantially easier if it will work for you, but is limited to derivations with the following properties: * Inductive - each derivation must be similar to the previous one. Binary does not have this property as a 1 item derivation does not have a tag, but a 2 item derivation does. * Not inductive on the type - it must be an instance for the constructors, not for the type. Typeable violates this property by inducting on the free variables in the data type. * Not type based - the derivation must not change based on the types of the fields. Play and Functor both behave differently given differently typed fields. * Not record based - the derivation must not change on record fields. Show outputs the fields, so this is not allowed. If however your instance does meet these properties, you can use derivation by guess. Many instances do meet these conditions, for examples see: Eq, Ord, Data, Serial etc. If however you need to code the derivation manually see examples such as Update and Functor. ### Modifying Derive The standard sequence for testing Derive is: $ ghci Main.hs :main --generate :reload :main --test The `--generate` option will automatically generate DSL's for derivations derived by example. The `--test` option runs all test comparisons and then loads the file with Template Haskell. ### Coding a new derivation My best suggestion, start with a similar instance, i.e. to make `Eq2` from `Eq` do: * Copy `Data/Derive/Eq.hs` to `Data/Derive/Eq2.hs` * Rename some of the bits in `Eq2.hs` from `Eq` * `ghci` -- load derive * `:main` --generate -- this adds Eq2.hs to the .cabal/All.hs files etc * `:reload` -- reload with Eq2.hs Now fix up `Eq2.hs` appropriately. derive-2.6.3/Main.hs0000644000000000000000000000016613140114216012402 0ustar0000000000000000 module Main(main) where import Data.Derive.All import Data.DeriveMain main :: IO () main = deriveMain derivations derive-2.6.3/LICENSE0000644000000000000000000000276413140114216012175 0ustar0000000000000000Copyright Neil Mitchell 2006-2017. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Neil Mitchell nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. derive-2.6.3/derive.cabal0000644000000000000000000000625013140114216013424 0ustar0000000000000000cabal-version: >= 1.18 build-type: Default name: derive version: 2.6.3 build-type: Simple copyright: Neil Mitchell 2006-2017 author: Neil Mitchell maintainer: Neil Mitchell homepage: https://github.com/ndmitchell/derive#readme bug-reports: https://github.com/ndmitchell/derive/issues license: BSD3 license-file: LICENSE synopsis: A program and library to derive instances for data types category: Development description: Data.Derive is a library and a tool for deriving instances for Haskell programs. It is designed to work with custom derivations, SYB and Template Haskell mechanisms. The tool requires GHC, but the generated code is portable to all compilers. We see this tool as a competitor to DrIFT. extra-doc-files: README.md CHANGES.txt tested-with: GHC==8.2.1, GHC==8.0.2, GHC==7.10.3, GHC==7.8.4, GHC==7.6.3 source-repository head type: git location: https://github.com/ndmitchell/derive.git executable derive default-language: Haskell2010 build-depends: base==4.* , derive main-is: Main.hs library default-language: Haskell2010 hs-source-dirs: src build-depends: base == 4.*, filepath, syb, template-haskell, containers, pretty, directory, process, bytestring, haskell-src-exts >= 1.18 && < 1.20, transformers >= 0.2, uniplate >= 1.5 && < 1.7 exposed-modules: Data.DeriveMain Data.DeriveTH Data.DeriveDSL Data.Derive.All Data.Derive.DSL.Apply Data.Derive.DSL.Derive Data.Derive.DSL.DSL Data.Derive.DSL.HSE Data.Derive.DSL.SYB Data.Derive.Instance.Arities Data.Derive.Class.Arities Data.Derive.Class.Default Language.Haskell Language.Haskell.Convert Language.Haskell.TH.All Language.Haskell.TH.Compat Language.Haskell.TH.Data Language.Haskell.TH.ExpandSynonym Language.Haskell.TH.Helper Language.Haskell.TH.Peephole -- GENERATED START Data.Derive.Arbitrary Data.Derive.ArbitraryOld Data.Derive.Arities Data.Derive.Binary Data.Derive.BinaryDefer Data.Derive.Bounded Data.Derive.DataAbstract Data.Derive.Default Data.Derive.EnumCyclic Data.Derive.Fold Data.Derive.From Data.Derive.Has Data.Derive.Is Data.Derive.JSON Data.Derive.LazySet Data.Derive.Lens Data.Derive.Monoid Data.Derive.NFData Data.Derive.Ref Data.Derive.Serial Data.Derive.Serialize Data.Derive.Set Data.Derive.UniplateDirect Data.Derive.UniplateTypeable Data.Derive.Update -- GENERATED STOP -- Mainly internal but some still people use them -- to implement derivations outside Data.Derive.Internal.Derivation other-modules: Data.Derive.Internal.Instance Data.Derive.Internal.Traversal Derive.Main Derive.Derivation Derive.Flags Derive.Generate Derive.Test Derive.Utils derive-2.6.3/CHANGES.txt0000644000000000000000000000364213140114216012775 0ustar0000000000000000Changelog for Derive 2.6.3 #24, support GHC 8.2 2.6.2 #19, more upgrade bug fixes 2.6.1 #19, allow haskell-src-exts-1.19 2.6 Remove lots of derivations that didn't seem useful (Eq, Show etc) Change to use annotated Haskell syntax trees Require haskell-src-exts-1.18 2.5.26 #17, fix incomplete pattern matches for certain types of data 2.5.25 #14, further GHC 8.0.1 updates 2.5.24 #14, update to GHC 8.0.1 #15, move all the source files under src to speed up building Delete the FixedPpr module, was unused 2.5.23 Require haskell-src-exts-1.17 2.5.22 #7, #8 convert more types from TemplateHaskell 2.5.21 Fix the homepage link 2.5.20 #5, fix regression with higher-kinded constructors becoming context 2.5.19 Support GHC 7.10 2.5.18 #4, fix the read instance for nullary constructors 2.5.17 Upgrade to haskell-src-exts-1.16 Remove GHC 7.2 support 2.5.16 Allow transformers-0.4 and above 2.5.15 Allow haskell-src-exts-1.15.* 2.5.14 #3, support GHC 7.9 2.5.13 #622, turn on more Haskell extensions 2.5.12 Upgrade to haskell-src-exts-1.14.* 2.5.11 Support GHC 7.6 2.5.10 Add derivation for Lens Modify the Typeable derivation to use mkTyCon3 2.5.9 Support the Template Haskell Unpacked constructor 2.5.8 Allow haskell-src-exts-1.13.* 2.5.7 Allow haskell-src-exts-1.12.* 2.5.6 Update the copyright year Allow transformers-0.3.* 2.5.5 #513, allow derive to be run as a preprocessor Improve the documentation for UniplateDirect 2.5.4 #394, allow tuple names in more places Fix error when deriving Binary on "data A = B" 2.5.3 GHC 7.2 compatibility 2.5.2 Relax the dependency on haskell-src-exts to < 1.12 2.5.1 Improve documentation for deriveMain 2.5 #257, add Data.DeriveMain.deriveMain, to allow user derivations 2.4.2 Relax the dependency on haskell-src-exts to < 1.11 Start of changelog derive-2.6.3/src/0000755000000000000000000000000013140114216011746 5ustar0000000000000000derive-2.6.3/src/Language/0000755000000000000000000000000013140114216013471 5ustar0000000000000000derive-2.6.3/src/Language/Haskell.hs0000644000000000000000000002677713140114216015433 0ustar0000000000000000{-# LANGUAGE PatternGuards #-} module Language.Haskell(module Language.Haskell, module Language.Haskell.Exts) where import Language.Haskell.Exts hiding (var,app,binds,paren,FieldDecl) import qualified Language.Haskell.Exts as HSE import Data.List import Data.Generics.Uniplate.Data import Data.Data import Data.Char import Data.Maybe import Control.Arrow infix 1 ? True ? b = const b False ? b = id -- insert explicit foralls foralls :: Type () -> Type () foralls x = TyForall () (Just $ map (UnkindedVar ()) $ nub [y | TyVar _ y <- universe x]) Nothing x tyApps x [] = x tyApps x (y:ys) = tyApps (TyApp () x y) ys fromTyApps (TyTuple _ _ xs) = (tyCon $ "(" ++ replicate (length xs - 1) ',' ++ ")", xs) fromTyApps (TyApp _ x y) = let (a,b) = fromTyApps x in (a, b ++ [y]) fromTyApps (TyList _ x) = (TyCon () $ Special () $ ListCon (), [x]) fromTyApps x = (x, []) fromTyTuple (TyTuple _ _ xs) = xs fromTyTuple x = [x] fromTyParen (TyParen () x) = fromTyParen x fromTyParen x = x fromTyParens = transform fromTyParen tyRoot = prettyPrint . fst . fromTyApps . fromTyParen isTyFun :: Type () -> Bool isTyFun TyFun{} = True isTyFun _ = False isTyParen TyParen{} = True ; isTyParen _ = False fromTyList (TyList _ x) = Just x fromTyList (TyApp _ (TyCon _ (Special _ ListCon{})) x) = Just x fromTyList x = Nothing x ~= y = prettyPrint x == y appP x@App{} y = App () x y appP x y = App () (paren x) (paren y) simplify :: Data a => a -> a simplify = transformBi fDecl . transformBi fMatch . transformBi fPat . transformBi fTyp . transformBi fExp where fExp :: Exp () -> Exp () fExp (App _ op (List _ xs)) | op ~= "length" = Lit () $ Int () (fromIntegral $ length xs) (show $ length xs) | op ~= "head" = head xs | op ~= "null" = con $ show $ null xs fExp (InfixApp _ (Lit _ (Int _ i _)) op (Lit _ (Int _ j _))) | op ~= "-" = Lit () $ Int () (i - j) (show $ i-j) | op ~= "+" = Lit () $ Int () (i + j) (show $ i+j) | op ~= ">" = Con () $ UnQual () $ Ident () $ show $ i > j fExp (InfixApp _ x op y) | op ~= "`const`" = x | op ~= "&&" && y ~= "True" = x | x ~= "id" && op ~= "." = y | y ~= "id" && op ~= "." = x fExp (InfixApp _ (Lit _ (String _ x _)) op (Lit _ (String _ y _))) | op ~= "++" = Lit () $ String () (x ++ y) (show $ x ++ y) fExp (App _ (App _ (App _ flp f) x) y) | flp ~= "flip" = fExp $ appP (fExp $ appP f y) x fExp (App _ (Paren _ x@App{}) y) = fExp $ App () x y fExp (App _ (Paren _ (InfixApp _ x op y)) z) | op ~= "." = fExp $ appP x $ fExp $ appP y z fExp (App _ op x) | op ~= "id" = x fExp (App _ (App _ flp con) x) | flp ~= "flip" && con ~= "const" = var "id" fExp (App _ (App _ con x) y) | con ~= "const" = x fExp (App _ choose (Tuple _ _ [x@(ExpTypeSig _ y _),z])) | choose ~= "choose" && y == z = fExp $ App () (var "return") x fExp (App _ op x) | op ~= "id" = x fExp (InfixApp _ (App _ when true) dot res) | when ~= "when" && true ~= "True" = res fExp (InfixApp _ x y z) | y ~= "++" && z ~= "[]" = x fExp (App _ (LeftSection _ x op) y) = fExp $ InfixApp () x op (paren y) fExp (Paren _ x) | isAtom x = x fExp (Do _ [Qualifier _ x]) = x fExp (Do _ (Qualifier _ (App _ ret unit):xs)) | ret ~= "return" && unit ~= "()" = fExp $ Do () xs fExp (Do _ (Generator _ (PVar _ x) (App _ ret y):xs)) | ret ~= "return" && once x2 xs = simplify $ Do () $ subst x2 y xs where x2 = Var () $ UnQual () x fExp (Case _ (ExpTypeSig _ x@Lit{} _) alts) = fExp $ Case () x alts fExp (Case _ (Lit _ x) alts) | good:_ <- good = good where good = [z | Alt _ (PLit _ Signless{} y) (UnGuardedRhs _ z) Nothing <- alts, y == x] fExp (If _ x t f) | x ~= "True" = t | x ~= "False" = f fExp (App _ (App _ when b) x) | when ~= "when" && b ~= "True" = x | when ~= "when" && b ~= "False" = App () (Var () $ UnQual () $ Ident () "return") (Con () $ Special () $ TupleCon () Boxed 0) fExp (App _ (Paren _ (Lambda _ [PVar _ x] y)) z) | once x2 y = fExp $ subst x2 z y where x2 = Var () $ UnQual () x fExp (App _ (Paren _ (Lambda _ [PWildCard _] x)) _) = x fExp (Lambda s ps x) = Lambda s (minPat x ps) x fExp (Con _ x) = Con () $ rename x fExp x = x fTyp :: Type () -> Type () fTyp (TyApp _ x y) | x ~= "[]" = TyList () y fTyp (TyApp _ (TyCon _ (Special _ ListCon{})) x) = TyList () x fTyp (TyParen _ x@TyCon{}) = x fTyp (TyParen _ x@TyVar{}) = x fTyp (TyParen _ x@TyList{}) = x fTyp (TyCon _ nam) = TyCon () $ rename nam fTyp x = x fPat :: Pat () -> Pat () fPat (PParen _ x@(PApp _ _ [])) = x fPat (PParen _ (PParen _ x)) = PParen () x fPat (PApp _ nam xs) = case rename nam of Special _ (TupleCon _ Boxed _) -> PTuple () Boxed xs nam -> PApp () nam xs fPat (PParen _ (PTuple _ l xs)) = PTuple () l xs fPat x = x fMatch :: Match () -> Match () fMatch (Match sl nam pat (GuardedRhss _ [GuardedRhs _ [Qualifier _ x] bod]) decls) | x ~= "True" = fMatch $ Match sl nam pat (UnGuardedRhs () bod) decls fMatch (Match sl nam [PVar _ x] (UnGuardedRhs _ (Case _ (Var _ (UnQual _ x2)) [Alt _ pat (UnGuardedRhs _ y) Nothing])) decls) | x == x2 = fMatch $ Match sl nam [PParen () pat] (UnGuardedRhs () y) decls fMatch o@(Match a b c d bind) = fBinds (Match a b (minPat o c) d) bind fDecl :: Decl () -> Decl () fDecl (PatBind a b c bind) = fBinds (PatBind a b c) bind fDecl (FunBind _ xs) = FunBind () $ filter (not . isGuardFalse) xs fDecl x = x fBinds context Nothing = context Nothing fBinds context (Just (BDecls _ bind)) | inline /= [] = simplify $ subst (Var () $ UnQual () from) to $ context $ let xs = take i bind ++ drop (i+1) bind in if null xs then Nothing else Just $ BDecls () xs where f (PatBind _ (PVar _ x) (UnGuardedRhs _ bod) Nothing) = [(x,bod)] f (FunBind _ [Match _ x [PVar _ v] (UnGuardedRhs _ (Paren _ (App _ bod (Var _ v2)))) Nothing]) | UnQual () v == v2 = [(x,bod)] f (FunBind _ [Match sl x pat (UnGuardedRhs _ bod) Nothing]) = [(x,Paren () $ Lambda sl pat bod)] f _ = [] (i,from,to) = head inline inline = [(i, x, bod) | (i,b) <- zip [0..] bind, (x,bod) <- f b , isAtom bod || once (Var () $ UnQual () x) (context $ Just $ BDecls () bind)] fBinds a y = a y subst from to = transformBi $ \x -> if x == from then to else x once x y = length (filter (== x) (universeBi y)) <= 1 minPat o ps = transformBi f ps where known = nub [x | UnQual _ x <- universeBi o] f (PVar () x) | x `notElem` known = PWildCard () f (PAsPat () x y) | x `notElem` known = y f x = x isGuardFalse (Match sl nam pat (GuardedRhss _ [GuardedRhs _ [Qualifier _ x] bod]) decls) = x ~= "False" isGuardFalse _ = False rename (UnQual _ (Ident _ ('(':xs@(x:_)))) | x == ',' = Special () $ TupleCon () Boxed $ length xs | x /= ')' = UnQual () $ Symbol () $ init xs rename x = x isAtom Con{} = True isAtom Var{} = True isAtom Lit{} = True isAtom Paren{} = True isAtom _ = False paren x = if isAtom x then x else Paren () x sl = SrcLoc "" 0 0 noSl mr = transformBi (const sl) mr isIdent (x:xs) = isAlpha x || x == '_' title (x:xs) = toUpper x : xs qname = UnQual () . name var = Var () . qname con = Con () . qname tyVar = TyVar () . name tyVarBind = UnkindedVar () . name tyCon = TyCon () . qname pVar = PVar () . name qvop = QVarOp () . UnQual () . Symbol () dataDeclType :: DataDecl -> Type () dataDeclType d = tyApp (tyCon $ dataDeclName d) (map tyVar $ dataDeclVars d) dataDeclFields :: DataDecl -> [String] dataDeclFields = sort . nub . filter (not . null) . map fst . concatMap ctorDeclFields . dataDeclCtors -- A declaration that is either a DataDecl of GDataDecl type DataDecl = Decl () type CtorDecl = Either (QualConDecl ()) (GadtDecl ()) type FieldDecl = [(String, Type ())] type FullDataDecl = (ModuleName (), DataDecl) moduleName (Module _ (Just (ModuleHead _ name _ _)) _ _ _) = name moduleDecls (Module _ _ _ _ decls) = decls moduleImports (Module _ _ _ imps _) = imps modulePragmas (Module _ _ pragmas _ _) = pragmas showDecls x = unlines $ map prettyPrint x tyApp x [] = x tyApp x xs = TyApp () (tyApp x $ init xs) (last xs) tyFun [x] = x tyFun (x:xs) = TyFun () x (tyFun xs) apps x [] = x apps x (y:ys) = apps (App () x y) ys bind :: String -> [Pat ()] -> Exp () -> Decl () bind s p e = binds s [(p,e)] binds :: String -> [([Pat ()], Exp ())] -> Decl () binds n [([],e)] = PatBind () (pVar n) (UnGuardedRhs () e) Nothing binds n xs = FunBind () [Match () (name n) p (UnGuardedRhs () e) Nothing | (p,e) <- xs] isDataDecl :: Decl () -> Bool isDataDecl DataDecl{} = True isDataDecl GDataDecl{} = True isDataDecl _ = False dataDeclName :: DataDecl -> String dataDeclName (DataDecl _ _ _ name _ _) = prettyPrint $ fst $ fromDeclHead name dataDeclName (GDataDecl _ _ _ name _ _ _) = prettyPrint $ fst $ fromDeclHead name fromDeclHead :: DeclHead a -> (Name a, [TyVarBind a]) fromDeclHead (DHead _ n) = (n, []) fromDeclHead (DHInfix _ x n) = (n, [x]) fromDeclHead (DHParen _ x) = fromDeclHead x fromDeclHead (DHApp _ dh x) = second (++[x]) $ fromDeclHead dh fromIParen :: InstRule a -> InstRule a fromIParen (IParen _ x) = fromIParen x fromIParen x = x fromInstHead :: InstHead a -> (QName a, [Type a]) fromInstHead (IHCon _ x) = (x, []) fromInstHead (IHInfix _ t x) = (x, [t]) fromInstHead (IHParen _ x) = fromInstHead x fromInstHead (IHApp l hd t) = second (++ [t]) $ fromInstHead hd dataDeclVars :: DataDecl -> [String] dataDeclVars (DataDecl _ _ _ hd _ _) = map f $ snd $ fromDeclHead hd where f (KindedVar _ x _) = prettyPrint x f (UnkindedVar _ x) = prettyPrint x dataDeclVarsStar :: DataDecl -> [String] dataDeclVarsStar (DataDecl _ _ _ hd _ _) = mapMaybe f $ snd $ fromDeclHead hd where f (UnkindedVar _ x) = Just $ prettyPrint x f (KindedVar _ x (KindStar _)) = Just $ prettyPrint x f _ = Nothing dataDeclArity :: DataDecl -> Int dataDeclArity = length . dataDeclVars dataDeclCtors :: DataDecl -> [CtorDecl] dataDeclCtors (DataDecl _ _ _ _ ctors _) = map Left ctors ctorDeclName :: CtorDecl -> String ctorDeclName = prettyPrint . ctorDeclName' ctorDeclName' :: CtorDecl -> Name () ctorDeclName' (Left (QualConDecl _ _ _ (ConDecl _ name _))) = name ctorDeclName' (Left (QualConDecl _ _ _ (InfixConDecl _ _ name _))) = name ctorDeclName' (Left (QualConDecl _ _ _ (RecDecl _ name _))) = name ctorDeclFields :: CtorDecl -> FieldDecl ctorDeclFields (Left (QualConDecl _ _ _ (ConDecl _ name fields))) = map ((,) "") fields ctorDeclFields (Left (QualConDecl _ _ _ (InfixConDecl _ x1 name x2))) = map ((,) "") [x1,x2] ctorDeclFields (Left (QualConDecl _ _ _ (RecDecl _ name fields))) = [(prettyPrint a, b) | HSE.FieldDecl _ as b <- fields, a <- as] ctorDeclArity :: CtorDecl -> Int ctorDeclArity = length . ctorDeclFields declName :: Decl () -> String declName (DataDecl _ _ _ name _ _) = prettyPrint $ fst $ fromDeclHead name declName (GDataDecl _ _ _ name _ _ _) = prettyPrint $ fst $ fromDeclHead name declName (TypeDecl _ name _) = prettyPrint $ fst $ fromDeclHead name derive-2.6.3/src/Language/Haskell/0000755000000000000000000000000013140114216015054 5ustar0000000000000000derive-2.6.3/src/Language/Haskell/Convert.hs0000644000000000000000000003055413140114216017037 0ustar0000000000000000{-# LANGUAGE CPP, ScopedTypeVariables, MultiParamTypeClasses, TypeSynonymInstances, FlexibleInstances #-} {-# LANGUAGE ViewPatterns #-} module Language.Haskell.Convert(Convert, convert) where import Language.Haskell as HS import qualified Language.Haskell.Exts as HSE(FieldDecl(..)) import Language.Haskell.TH.Compat import Language.Haskell.TH.Syntax as TH import Control.Exception import Data.Typeable import System.IO.Unsafe import Data.Maybe class (Typeable a, Typeable b, Show a, Show b) => Convert a b where conv :: a -> b convert :: forall a b . Convert a b => a -> b convert a = unsafePerformIO $ (return $! (conv a :: b)) `Control.Exception.catch` (\(e :: SomeException) -> error $ msg e) where msg e = "Could not convert " ++ show (typeOf a) ++ " to " ++ show (typeOf (undefined :: b)) ++ "\n" ++ show a ++ "\n" ++ show e appT :: TH.Type -> [TH.Type] -> TH.Type appT = foldl AppT c mr = convert mr instance Convert a b => Convert [a] [b] where conv = map c instance Convert TH.Dec (HS.Decl ()) where conv x = case x of #if __GLASGOW_HASKELL__ >= 800 DataD cxt n vs _ con ds -> f (DataType ()) cxt n vs con ds NewtypeD cxt n vs _ con ds -> f (NewType ()) cxt n vs [con] ds where f :: DataOrNew () -> Cxt -> TH.Name -> [TyVarBndr] -> [Con] -> unused -> HS.Decl () f t cxt n vs con _ = DataDecl () t (Just $ c cxt) (dh (c n) (c vs)) (c con) Nothing #else DataD cxt n vs con ds -> f (DataType ()) cxt n vs con ds NewtypeD cxt n vs con ds -> f (NewType ()) cxt n vs [con] ds where f :: DataOrNew () -> Cxt -> TH.Name -> [TyVarBndr] -> [Con] -> [TH.Name] -> HS.Decl () f t cxt n vs con ds = DataDecl () t (Just $ c cxt) (dh (c n) (c vs)) (c con) Nothing #endif dh name [] = DHead () name dh name xs = DHApp () (dh name $ init xs) (last xs) instance Convert TH.Cxt (HS.Context ()) where conv = CxTuple () . map c instance Convert (Maybe (HS.Context ())) TH.Cxt where conv Nothing = [] conv (Just (CxSingle _ x)) = [c x] conv (Just (CxTuple _ xs)) = map c xs conv (Just (CxEmpty _)) = [] instance Convert TH.Name (HS.TyVarBind ()) where conv = UnkindedVar () . c instance Convert TH.Name (HS.Name ()) where conv x = name $ if '.' `elem` x2 then reverse $ takeWhile (/= '.') $ reverse x2 else x2 where x2 = show x instance Convert TH.Name (HS.QName ()) where conv x = if x2 == Ident () "[]" then Special () $ ListCon () else UnQual () x2 where x2 = c x instance Convert TH.Con (HS.QualConDecl ()) where conv (ForallC vs cxt x) = QualConDecl () (Just $ c vs) (Just $ c cxt) (c x) conv x = QualConDecl () Nothing Nothing (c x) instance Convert TH.Con (HS.ConDecl ()) where conv (NormalC n xs) = ConDecl () (c n) (c xs) conv (RecC n xs) = RecDecl () (c n) [HSE.FieldDecl () [c x] $ c (y,z) | (x,y,z) <- xs] conv (InfixC x n y) = InfixConDecl () (c x) (c n) (c y) instance Convert TH.StrictType (HS.Type ()) where #if __GLASGOW_HASKELL__ >= 800 conv (Bang SourceUnpack SourceStrict, x) = TyBang () (BangedTy ()) (Unpack ()) $ c x conv (Bang SourceUnpack _, x) = TyBang () (NoStrictAnnot ()) (Unpack ()) $ c x conv (Bang _ SourceStrict, x) = TyBang () (BangedTy ()) (NoUnpack ()) $ c x conv (Bang _ _, x) = c x #else conv (IsStrict, x) = TyBang () (BangedTy ()) (NoUnpack ()) $ c x conv (NotStrict, x) = c x #if __GLASGOW_HASKELL__ >= 704 conv (Unpacked, x) = TyBang () (BangedTy ()) (Unpack ()) $ c x #endif #endif instance Convert TH.Type (HS.Type ()) where conv (ForallT xs cxt t) = TyForall () (Just $ c xs) (Just $ c cxt) (c t) conv (VarT x) = TyVar () $ c x conv (ConT x) | ',' `elem` show x = TyTuple () Boxed [] | otherwise = TyCon () $ c x conv (AppT (AppT ArrowT x) y) = TyFun () (c x) (c y) conv (ArrowT) = TyCon () $ Special () $ FunCon () conv (AppT ListT x) = TyList () $ c x conv (ListT) = TyCon () $ Special () $ ListCon () conv (TupleT _) = TyTuple () Boxed [] conv (AppT x y) = case c x of TyTuple _ b xs -> TyTuple () b $ xs ++ [c y] x -> TyApp () x $ c y instance Convert TH.Type (HS.Asst ()) where conv (ConT x) = ClassA () (UnQual () $ c x) [] conv (AppT x y) = case c x of ClassA _ a b -> ClassA () a (b ++ [c y]) instance Convert (HS.Decl ()) TH.Dec where conv (InstDecl _ _ (fromIParen -> IRule _ _ cxt (fromInstHead -> (nam,typ))) ds) = instanceD (c cxt) (c $ tyApp (TyCon () nam) typ) [c d | InsDecl _ d <- fromMaybe [] ds] conv (FunBind _ ms@(HS.Match _ nam _ _ _:_)) = FunD (c nam) (c ms) conv (PatBind _ p bod ds) = ValD (c p) (c bod) (c ds) conv (TypeSig _ [nam] typ) = SigD (c nam) (c $ foralls typ) #if __GLASGOW_HASKELL__ >= 800 -- ! certainly BROKEN because it ignores contexts conv (DataDecl _ DataType{} ctx (fromDeclHead -> (nam, typ)) cs ds) = DataD (c ctx) (c nam) (c typ) Nothing (c cs) [] -- (c (map fst ds)) conv (DataDecl _ NewType{} ctx (fromDeclHead -> (nam, typ)) [con] ds) = NewtypeD (c ctx) (c nam) (c typ) Nothing (c con) [] -- (c (map fst ds)) #else conv (DataDecl _ DataType{} ctx (fromDeclHead -> (nam, typ)) cs ds) = DataD (c ctx) (c nam) (c typ) (c cs) [] conv (DataDecl _ NewType{} ctx (fromDeclHead -> (nam, typ)) [con] ds) = NewtypeD (c ctx) (c nam) (c typ) (c con) [] #endif instance Convert (HS.QualConDecl ()) TH.Con where conv (QualConDecl _ Nothing Nothing con) = c con conv (QualConDecl _ vs cx con) = ForallC (c $ fromMaybe [] vs) (c cx) (c con) instance Convert (HS.ConDecl ()) TH.Con where conv (ConDecl _ nam typ) = NormalC (c nam) (c typ) conv (InfixConDecl _ l nam r) = InfixC (c l) (c nam) (c r) conv (RecDecl _ nam fs) = RecC (c nam) (concatMap c fs) instance Convert (HSE.FieldDecl ()) [TH.VarStrictType] where conv (HSE.FieldDecl _ names ty) = [(c name, bang, t) | let (bang,t) = c ty, name <- names] instance Convert (HS.Type ()) TH.StrictType where #if __GLASGOW_HASKELL__ >= 800 conv (TyBang _ BangedTy{} _ t) = (Bang NoSourceUnpackedness SourceStrict, c t) #else conv (TyBang _ BangedTy{} _ t) = (IsStrict, c t) #if __GLASGOW_HASKELL__ >= 704 conv (TyBang _ _ Unpack{} t) = (Unpacked, c t) #else conv (TyBang _ _ Unpack{} t) = (IsStrict, c t) #endif #endif #if __GLASGOW_HASKELL__ >= 800 conv t = (Bang NoSourceUnpackedness NoSourceStrictness, c t) #else conv t = (NotStrict, c t) #endif instance Convert ([HS.Name ()],HS.Type ()) [TH.VarStrictType] where conv (names,bt) = [(c name,s,t) | name <- names] where (s,t) = c bt instance Convert (HS.Asst ()) TH.Type where conv (InfixA _ x y z) = c $ ClassA () y [x,z] conv (ClassA _ x y) = appT (ConT $ c x) (c y) instance Convert (HS.Type ()) TH.Type where conv (TyCon _ (Special _ ListCon{})) = ListT conv (TyCon _ (Special _ UnitCon{})) = TupleT 0 conv (TyParen _ x) = c x conv (TyForall _ x y z) = ForallT (c $ fromMaybe [] x) (c y) (c z) conv (TyVar _ x) = VarT $ c x conv (TyCon _ x) = if x ~= "[]" then error "here" else ConT $ c x conv (TyFun _ x y) = AppT (AppT ArrowT (c x)) (c y) conv (TyList _ x) = AppT ListT (c x) conv (TyTuple _ _ x) = appT (TupleT (length x)) (c x) conv (TyApp _ x y) = AppT (c x) (c y) instance Convert (HS.Name ()) TH.Name where conv = mkName . filter (`notElem` "()") . prettyPrint instance Convert (HS.Match ()) TH.Clause where conv (HS.Match _ _ ps bod ds) = Clause (c ps) (c bod) (c ds) instance Convert (HS.Rhs ()) TH.Body where conv (UnGuardedRhs _ x) = NormalB (c x) conv (GuardedRhss _ x) = GuardedB (c x) instance Convert (HS.Exp ()) TH.Exp where conv (Con _ (Special _ UnitCon{})) = TupE [] conv (Var _ x) = VarE (c x) conv (Con _ x) = ConE (c x) conv (Lit _ x) = LitE (c x) conv (App _ x y) = AppE (c x) (c y) conv (Paren _ x) = c x conv (InfixApp _ x y z) = InfixE (Just $ c x) (c y) (Just $ c z) conv (LeftSection _ x y) = InfixE (Just $ c x) (c y) Nothing conv (RightSection _ y z) = InfixE Nothing (c y) (Just $ c z) conv (Lambda _ x y) = LamE (c x) (c y) conv (Tuple _ _ x) = TupE (c x) conv (If _ x y z) = CondE (c x) (c y) (c z) conv (Let _ x y) = LetE (c x) (c y) conv (Case _ x y) = CaseE (c x) (c y) conv (Do _ x) = DoE (c x) conv (EnumFrom _ x) = ArithSeqE $ FromR (c x) conv (EnumFromTo _ x y) = ArithSeqE $ FromToR (c x) (c y) conv (EnumFromThen _ x y) = ArithSeqE $ FromThenR (c x) (c y) conv (EnumFromThenTo _ x y z) = ArithSeqE $ FromThenToR (c x) (c y) (c z) conv (List _ x) = ListE (c x) conv (ExpTypeSig _ x y) = SigE (c x) (c y) conv (RecConstr _ x y) = RecConE (c x) (c y) conv (RecUpdate _ x y) = RecUpdE (c x) (c y) -- Work around bug 3395, convert to do notation instead conv (ListComp _ x y) = CompE $ c $ y ++ [QualStmt () $ Qualifier () x] instance Convert (HS.GuardedRhs ()) (TH.Guard, TH.Exp) where conv (GuardedRhs _ g x) = (conv g, conv x) instance Convert [HS.Stmt ()] TH.Guard where conv xs = PatG $ map conv xs instance Convert (HS.Binds ()) [TH.Dec] where conv (BDecls _ x) = c x instance Convert (Maybe (HS.Binds ())) [TH.Dec] where conv Nothing = [] conv (Just x) = c x instance Convert (HS.Pat ()) TH.Pat where conv (PParen _ x) = c x conv (PLit _ Signless{} x) = LitP (c x) conv (PTuple _ _ x) = TupP (c x) conv (PApp _ x y) = ConP (c x) (c y) conv (PVar _ x) = VarP (c x) conv (PInfixApp _ x y z) = InfixP (c x) (c y) (c z) conv (PIrrPat _ x) = TildeP (c x) conv (PAsPat _ x y) = AsP (c x) (c y) conv (PWildCard{}) = WildP conv (PRec _ x y) = RecP (c x) (c y) conv (PList _ x) = ListP (c x) conv (PatTypeSig _ x y) = SigP (c x) (c y) instance Convert (HS.Literal ()) TH.Lit where conv (Char _ x _) = CharL x conv (String _ x _) = StringL x conv (Int _ x _) = IntegerL x conv (Frac _ x _) = RationalL x conv (PrimInt _ x _) = IntPrimL x conv (PrimWord _ x _) = WordPrimL x conv (PrimFloat _ x _) = FloatPrimL x conv (PrimDouble _ x _) = DoublePrimL x instance Convert (HS.QName ()) TH.Name where conv (UnQual _ x) = c x conv (Qual _ m x) = c (Ident () $ prettyPrint m ++ "." ++ prettyPrint x) conv (Special _ (TupleCon _ Boxed i)) = Name (mkOccName $ "(" ++ replicate (i-1) ',' ++ ")") NameS instance Convert (HS.PatField ()) TH.FieldPat where conv (PFieldPat _ name pat) = (c name, c pat) conv (PFieldPun _ name) = (c name, c $ PVar () $ Ident () $ prettyPrint name) conv (PFieldWildcard _) = error "Can't convert PFieldWildcard" instance Convert (HS.QOp ()) TH.Exp where conv (QVarOp _ x) = c $ Var () x conv (QConOp _ x) = c $ Con () x instance Convert (HS.Alt ()) TH.Match where conv (Alt _ x y z) = TH.Match (c x) (c y) (c z) instance Convert (HS.Stmt ()) TH.Stmt where conv (Generator _ x y) = BindS (c x) (c y) conv (LetStmt _ x) = LetS (c x) conv (Qualifier _ x) = NoBindS (c x) instance Convert (HS.QualStmt ()) TH.Stmt where conv (QualStmt _ x) = c x instance Convert (HS.FieldUpdate ()) TH.FieldExp where conv (FieldUpdate _ x y) = (c x, c y) instance Convert (HS.TyVarBind ()) TH.Name where conv (UnkindedVar _ x) = c x #if __GLASGOW_HASKELL__ >= 612 instance Convert TH.TyVarBndr (HS.TyVarBind ()) where conv (PlainTV x) = UnkindedVar () $ c x conv (KindedTV x y) = KindedVar () (c x) $ c y #if __GLASGOW_HASKELL__ < 706 instance Convert (TH.Kind ()) HS.Kind where conv StarK = KindStar conv (ArrowK x y) = KindFn (c x) $ c y #else instance Convert TH.Kind (HS.Kind ()) where conv StarT = KindStar () conv (AppT (AppT ArrowT x) y) = KindFn () (c x) (c y) #endif #if __GLASGOW_HASKELL__ < 709 instance Convert TH.Pred (HS.Asst ()) where conv (ClassP x y) = ClassA () (UnQual () $ c x) $ c y conv (TH.EqualP x y) = HS.EqualP () (c x) $ c y instance Convert (HS.Asst ()) TH.Pred where conv (ClassA _ x y) = ClassP (c x) $ c y conv (HS.EqualP _ x y) = TH.EqualP (c x) $ c y #endif instance Convert (HS.TyVarBind ()) TH.TyVarBndr where conv (UnkindedVar _ x) = PlainTV $ c x conv (KindedVar _ x y) = KindedTV (c x) $ c y #if __GLASGOW_HASKELL__ < 706 instance Convert (HS.Kind ()) TH.Kind where conv (KindStar _) = StarK conv (KindFn _ x y) = ArrowK (c x) $ c y #else instance Convert (HS.Kind ()) TH.Kind where conv KindStar{} = StarT conv (KindFn _ x y) = AppT (AppT ArrowT (c x)) (c y) #endif #endif derive-2.6.3/src/Language/Haskell/TH/0000755000000000000000000000000013140114216015367 5ustar0000000000000000derive-2.6.3/src/Language/Haskell/TH/Peephole.hs0000644000000000000000000001373113140114216017471 0ustar0000000000000000{-# LANGUAGE PatternGuards #-} {-# OPTIONS_GHC -Wwarn #-} {- Otherwise I get: src/Language/Haskell/TH/Peephole.hs:64:1: warning: Pattern match checker exceeded (2000000) iterations in an equation for ‘peep’. (Use -fmax-pmcheck-iterations=n to set the maximun number of iterations to n) Seriously. Your warning checker is crap. My code is fine. Don't produce warnings about code I can't possibly fix. Especially not by default. -} module Language.Haskell.TH.Peephole(peephole, replaceVar, replaceVars) where import Language.Haskell.TH.Syntax import Language.Haskell.TH.Helper import Data.Generics import Data.Maybe import Data.List import Debug.Trace traceMode = False peephole :: Data a => a -> a peephole = everywhere (mkT peep) . everywhere (mkT peepPat) -- find a given string, and replace it with a particular expression -- must succeed, so crashes readily (deliberately!) replaceVars :: [(Name,Exp)] -> Exp -> Exp replaceVars rep orig = fExp orig where fExp x = case x of VarE y -> fromMaybe x $ lookup y rep ConE _ -> x LitE _ -> x AppE x y -> AppE (fExp x) (fExp y) CaseE x y -> CaseE (fExp x) (map fMatch y) TupE xs -> TupE (map fExp xs) ListE xs -> ListE (map fExp xs) LamE x y -> LamE x (fPat x y) _ | null $ map fst rep `intersect` getNames x -> x _ -> error $ "replaceVar: " ++ show x getNames x = everything (++) ([] `mkQ` f) x where f :: Name -> [Name] f x = [x] fMatch o@(Match pat (NormalB bod) []) = Match pat (NormalB $ fPat [pat] bod) [] -- given these pattern have come into scope -- continue matching on the rest fPat :: [Pat] -> Exp -> Exp fPat pat = replaceVars (filter ((`notElem` used) . fst) rep) where used = concatMap usedPats pat usedPats x = everything (++) ([] `mkQ` f) x where f (VarP x) = [x] f _ = [] replaceVar :: Name -> Exp -> Exp -> Exp replaceVar name with = replaceVars [(name,with)] -- based on the rewrite combinator in Play peep :: Exp -> Exp peep (ListE xs) | not (null xs) && all (isJust . fromLitChar) xs = peep $ LitE $ StringL $ map (fromJust . fromLitChar) xs where fromLitChar (LitE (CharL x)) = Just x fromLitChar _ = Nothing peep (AppE x y) | x ~= "id" = y peep (AppE (AppE op x) y) | Just res <- peepBin op x y = res peep (InfixE (Just x) op (Just y)) | Just res <- peepBin op x y = res peep (LamE [] x) = x peep (LamE [VarP x] (VarE y)) | x == y = l0 "id" peep (DoE [NoBindS x]) = x peep x@(ConE _) | x ~= "[]" = ListE [] peep (AppE (AppE cons x) nil) | cons ~= ":" && nil ~= "[]" = ListE [x] peep (DoE [BindS (VarP p) (AppE ret (LitE val)),NoBindS e]) | ret ~= "return" = peep $ replaceVar p (LitE val) e peep (LamE [TupP [VarP x, VarP y]] (VarE z)) | x == z = l0 "fst" | y == z = l0 "snd" peep (AppE (LamE (VarP x:xs) y) z) | simple z = peep $ LamE xs (replaceVar x z y) peep (AppE (AppE bind (AppE ret x)) y) | bind ~= ">>=" && ret ~= "return" = peep $ AppE y x peep (InfixE (Just (AppE ret x)) bind (Just y)) | bind ~= ">>=" && ret ~= "return" = peep $ AppE y x peep (InfixE (Just (AppE pure x)) ap y) | ap ~= "<*>" && pure ~= "pure" = peep $ InfixE (Just x) (l0 "<$>") y peep (InfixE (Just x) fmap (Just (AppE pure y))) | fmap ~= "<$>" && pure ~= "pure" = peep $ AppE pure (peep $ AppE x y) peep (AppE append (ListE [x])) | append ~= "++" = peep $ AppE (l0 ":") x peep (InfixE (Just (ListE [x])) append y) | append ~= "++" = peep $ InfixE (Just x) (l0 ":") y peep (InfixE (Just x) cons (Just (ListE xs))) | cons ~= ":" = peep $ ListE (x:xs) peep (AppE (AppE (AppE comp f) g) x) | comp ~= "." = peep $ AppE f (peep $ AppE g x) peep (AppE (InfixE (Just f) comp (Just g)) x) | comp ~= "." = peep $ AppE f (peep $ AppE g x) peep (AppE (AppE (AppE flip f) x) y) | flip ~= "flip" = peep $ AppE (AppE f y) x peep (AppE (InfixE (Just x) op Nothing) y) = peep $ InfixE (Just x) op (Just y) peep (AppE (InfixE Nothing op (Just y)) x) = peep $ InfixE (Just x) op (Just y) peep (AppE f (LamE x (ListE [y]))) | f ~= "concatMap" = peep $ AppE (l0 "map") (peep $ LamE x y) peep (AppE f (ListE xs)) | f ~= "head" && not (null xs) = head xs | f ~= "reverse" = ListE $ reverse xs peep (AppE f (TupE [x,y])) | f ~= "choose" && x == y = peep $ AppE (VarE (mkName "return")) x peep (AppE (AppE sq o@(AppE rnf x)) (TupE [])) | sq ~= "seq" && rnf ~= "rnf" = o peep (CaseE (LitE x) (Match (LitP y) (NormalB z) [] : _)) | x == y = z peep (AppE len (ListE xs)) | len ~= "length" = LitE $ IntegerL $ toInteger $ length xs peep (TupE [x]) = x peep (AppE (LamE [pat] x) e) = CaseE e [Match pat (NormalB x) []] peep (AppE (CaseE e [Match p (NormalB x) []]) y) = CaseE e [Match p (NormalB $ peep $ AppE x y) []] -- allow easy flip to tracing mode peep x | traceMode = trace (show x) x peep x = x peepPat :: Pat -> Pat peepPat (ListP xs) | all (\x -> case x of LitP (CharL _) -> True _ -> False) xs = LitP $ StringL $ map (\(LitP (CharL x)) -> x) xs peepPat x = x peepBin :: Exp -> Exp -> Exp -> Maybe Exp peepBin op x y | op ~= "." && x ~= "id" = Just y | op ~= "." && y ~= "id" = Just x | op ~= "&&" && y ~= "True" = Just x | op ~= "const" = Just x | op ~= "map" && x ~= "id" = Just y | op ~= "++" && x ~= "[]" = Just y | op ~= "++" && y ~= "[]" = Just x | op ~= "." && y ~= "id" = Just x | op ~= ">>" && x ~= "return" && y == TupE [] = Just $ l0 "id" | op ~= "$" = Just $ peep $ AppE x y peepBin op (LitE (StringL x)) (LitE (StringL y)) | op ~= "++" = Just $ LitE $ StringL (x++y) peepBin _ _ _ = Nothing (VarE f) ~= x = show f == x (ConE f) ~= x = show f == x (ListE []) ~= "[]" = True _ ~= _ = False simple (VarE _) = True simple (LitE _) = True simple _ = False derive-2.6.3/src/Language/Haskell/TH/Helper.hs0000644000000000000000000001625613140114216017154 0ustar0000000000000000{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-} -- | These small short-named functions are intended to make the -- construction of abstranct syntax trees less tedious. module Language.Haskell.TH.Helper where import Data.Char import Language.Haskell.TH.Syntax import Language.Haskell.TH.Data import Language.Haskell.TH.Compat -- * Special folds for the guessing applyWith, foldl1With, foldr1With :: Exp -> [Exp] -> Exp applyWith join xs = foldl AppE join xs foldl1With join xs = foldr1 (\y x -> AppE (AppE join y) x) xs foldr1With join xs = foldr1 (\y x -> AppE (AppE join x) y) xs -- * Syntax elements -- -- | A simple clause, without where or guards. sclause :: [Pat] -> Exp -> Clause sclause pats body = Clause pats (NormalB body) [] -- | A default clause with N arguments. defclause :: Int -> Exp -> Clause defclause num = sclause (replicate num WildP) -- | A simple Val clause sval :: Pat -> Exp -> Dec sval pat body = ValD pat (NormalB body) [] case' :: Exp -> [(Pat, Exp)] -> Exp case' exp alts = CaseE exp [ Match x (NormalB y) [] | (x,y) <- alts ] (->:) :: String -> Exp -> Exp (->:) nm bdy = LamE [vr nm] bdy -- | We provide 3 standard instance constructors -- instance_default requires C for each free type variable -- instance_none requires no context -- instance_context requires a given context instance_none :: String -> DataDef -> [Dec] -> Dec instance_none = instance_context [] instance_default :: String -> DataDef -> [Dec] -> Dec instance_default n = instance_context [n] n instance_context :: [String] -> String -> DataDef -> [Dec] -> Dec instance_context req cls dat defs = instanceD ctx hed defs where vrs = vars 't' (dataArity dat) hed = l1 cls (lK (dataName dat) vrs) ctx = [typeToPred $ l1 r v | r <- req, v <- vrs] -- | Build an instance of a class for a data type, using the heuristic -- that the type is itself required on all type arguments. simple_instance :: String -> DataDef -> [Dec] -> [Dec] simple_instance cls dat defs = [instance_default cls dat defs] -- | Build an instance of a class for a data type, using the class at the given types generic_instance :: String -> DataDef -> [Type] -> [Dec] -> [Dec] generic_instance cls dat ctxTypes defs = [instanceD ctx hed defs] where vrs = vars 't' (dataArity dat) hed = l1 cls (lK (dataName dat) vrs) ctx = map (typeToPred . l1 cls) ctxTypes -- | Build a type signature declaration with a string name sigN :: String -> Type -> Dec sigN nam ty = SigD (mkName nam) ty -- | Build a fundecl with a string name funN :: String -> [Clause] -> Dec funN nam claus = FunD (mkName nam) claus -- * Pattern vs Value abstraction class Eq nm => NameLike nm where toName :: nm -> Name instance NameLike Name where toName = id instance NameLike String where toName = mkName -- | The class used to overload lifting operations. To reduce code -- duplication, we overload the wrapped constructors (and everything -- else, but that's irrelevant) to work in patterns, expressions, and -- types. class Valcon a where -- | Build an application node, with a name for a head and a -- provided list of arguments. lK :: NameLike nm => nm -> [a] -> a -- | Reference a named variable. vr :: NameLike nm => nm -> a -- | Lift a TH 'Lit' raw_lit :: Lit -> a -- | Tupling tup :: [a] -> a -- | Listing lst :: [a] -> a instance Valcon Exp where lK nm ys = let name = toName nm in case (nameBase name, ys) of ("[]", []) -> ConE name ("[]", xs) -> lst xs ((x:_), args) | isUpper x || x == ':' -> foldl AppE (ConE name) args ((x:_), [a,b]) | isOper x -> InfixE (Just a) (VarE name) (Just b) where isOper x = not (isAlpha x || x == '_') (nm, args) -> foldl AppE (VarE name) args vr = VarE . toName raw_lit = LitE tup = TupE lst = ListE instance Valcon Pat where lK = ConP . toName vr = VarP . toName raw_lit = LitP tup = TupP lst = ListP instance Valcon Type where lK nm = foldl AppT (if bNm == "[]" then ListT else ConT (mkName bNm)) where bNm = nameBase (toName nm) vr = VarT . toName raw_lit = error "raw_lit @ Type" -- XXX work around bug in GHC < 6.10 -- (see http://hackage.haskell.org/trac/ghc/ticket/2358 for details) tup [t] = t tup ts = foldl AppT (TupleT (length ts)) ts lst = error "lst @ Type" -- | Build an application node without a given head app :: Exp -> [Exp] -> Exp app root args = foldl AppE root args -- | This class is used to overload literal construction based on the -- type of the literal. class LitC a where lit :: Valcon p => a -> p instance LitC Integer where lit = raw_lit . IntegerL instance LitC Char where lit = raw_lit . CharL instance LitC a => LitC [a] where lit = lst . map lit instance (LitC a, LitC b) => LitC (a,b) where lit (x,y) = tup [lit x, lit y] instance (LitC a, LitC b, LitC c) => LitC (a,b,c) where lit (x,y,z) = tup [lit x, lit y, lit z] instance LitC () where lit () = tup [] -- * Constructor abstraction dataVars :: DataDef -> [Type] dataVars dat = take (dataArity dat) $ map (VarT . mkName . return) ['a'..] -- | Common pattern: list of a familiy of variables vars :: Valcon a => Char -> Int -> [a] vars c n = map (vrn c) [1 .. n] -- | Variable based on a letter + number vrn :: Valcon a => Char -> Int -> a vrn c n = vr (c : show n) -- | Make a list of variables, one for each argument to a constructor ctv :: Valcon a => CtorDef -> Char -> [a] ctv ctor c = vars c (ctorArity ctor) -- | Make a simple pattern to bind a constructor ctp :: Valcon a => CtorDef -> Char -> a ctp ctor c = lK (ctorName ctor) (ctv ctor c) -- | Reference the constructor itself ctc :: Valcon a => CtorDef -> a ctc = l0 . ctorName -- * Lift a constructor over a fixed number of arguments. l0 :: (NameLike nm, Valcon a) => nm -> a l1 :: (NameLike nm, Valcon a) => nm -> a -> a l2 :: (NameLike nm, Valcon a) => nm -> a -> a -> a l0 s = lK s [] l1 s a = lK s [a] l2 s a b = lK s [a,b] -- * Pre-lifted versions of common operations true, false, nil :: Valcon a => a hNil', hZero' :: Type true = l0 "True" false = l0 "False" nil = l0 "[]" unit = lit () hNil' = l0 "HNil" hZero' = l0 "HZero" id' = l0 "id" cons :: Valcon a => a -> a -> a cons = l2 ":" box :: Valcon a => a -> a return', const' :: Exp -> Exp hSucc' :: Type -> Type box x = cons x nil return' = l1 "return" const' = l1 "const" hSucc' = l1 "HSucc" (==:), (&&:), (++:), (>>=:), (>>:), (.:), ap', (>:) :: Exp -> Exp -> Exp hCons' :: Type -> Type -> Type (==:) = l2 "==" (&&:) = l2 "&&" (++:) = l2 "++" (>>=:) = l2 ">>=" (>>:) = l2 ">>" (.:) = l2 "." (>:) = l2 ">" ap' = l2 "ap" hCons' = l2 "HCons" -- | Build a chain of expressions, with an appropriate terminal -- sequence__ does not require a unit at the end (all others are optimised automatically) (&&::), (++::), (>>::), sequence__, (.::) :: [Exp] -> Exp (&&::) = foldr (&&:) true (++::) = foldr (++:) nil (>>::) = foldr (>>:) (return' unit) (.::) = foldr (.:) id' sequence__ [] = return' unit sequence__ xs = foldr1 (>>:) xs -- | K-way liftM liftmk :: Exp -> [Exp] -> Exp liftmk hd args = foldl ap' (return' hd) args derive-2.6.3/src/Language/Haskell/TH/ExpandSynonym.hs0000644000000000000000000000401113140114216020533 0ustar0000000000000000{-# LANGUAGE PatternGuards #-} -- | Expand type synonyms in data declarations. -- -- This is needed for some type based derivations. module Language.Haskell.TH.ExpandSynonym (expandData) where import Language.Haskell.TH import Language.Haskell.TH.Compat import Language.Haskell.TH.Data import Data.Generics -- | Expand type synonyms in a data declaration expandData :: DataDef -> Q DataDef expandData = everywhereM (mkM expandType) expandType :: Type -> Q Type expandType t = expandType' t [] -- Walk over a type, collecting applied arguments expandType' :: Type -> [Type] -> Q Type expandType' (AppT t arg) args = expandType' t (arg:args) expandType' t@(ConT name) args = do result <- expandSyn name args case result of Just (t',args') -> everywhereM (mkM expandType) $ foldl AppT t' args' _ -> return $ foldl AppT t args expandType' t args = return $ foldl AppT t args -- Is the name a type synonym and are there enough arguments? if so, apply it expandSyn :: Name -> [Type] -> Q (Maybe (Type, [Type])) expandSyn name args = recover (return Nothing) $ do info <- reify name case info of TyConI (TySynD _ synArgs t) | length args >= length synArgs -> return $ Just (substitute (map fromTyVar synArgs) argsInst t, argsMore) -- instantiate type synonym where (argsInst,argsMore) = splitAt (length synArgs) args _ -> return Nothing -- `recover` return Nothing -- Substitute names for types in a type substitute :: [Name] -> [Type] -> Type -> Type substitute ns ts = subst (zip ns ts) where subst s (ForallT ns ctx t) = ForallT ns ctx (subst (filter ((`notElem` (map fromTyVar ns)) . fst) s) t) subst s (VarT n) | Just t' <- lookup n s = t' subst s (AppT a b) = AppT (subst s a) (subst s b) subst _ t = t derive-2.6.3/src/Language/Haskell/TH/Data.hs0000644000000000000000000000724413140114216016603 0ustar0000000000000000 -- | The core module of the Data.Derive system. This module contains -- the data types used for communication between the extractors and -- the derivors. {-# language CPP #-} module Language.Haskell.TH.Data where import Data.Char import Data.Generics import Language.Haskell.TH.Syntax import Language.Haskell.TH.Compat -- must be one of DataD or NewtypeD type DataDef = Dec type CtorDef = Con dataName :: DataDef -> String #if __GLASGOW_HASKELL__ >= 800 dataName (DataD _ name _ _ _ _) = unqualifiedName name dataName (NewtypeD _ name _ _ _ _) = unqualifiedName name #else dataName (DataD _ name _ _ _) = unqualifiedName name dataName (NewtypeD _ name _ _ _) = unqualifiedName name #endif qualifiedDataName :: DataDef -> Name #if __GLASGOW_HASKELL__ >= 800 qualifiedDataName (DataD _ name _ _ _ _) = name qualifiedDataName (NewtypeD _ name _ _ _ _) = name #else qualifiedDataName (DataD _ name _ _ _) = name qualifiedDataName (NewtypeD _ name _ _ _) = name #endif dataArity :: DataDef -> Int #if __GLASGOW_HASKELL__ >= 800 dataArity (DataD _ _ xs _ _ _) = length xs dataArity (NewtypeD _ _ xs _ _ _) = length xs #else dataArity (DataD _ _ xs _ _) = length xs dataArity (NewtypeD _ _ xs _ _) = length xs #endif dataArgs :: DataDef -> [Name] dataArgs = dataDefinitionTypeArgs dataCtors :: DataDef -> [CtorDef] #if __GLASGOW_HASKELL__ >= 800 dataCtors (DataD _ _ _ _ xs _) = xs dataCtors (NewtypeD _ _ _ _ x _) = [x] #else dataCtors (DataD _ _ _ xs _) = xs dataCtors (NewtypeD _ _ _ x _) = [x] #endif ctorName :: CtorDef -> String ctorName (NormalC name _ ) = unqualifiedName name ctorName (RecC name _ ) = unqualifiedName name ctorName (InfixC _ name _) = unqualifiedName name ctorName (ForallC _ _ c ) = ctorName c qualifiedCtorName :: CtorDef -> Name qualifiedCtorName (NormalC name _ ) = name qualifiedCtorName (RecC name _ ) = name qualifiedCtorName (InfixC _ name _) = name qualifiedCtorName (ForallC _ _ c ) = qualifiedCtorName c ctorArity :: CtorDef -> Int ctorArity (NormalC _ xs ) = length xs ctorArity (RecC _ xs ) = length xs ctorArity (InfixC _ _ _ ) = 2 ctorArity (ForallC _ _ c) = ctorArity c ctorStrictTypes :: CtorDef -> [StrictType] ctorStrictTypes (NormalC _ xs ) = xs ctorStrictTypes (RecC _ xs ) = [(b,c) | (a,b,c) <- xs] ctorStrictTypes (InfixC x _ y ) = [x,y] ctorStrictTypes (ForallC _ _ c) = ctorStrictTypes c ctorTypes :: CtorDef -> [Type] ctorTypes = map snd . ctorStrictTypes ctorFields :: CtorDef -> [String] ctorFields (RecC name varStrictType) = [unqualifiedName name | (name,strict,typ) <- varStrictType] ctorFields _ = [] -- normalisation -- make sure you deal with "GHC.Base.." dropModule :: String -> String dropModule xs = case reverse xs of ('.':xs) -> takeWhile (== '.') xs xs -> reverse $ takeWhile (/= '.') xs -- i_123432 -> i dropNumber :: String -> String dropNumber xs = if all isDigit a then reverse (tail b) else xs where (a,b) = break (== '_') $ reverse xs normData :: DataDef -> DataDef normData = everywhere (mkT normType) where normType :: Type -> Type normType (ConT x) | show x == "[]" = ListT normType x = x unqualifiedName :: Name -> String unqualifiedName = dropModule . show -- convert AppT chains back to a proper list typeApp :: Type -> (Type, [Type]) typeApp (AppT l r) = (a, b++[r]) where (a,b) = typeApp l typeApp t = (t, []) eqConT :: String -> Type -> Bool eqConT name (ConT x) = name == show x eqConT _ _ = False isTupleT :: Type -> Bool isTupleT (TupleT _) = True isTupleT (ConT x) = head sx == '(' && last sx == ')' && all (== ',') (take (length sx - 2) (tail sx)) where sx = nameBase x isTupleT _ = False derive-2.6.3/src/Language/Haskell/TH/Compat.hs0000644000000000000000000000305113140114216017145 0ustar0000000000000000{-# LANGUAGE CPP #-} -- | Compatibility definitions to paper over differences between 6.10 and 6.12. module Language.Haskell.TH.Compat where import Language.Haskell.TH #if __GLASGOW_HASKELL__ >= 612 fromTyVar :: TyVarBndr -> Name fromTyVar (PlainTV v) = v fromTyVar (KindedTV v _) = v #else fromTyVar :: Name -> Name fromTyVar v = v #endif #if __GLASGOW_HASKELL__ >= 800 instanceD = InstanceD Nothing #else instanceD = InstanceD #endif dataDefinitionTypeArgs :: Dec -> [Name] #if __GLASGOW_HASKELL__ >= 802 dataDefinitionTypeArgs (DataD _ _ _ _ _ deriv_clauses) = deriv_clauses >>= from_deriv_clause dataDefinitionTypeArgs (NewtypeD _ _ _ _ _ deriv_clauses) = deriv_clauses >>= from_deriv_clause from_deriv_clause :: DerivClause -> [Name] from_deriv_clause (DerivClause _ cxt) = map from_cxt cxt #elif __GLASGOW_HASKELL__ >= 800 dataDefinitionTypeArgs (DataD _cx name _ _ _ cxt) = map from_cxt cxt dataDefinitionTypeArgs (NewtypeD cx name _ _ _ cxt) = map from_cxt cxt #elif __GLASGOW_HASKELL__ >= 612 dataDefinitionTypeArgs (DataD _cx name _ _ args) = args dataDefinitionTypeArgs (NewtypeD cx name _ _ args) = args #else dataDefinitionTypeArgs (DataD _cx name args cons _derv) = args dataDefinitionTypeArgs (NewtypeD cx name args con derv) = args #endif from_cxt :: Type -> Name from_cxt (ConT name) = name #if __GLASGOW_HASKELL__ >= 612 && __GLASGOW_HASKELL__ < 709 typeToPred :: Type -> Pred typeToPred (ConT v) = ClassP v [] typeToPred (AppT x y) = ClassP v (t++[y]) where ClassP v t = typeToPred x #else typeToPred :: Type -> Type typeToPred x = x #endif derive-2.6.3/src/Language/Haskell/TH/All.hs0000644000000000000000000000176613140114216016445 0ustar0000000000000000{-# OPTIONS_GHC -w #-} module Language.Haskell.TH.All ( module Language.Haskell.TH.All, module Language.Haskell.TH.Syntax, module Language.Haskell.TH.Peephole, module Language.Haskell.TH.Helper, module Language.Haskell.TH.Data, module Language.Haskell.TH.ExpandSynonym, ) where import Language.Haskell.TH.Syntax import Language.Haskell.TH.Peephole import Language.Haskell.TH.Helper import Language.Haskell.TH.ExpandSynonym import Language.Haskell.TH.Data import Control.Monad -- | The type of ways to derive classes. -- Should not really be in this module! data Derivation = Derivation { derivationDeriver :: DataDef -> Q [Dec], -- ^ The derivation function proper derivationName :: String -- ^ The name of the derivation } -- create a new derivation more abstractly derivation :: (DataDef -> [Dec]) -> String -> Derivation derivation f = Derivation (return . f) derivationQ :: (DataDef -> Q [Dec]) -> String -> Derivation derivationQ = Derivation derive-2.6.3/src/Derive/0000755000000000000000000000000013140114216013164 5ustar0000000000000000derive-2.6.3/src/Derive/Utils.hs0000644000000000000000000000477213140114216014632 0ustar0000000000000000 module Derive.Utils where import Data.Derive.DSL.HSE import Data.List import qualified Data.ByteString.Char8 as BS import System.Directory import System.IO import System.FilePath import Control.Monad import Data.Maybe data Src = Src {srcName :: String ,srcImport :: [ImportDecl ()] ,srcExample :: Maybe [Decl ()] ,srcTest :: [(Type (),[Decl ()])] ,srcCustom :: Bool } -- skip the importPkg bits srcImportStd :: Src -> [ImportDecl ()] srcImportStd y= [x{importPkg=Nothing} | x <- srcImport y] nullSrc = Src "" [] Nothing [] False readHSE :: FilePath -> IO (Module ()) readHSE file = do src <- readFile' file src <- return $ takeWhile (/= "-}") $ drop 1 $ dropWhile (/= "{-") $ dropWhile (not . isPrefixOf "module ") $ lines src let mode = defaultParseMode{extensions=map EnableExtension [MultiParamTypeClasses,FlexibleContexts,TemplateHaskell,PackageImports,TypeOperators]} return $ fmap (const ()) $ fromParseResult $ parseFileContentsWithMode mode $ unlines $ "module Example where":src data Pragma = Example Bool | Test (Type ()) asPragma :: Decl () -> Maybe Pragma asPragma (TypeSig _ [x] t) | x ~= "example" = Just $ Example $ prettyPrint t == "Custom" | x ~= "test" = Just $ Test t asPragma _ = Nothing readSrc :: FilePath -> IO Src readSrc file = do modu <- readHSE file return $ foldl f nullSrc{srcName=takeBaseName file, srcImport=moduleImports modu} [ (p,xs) | p:real <- tails $ moduleDecls modu, Just p <- [asPragma p] , let xs = takeWhile (isNothing . asPragma) real ] where f src (Example x,bod) = src{srcExample = Just bod, srcCustom = x} f src (Test x,bod) = src{srcTest = srcTest src ++ [(x,bod)]} generatedStart = "-- GENERATED START" generatedStop = "-- GENERATED STOP" writeGenerated :: FilePath -> [String] -> IO () writeGenerated file x = do src <- fmap lines $ readFile' file let pre = takeWhile (/= generatedStart) src post = drop 1 $ dropWhile (/= generatedStop) src src2 = pre ++ [generatedStart] ++ x ++ [generatedStop] ++ post when (src /= src2) $ seq (length src2) $ writeBinaryFile file $ unlines src2 readFile' :: FilePath -> IO String readFile' file = do b <- doesFileExist file if b then fmap BS.unpack $ BS.readFile file else return [] writeBinaryFile :: FilePath -> String -> IO () writeBinaryFile file x = withBinaryFile file WriteMode (`hPutStr` x) rep from to x = if x == from then to else x reps from to = map (rep from to) derive-2.6.3/src/Derive/Test.hs0000644000000000000000000001000013140114216014426 0ustar0000000000000000 module Derive.Test(test) where import Derive.Utils import Data.Derive.DSL.HSE import Control.Monad import Data.Maybe import Data.List import System.FilePath import System.Process import System.Exit import Control.Arrow import Data.Derive.All import Data.Derive.Internal.Derivation -- These overlap with other derivations overlaps = [["BinaryDefer","EnumCyclic","LazySet","DataAbstract"] ,["Serialize"]] -- REASONS: -- UniplateDirect: Doesn't work through Template Haskell -- Typeable cannot be separately derived in GHC 7.8 exclude = ["ArbitraryOld","UniplateDirect","Ref","Serial","Binary","Typeable"] -- These must be first and in every set priority = [] listType :: Decl () listType = DataDecl () (DataType ()) Nothing (DHApp () (DHead () (Ident () "[]")) (UnkindedVar () $ Ident () "a")) [QualConDecl () Nothing Nothing (ConDecl () (Ident () "[]") []) ,QualConDecl () Nothing Nothing (ConDecl () (Ident () "Cons") [TyVar () (Ident () "a") ,TyApp () (TyCon () (UnQual () (Ident () "List"))) (TyVar () (Ident () "a"))])] Nothing -- test each derivation test :: IO () test = do decls <- fmap (filter isDataDecl . moduleDecls) $ readHSE "Data/Derive/Internal/Test.hs" -- check the test bits let ts = ("[]",listType) : map (dataDeclName &&& id) decls mapM_ (testFile ts) derivations -- check the $(derive) bits putStrLn "Type checking examples" let name = "AutoGenerated_Test" devs <- sequence [liftM ((,) d) $ readSrc $ "Data/Derive" derivationName d <.> "hs" | d <- derivations] let lookupDev x = fromMaybe (error $ "Couldn't find derivation: " ++ x) $ find ((==) x . derivationName . fst) devs let sets = zip [1..] $ map (map lookupDev) $ map (priority++) $ [d | d <- map (derivationName . fst) devs, d `notElem` (exclude ++ priority ++ concat overlaps)] : overlaps forM sets $ \(i,xs) -> autoTest (name++show i) decls xs writeFile (name++".hs") $ unlines $ ["import " ++ name ++ show (fst i) | i <- sets] ++ ["main = putStrLn \"Type checking successful\""] res <- system $ "runhaskell -isrc " ++ name ++ ".hs" when (res /= ExitSuccess) $ error "Failed to typecheck results" testFile :: [(String,Decl ())] -> Derivation -> IO () testFile types (Derivation name op) = do putStrLn $ "Testing " ++ name src <- readSrc $ "Data/Derive/" ++ name ++ ".hs" forM_ (srcTest src) $ \(typ,res) -> do let d = if tyRoot typ /= name then tyRoot typ else tyRoot $ head $ snd $ fromTyApps $ fromTyParen typ let grab x = fromMaybe (error $ "Error in tests, couldn't resolve type: " ++ x) $ lookup x types let Right r = op typ grab (ModuleName () "Example", grab d) when (not $ r `outEq` res) $ error $ "Results don't match!\nExpected:\n" ++ showOut res ++ "\nGot:\n" ++ showOut r ++ "\n\n" ++ detailedNeq res r detailedNeq as bs | na /= nb = "Lengths don't match, " ++ show na ++ " vs " ++ show nb where na = length as ; nb = length bs detailedNeq as bs = "Mismatch on line " ++ show i ++ "\n" ++ show a ++ "\n" ++ show b where (i,a,b) = head $ filter (\(i,a,b) -> a /= b) $ zip3 [1..] (noSl as) (noSl bs) autoTest :: String -> [DataDecl] -> [(Derivation,Src)] -> IO () autoTest name ts ds = writeFile (name++".hs") $ unlines $ ["{-# LANGUAGE TemplateHaskell,FlexibleInstances,MultiParamTypeClasses,TypeOperators,DeriveDataTypeable #-}" ,"{-# OPTIONS_GHC -Wall -fno-warn-missing-fields -fno-warn-unused-imports #-}" ,"module " ++ name ++ " where" ,"import Prelude" ,"import Data.DeriveTH" ,"import Data.Typeable" ,"import Derive.TestInstances()"] ++ [prettyPrint i | (_,s) <- ds, i <- srcImportStd s] ++ [prettyPrint t ++ "\n deriving Typeable" | t <- ts2] ++ ["$(derives [make" ++ derivationName d ++ "] " ++ types ++ ")" | (d,_) <- ds] where types = "[" ++ intercalate "," ["''" ++ dataDeclName t | t <- ts2] ++ "]" ts2 = filter (not . isBuiltIn) ts isBuiltIn x = dataDeclName x `elem` ["Bool","Either"] derive-2.6.3/src/Derive/Main.hs0000644000000000000000000000415413140114216014410 0ustar0000000000000000 module Derive.Main(deriveMain) where import Language.Haskell import Data.Derive.All(Derivation) import Derive.Derivation import Derive.Generate import Derive.Test import Derive.Flags import Data.List import System.Directory deriveMain :: [Derivation] -> IO () deriveMain derivations = do (flags,files) <- getFlags if Test `elem` flags then test else if Generate `elem` flags then generate else if Preprocessor `elem` flags then (if length files /= 3 then error $ "Expected to be invoked as a GHC preprocessor with 3 files, but got " ++ show (length files) else do copyFile (files !! 1) (files !! 2) mainFile derivations (Append:flags) (files !! 2) ) else if null files then putStr $ "No files specified\n" ++ flagInfo else mapM_ (mainFile derivations flags) files mainFile :: [Derivation] -> [Flag] -> FilePath -> IO () mainFile derivations flags file = do src <- readFile file src <- return $ unlines $ filter (not . isPrefixOf "#") $ lines src let parse = fromParseResult . parseFileContentsWithMode defaultParseMode{parseFilename=file,extensions=defaultExtensions} real = parse src mine = parse $ uncomment src :: Module SrcSpanInfo flags <- return $ foldl addFlags flags [(getPointLoc sl,words x) | OptionsPragma sl (Just (UnknownTool "DERIVE")) x <- modulePragmas mine] let blur = fmap (const ()) let res = performDerive derivations (blur mine :: Module ()) $ wantDerive flags (blur real) (blur mine) writeDerive file (moduleName $ blur mine) flags res uncomment :: String -> String uncomment ('{':'-':'!':xs) = ' ':' ':' ':uncomment xs uncomment ('!':'-':'}':xs) = ' ':' ':' ':uncomment xs uncomment (x:xs) = x:uncomment xs uncomment [] = [] -- Taken from HLint, update occasionally defaultExtensions :: [Extension] defaultExtensions = [e | e@EnableExtension{} <- knownExtensions] \\ map EnableExtension badExtensions badExtensions = [Arrows -- steals proc ,TransformListComp -- steals the group keyword ,XmlSyntax, RegularPatterns -- steals a-b ] derive-2.6.3/src/Derive/Generate.hs0000644000000000000000000001062613140114216015257 0ustar0000000000000000 module Derive.Generate(generate) where import Language.Haskell.Exts import Data.DeriveDSL import Derive.Utils import Control.Monad import Data.Maybe import System.FilePath import System.Directory import Data.Char import Data.List evil = words "TTypeable Uniplate" -- generate extra information for each derivation generate :: IO () generate = do xs <- getDirectoryContents "src/Data/Derive" xs <- return $ sort [x | x <- xs, takeExtension x == ".hs", x /= "All.hs", takeBaseName x `notElem` evil] lis <- mapM generateFile $ map ("src/Data/Derive" ) xs let names = map dropExtension xs n = maximum $ map length names writeGenerated "src/Data/Derive/All.hs" $ ["import Data.Derive." ++ x ++ replicate (4 + n - length x) ' ' ++ "as D" | x <- names] ++ ["derivations :: [Derivation]" ,"derivations = [make" ++ concat (intersperse ",make" names) ++ "]"] writeGenerated "README.md" $ ["-->",""] ++ lis ++ ["","