parser-c 0.3.0

Macros for parser-c.
Documentation
diff -Nur derive-2.4.2/Data/Derive/All.hs derive-2.4.2-patched/Data/Derive/All.hs
--- derive-2.4.2/Data/Derive/All.hs	2011-04-17 14:52:21.000000000 +0200
+++ derive-2.4.2-patched/Data/Derive/All.hs	2011-04-16 21:56:20.000000000 +0200
@@ -39,6 +39,10 @@
 import Data.Derive.UniplateDirect      as D
 import Data.Derive.UniplateTypeable    as D
 import Data.Derive.Update              as D
+
+import Data.Derive.Annotated           as D
+import Data.Derive.CNode               as D
+
 derivations :: [Derivation]
-derivations = [makeArbitrary,makeArbitraryOld,makeArities,makeBinary,makeBinaryDefer,makeBounded,makeData,makeDataAbstract,makeDefault,makeEnum,makeEnumCyclic,makeEq,makeFold,makeFoldable,makeFrom,makeFunctor,makeHas,makeIs,makeJSON,makeLazySet,makeMonoid,makeNFData,makeOrd,makeRead,makeRef,makeSerial,makeSerialize,makeSet,makeShow,makeTraversable,makeTypeable,makeUniplateDirect,makeUniplateTypeable,makeUpdate]
+derivations = [makeArbitrary,makeArbitraryOld,makeArities,makeBinary,makeBinaryDefer,makeBounded,makeData,makeDataAbstract,makeDefault,makeEnum,makeEnumCyclic,makeEq,makeFold,makeFoldable,makeFrom,makeFunctor,makeHas,makeIs,makeJSON,makeLazySet,makeMonoid,makeNFData,makeOrd,makeRead,makeRef,makeSerial,makeSerialize,makeSet,makeShow,makeTraversable,makeTypeable,makeUniplateDirect,makeUniplateTypeable,makeUpdate, makeCNode, makeAnnotated]
 -- GENERATED STOP
diff -Nur derive-2.4.2/Data/Derive/Annotated.hs derive-2.4.2-patched/Data/Derive/Annotated.hs
--- derive-2.4.2/Data/Derive/Annotated.hs	1970-01-01 01:00:00.000000000 +0100
+++ derive-2.4.2-patched/Data/Derive/Annotated.hs	2011-04-17 15:42:48.000000000 +0200
@@ -0,0 +1,110 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Derives 'Annotated' instances for language.c
+module Data.Derive.Annotated(
+    makeAnnotated,
+    -- few misc helpers for my derivations
+    isVarName, ctorArgs, selectPolyArg, matchIndex,
+    noLoc, funDecl,
+    -- a monad with failure (Either String)
+    DeriveM(..), runDeriveM
+    ) where
+
+{-
+-- For a type T a, for each constructor C:
+--   If C ~ X a_1 .. a_n, and exactly one a_k is a polymorphic variable, then
+--    annotation t@(X a_1 ... a_n) = a_k
+--    amap f     t@(X a_1 ... a_n) = X a_1 ... (f a_k) ... a_n
+--   If C ~ X t, where t is of type S a, then
+--    annotation (X s) = annotation s
+--    amap f (X s) = amap f s
+--   Else Fail
+-- data Test1 a = A Int a String | B a (Test a) (Test a) | C a | D (Test1 a)
+-}
+import Control.Monad (liftM)
+import Language.Haskell.Exts hiding (paren)
+import Language.Haskell -- helpers from Derive
+import Data.Derive.Internal.Derivation
+
+makeAnnotated :: Derivation
+makeAnnotated = derivationCustom "Annotated" (runDeriveM . genAnnotatedInst)
+
+genAnnotatedInst :: FullDataDecl -> DeriveM [Decl]
+genAnnotatedInst (_,dat) = do
+  let ctors = dataDeclCtors dat
+  (annotDecls, amapDecls) <- liftM unzip $ mapM (annotClause "annotation" "amap") ctors
+  return [ InstDecl noLoc [] (qname "Annotated") [TyCon $ qname (dataDeclName dat)] (map InsDecl [ FunBind annotDecls, FunBind amapDecls ]) ]
+
+annotClause :: String -> String -> CtorDecl -> DeriveM (Match, Match)
+annotClause annot amap ctor = do
+  args <- ctorArgs ctor
+  case (selectPolyArg args, selectDelegateArg args) of
+    ( DOk (ix,_), DErr _ ) -> return ( funDecl annot  [matchIndex ctor args ix (PVar (name "n"))] (Var (qname "n"))
+                                     , funDecl amap [PVar (name f), matchCtor ctor args "a_"] (mapPoly ctor args ix) )
+    ( DErr _, DOk _ )      -> return ( funDecl annot  [matchOne ctor "n"] (app (Var (qname annot)) (Var (qname "n")))
+                                     , funDecl amap [PVar (name f), matchOne ctor "n"] (amapRec ctor "n") )
+    ( DErr m1, DErr m2)    -> fail $ "Deriving Annotation: Constructor has neither exactly one variable type argument, nor"++
+                                     "exactly one argument of type (T a). " ++ m1 ++ ". " ++ m2
+    ( DOk _, DOk _)        -> fail $ "Internal Error: Constructor has both a variable type argument, and a constructor type argument"
+  where
+    f = "f"
+    argName i = qname ("a_" ++ show i)
+    mapPoly ctor args ix = apps (Con (qname $ ctorDeclName ctor)) (map (applyAt ix) args)
+    applyAt i (index,_) | index == i = app (Var (qname f)) (Var (argName i))
+                        | otherwise  = Var (argName index)
+    matchOne ctor var = PApp (qname (ctorDeclName ctor)) [PVar (name var)]
+    amapRec ctor var = App (Con (qname (ctorDeclName ctor))) (Paren (apps (Var (qname amap)) [Var (qname f), Var (qname var)]))
+
+-- we do not have source locations when generating code
+noLoc :: SrcLoc
+noLoc = SrcLoc "<generated>" 0 0
+
+-- whether we have a ctor argument of variable type
+isVarName :: Type -> Bool
+isVarName (TyVar _) = True
+isVarName _         = False
+
+ctorArgs :: CtorDecl -> DeriveM [(Integer,BangType)]
+ctorArgs ctor@(Left _)  = return $ zip [(1::Integer)..] $ map snd (ctorDeclFields ctor)
+ctorArgs ctor@(Right _) = fail   $ "CNode: GADTs are not supported: " ++ show ctor
+
+selectDelegateArg :: [(Integer, BangType)] -> DeriveM Type
+selectDelegateArg args =
+  case args of
+    []       -> fail "Select Delegate Argument: Constructor has no argument"
+    [(_,bty)] -> case fromTyParens (fromBangType bty) of
+      ty@(TyApp (TyCon _) (TyVar _)) -> return ty
+      ty     -> fail $ "Select Delegate Argument: Constructor is not of the form T x: " ++ show ty
+    _xs      -> fail "Select Delegate Argument: Constructor has more than one argument"
+
+selectPolyArg :: [(Integer, BangType)] -> DeriveM (Integer, Name)
+selectPolyArg args =
+  case filter (isVarName . fromBangType . snd) args of
+        []             -> fail   $ "Select Polymorphic Argument: no type variable arguments in " ++ show args
+        [(ix,ty)]      -> return $ (ix,fromTyVar (fromBangType ty))
+        _xs            -> fail   $ "Select Polymorphic Argument: More than one type variable argument in " ++ show args
+  where fromTyVar (TyVar n) = n
+
+-- a little bit more powerful than simpleFun ;)
+funDecl :: String -> [Pat] -> Exp -> Match
+funDecl funName patterns rhs = Match noLoc (Ident funName) patterns Nothing (UnGuardedRhs rhs) (BDecls [])
+
+matchCtor :: CtorDecl -> [(Integer, t)] -> String -> Pat
+matchCtor ctor ctorArgs varPrefix = PApp (qname (ctorDeclName ctor)) $ map matchArg ctorArgs
+  where
+    matchArg (ix,_) = PVar (name $ varPrefix ++ show ix)
+
+matchIndex :: (Eq a) => CtorDecl -> [(a, t)] -> a -> Pat -> Pat
+matchIndex ctor ctorArgs ix matchPat = PApp (qname (ctorDeclName ctor)) $ map matchArg ctorArgs
+  where
+    matchArg (ix',_) | ix == ix' = matchPat
+                     | otherwise = PWildCard
+
+-- I want to have an error monad, and Monad Either is not available :(
+data DeriveM a = DOk a | DErr String
+runDeriveM (DOk a)    = Right a
+runDeriveM (DErr msg) = Left msg
+instance Monad DeriveM where
+  return = DOk
+  (>>=) (DErr msg) f = DErr msg
+  (>>=) (DOk ok)   f = f ok
+  fail msg = DErr msg
diff -Nur derive-2.4.2/Data/Derive/CNode.hs derive-2.4.2-patched/Data/Derive/CNode.hs
--- derive-2.4.2/Data/Derive/CNode.hs	1970-01-01 01:00:00.000000000 +0100
+++ derive-2.4.2-patched/Data/Derive/CNode.hs	2011-04-17 15:37:32.000000000 +0200
@@ -0,0 +1,94 @@
+{-# LANGUAGE TemplateHaskell,PatternGuards #-}
+-- | Derives 'CNode' instances for language.c
+module Data.Derive.CNode(makeCNode) where
+
+{-
+-- For all type variables a, we require (CNode a)
+-- If we have a data constructor
+--   X a_1 .. a_n, and exactly one a_k is a polymorphic variable, then return (nodeInfo a_k)
+data Test3 a = A Test1 a Test1 | B a Test2 | C Test1 a deriving (Show {-! ,CNode !-})
+-- Else If we have a data constructor
+--   X a_1 .. a_n, and exactly one a_k is a Language.C.Data.NodeInfo, then return that a_k
+data Test1 = X Int NodeInfo |  Y NodeInfo String | Z Int NodeInfo Integer deriving (Show {-! ,CNode !-})
+
+-- Else If we have a data constructor
+--   X a, then return nodeInfo a
+data Test2 = U Test1 | V Test1 deriving (Show {-! ,CNode !-})
+-- Else Fail
+-}
+import Language.Haskell.Exts hiding (paren)
+import Language.Haskell -- helpers from Derive
+import Data.Derive.Internal.Derivation
+import Data.Derive.Annotated
+
+makeCNode :: Derivation
+makeCNode = derivationCustom "CNode" (runDeriveM . genNodeInst)
+
+nodeInfoTypeName :: [Char]
+nodeInfoTypeName = "Language.C.Data.Node.NodeInfo"
+
+genNodeInst :: FullDataDecl -> DeriveM [Decl]
+genNodeInst (_,dat) = do
+  nodeInfoDecls <- nodeInfoDefs "nodeInfo" dat
+  return $
+   [ instanceContext ["CNode"] "CNode" dat [ FunBind $ nodeInfoDecls ]
+   , instanceContext ["CNode"] "Pos" dat [ FunBind  $ posOfDef "posOf" ]
+   ]
+
+posOfDef :: String -> [Match]
+posOfDef funName =
+  [ funDecl funName [pvar "x"]
+                 (app (var "posOf") (paren $ app (var "nodeInfo") (var "x")))
+  ]
+  where
+    var  = Var . qname
+    pvar = PVar . Ident
+
+nodeInfoDefs :: String -> DataDecl -> DeriveM [Match]
+nodeInfoDefs funName dat = mapM nodeInfoImpl (dataDeclCtors dat) where
+    nodeInfoImpl ctor =
+        case matchNodeInfo ctor of
+            DOk (pat,rhs) ->
+                return $ funDecl funName [pat] rhs
+            DErr err ->
+                fail   $ "Failed to derive NodeInfo for " ++ ctorDeclName ctor ++ ": " ++ err
+
+matchNodeInfo :: CtorDecl -> DeriveM (Pat, Exp)
+matchNodeInfo ctor = ctorArgs ctor >>= tryNodeInfoArg
+  where
+    tryNodeInfoArg args =
+        case filter (isNodeInfo.fromBangType.snd) args  of
+            []       -> tryDelegate args
+            [(ix,_)] -> return $ (matchIndex ctor args ix (PVar (name "n")), Var (qname "n"))
+            _        -> fail   $ "More than one NodeInfo type"
+        where
+            isNodeInfo (TyCon qname) | (Qual _ (Ident "NodeInfo")) <- qname = True
+                                     | (UnQual (Ident "NodeInfo")) <- qname = True
+                                     | otherwise = False
+            isNodeInfo _ = False
+    tryDelegate args =
+       case args of
+           []        -> fail   $ "cannot derive NodeInfo for nullary constructor"
+           [_c]      -> return $ (PApp (qname $ ctorDeclName ctor) [PVar (name "d")],
+                                  App (Var (qname "nodeInfo")) (Var (qname "d")))
+           _xs       -> delegateToPolymorphic "nodeInfo" ctor
+    delegateToPolymorphic :: String -> CtorDecl -> DeriveM (Pat,Exp)
+    delegateToPolymorphic fun ctor = ctorArgs ctor >>= delegate
+      where
+        delegate args =
+          case filter (isVarName . fromBangType . snd) args of
+            []        -> fail   $ "delegateToPolymorphic: no type variable arguments"
+            [(ix,_)]  -> return $ (matchIndex ctor args ix (PVar (name "n")),
+                                 App (Var (qname fun)) (Var (qname "n")))
+            _xs       -> fail   $ "delegateToPolymorphic: More than one type variable argument"
+
+-- ported from TH.Helpers
+instanceContext :: [String] -> String -> Decl -> [Decl] -> Decl
+instanceContext reqs cls dat defs = InstDecl noLoc ctx className [hed] (map InsDecl defs)
+    where
+        vars = [Ident ('t' : show i) | i <- [1..dataDeclArity dat]]
+        ctx = [ ClassA (qname req) [TyVar var] | req <- reqs, var <- vars]
+        className = qname cls
+        hed = (if not (null vars) then TyParen else id) $
+              tyApp (TyCon $ qname (dataDeclName dat)) (map TyVar vars)
+
diff -Nur derive-2.4.2/derive.cabal derive-2.4.2-patched/derive.cabal
--- derive-2.4.2/derive.cabal	2011-04-17 14:52:21.000000000 +0200
+++ derive-2.4.2-patched/derive.cabal	2011-04-16 22:01:09.000000000 +0200
@@ -97,6 +97,8 @@
         Data.Derive.UniplateDirect
         Data.Derive.UniplateTypeable
         Data.Derive.Update
+        Data.Derive.Annotated
+        Data.Derive.CNode
 -- GENERATED STOP

         -- Mainly internal but some still people use them