{-# LANGUAGE CPP #-}
{-# LANGUAGE UndecidableInstances #-}
#ifndef MIN_VERSION_GLASGOW_HASKELL
#define MIN_VERSION_GLASGOW_HASKELL(a,b,c,d) 0
#endif
#if MIN_VERSION_GLASGOW_HASKELL(7,10,0,0)
#else
{-# LANGUAGE OverlappingInstances #-}
#endif
module Language.Syntactic.Syntax
(
AST (..)
, ASTF
, ASTFull (..)
, Full (..)
, (:->) (..)
, SigRep (..)
, Signature (..)
, DenResult
, Symbol (..)
, size
, SmartFun
, SmartSig
, SmartSym
, smartSym'
, (:+:) (..)
, Project (..)
, (:<:) (..)
, smartSym
, smartSymTyped
, Empty
, E (..)
, liftE
, liftE2
, EF (..)
, liftEF
, liftEF2
, Typed (..)
, injT
, castExpr
, NFData1 (..)
, symType
, prjP
) where
import Control.DeepSeq
import Data.Typeable
#if MIN_VERSION_GLASGOW_HASKELL(7,10,0,0)
#else
import Data.Foldable (Foldable)
import Data.Proxy
import Data.Traversable (Traversable)
#endif
data AST sym sig
where
Sym :: sym sig -> AST sym sig
(:$) :: AST sym (a :-> sig) -> AST sym (Full a) -> AST sym sig
infixl 1 :$
type ASTF sym a = AST sym (Full a)
newtype ASTFull sym a = ASTFull {unASTFull :: ASTF sym a}
instance Functor sym => Functor (AST sym)
where
fmap f (Sym s) = Sym (fmap f s)
fmap f (s :$ a) = fmap (fmap f) s :$ a
newtype Full a = Full { result :: a }
deriving (Eq, Show, Typeable, Functor)
newtype a :-> sig = Partial (a -> sig)
deriving (Typeable, Functor)
infixr :->
data SigRep sig
where
SigFull :: SigRep (Full a)
SigMore :: SigRep sig -> SigRep (a :-> sig)
class Signature sig
where
signature :: SigRep sig
instance Signature (Full a)
where
signature = SigFull
instance Signature sig => Signature (a :-> sig)
where
signature = SigMore signature
type family DenResult sig
type instance DenResult (Full a) = a
type instance DenResult (a :-> sig) = DenResult sig
class Symbol sym
where
symSig :: sym sig -> SigRep sig
instance NFData1 sym => NFData (AST sym sig)
where
rnf (Sym s) = liftRnf (`seq` ()) s
rnf (s :$ a) = rnf s `seq` rnf a
size :: AST sym sig -> Int
size (Sym _) = 1
size (s :$ a) = size s + size a
type family SmartFun (sym :: * -> *) sig
type instance SmartFun sym (Full a) = ASTF sym a
type instance SmartFun sym (a :-> sig) = ASTF sym a -> SmartFun sym sig
type family SmartSig f
type instance SmartSig (AST sym sig) = sig
type instance SmartSig (ASTF sym a -> f) = a :-> SmartSig f
type family SmartSym f :: * -> *
type instance SmartSym (AST sym sig) = sym
type instance SmartSym (a -> f) = SmartSym f
smartSym' :: forall sig f sym
. ( Signature sig
, f ~ SmartFun sym sig
, sig ~ SmartSig f
, sym ~ SmartSym f
)
=> sym sig -> f
smartSym' s = go (signature :: SigRep sig) (Sym s)
where
go :: forall sig . SigRep sig -> AST sym sig -> SmartFun sym sig
go SigFull s = s
go (SigMore sig) s = \a -> go sig (s :$ a)
data (sym1 :+: sym2) sig
where
InjL :: sym1 a -> (sym1 :+: sym2) a
InjR :: sym2 a -> (sym1 :+: sym2) a
deriving (Functor, Foldable, Traversable)
infixr :+:
instance (Symbol sym1, Symbol sym2) => Symbol (sym1 :+: sym2)
where
symSig (InjL s) = symSig s
symSig (InjR s) = symSig s
instance (NFData1 sym1, NFData1 sym2) => NFData1 (sym1 :+: sym2)
where
liftRnf r (InjL s) = liftRnf r s
liftRnf r (InjR s) = liftRnf r s
class Project sub sup
where
prj :: sup a -> Maybe (sub a)
instance {-# OVERLAPPING #-} Project sub sup => Project sub (AST sup)
where
prj (Sym s) = prj s
prj _ = Nothing
instance {-# OVERLAPPING #-} Project sym sym
where
prj = Just
instance {-# OVERLAPPING #-} Project sym1 (sym1 :+: sym2)
where
prj (InjL a) = Just a
prj _ = Nothing
instance {-# OVERLAPPING #-} Project sym1 sym3 => Project sym1 (sym2 :+: sym3)
where
prj (InjR a) = prj a
prj _ = Nothing
instance Project sub sup
where
prj _ = Nothing
class Project sub sup => sub :<: sup
where
inj :: sub a -> sup a
instance {-# OVERLAPPING #-} (sub :<: sup) => (sub :<: AST sup)
where
inj = Sym . inj
instance {-# OVERLAPPING #-} (sym :<: sym)
where
inj = id
instance {-# OVERLAPPING #-} (sym1 :<: (sym1 :+: sym2))
where
inj = InjL
instance {-# OVERLAPPING #-} (sym1 :<: sym3) => (sym1 :<: (sym2 :+: sym3))
where
inj = InjR . inj
smartSym
:: ( Signature sig
, f ~ SmartFun sup sig
, sig ~ SmartSig f
, sup ~ SmartSym f
, sub :<: sup
)
=> sub sig -> f
smartSym = smartSym' . inj
smartSymTyped
:: ( Signature sig
, f ~ SmartFun (Typed sup) sig
, sig ~ SmartSig f
, Typed sup ~ SmartSym f
, sub :<: sup
, Typeable (DenResult sig)
)
=> sub sig -> f
smartSymTyped = smartSym' . Typed . inj
data Empty :: * -> *
data E e
where
E :: e a -> E e
liftE :: (forall a . e a -> b) -> E e -> b
liftE f (E a) = f a
liftE2 :: (forall a b . e a -> e b -> c) -> E e -> E e -> c
liftE2 f (E a) (E b) = f a b
data EF e
where
EF :: e (Full a) -> EF e
liftEF :: (forall a . e (Full a) -> b) -> EF e -> b
liftEF f (EF a) = f a
liftEF2 :: (forall a b . e (Full a) -> e (Full b) -> c) -> EF e -> EF e -> c
liftEF2 f (EF a) (EF b) = f a b
data Typed sym sig
where
Typed :: Typeable (DenResult sig) => sym sig -> Typed sym sig
instance {-# OVERLAPPING #-} Project sub sup => Project sub (Typed sup)
where
prj (Typed s) = prj s
injT :: (sub :<: sup, Typeable (DenResult sig)) =>
sub sig -> AST (Typed sup) sig
injT = Sym . Typed . inj
castExpr :: forall sym a b
. ASTF (Typed sym) a
-> ASTF (Typed sym) b
-> Maybe (ASTF (Typed sym) b)
castExpr a b = cast1 a
where
cast1 :: (DenResult sig ~ a) => AST (Typed sym) sig -> Maybe (ASTF (Typed sym) b)
cast1 (s :$ _) = cast1 s
cast1 (Sym (Typed _)) = cast2 b
where
cast2 :: (DenResult sig ~ b) => AST (Typed sym) sig -> Maybe (ASTF (Typed sym) b)
cast2 (s :$ _) = cast2 s
cast2 (Sym (Typed _)) = gcast a
symType :: Proxy sym -> sym sig -> sym sig
symType _ = id
prjP :: Project sub sup => Proxy sub -> sup sig -> Maybe (sub sig)
prjP _ = prj