module Generics.BiGUL.AST
(BiGUL(..), CaseBranch(..), Pat(..), Direction(..), Expr(..),
deconstruct, construct, eval, uneval, emptyContainer, fromContainerS, fromContainerV) where
import Generics.BiGUL.Error
import Control.Monad.Except
import GHC.InOut
import Data.List(intersperse)
data CaseBranch s v = Normal (BiGUL s v) (s -> Bool) | Adaptive (s -> v -> s)
instance Show (CaseBranch s v) where
show (Normal bigul _) = "Normal " ++ show bigul
show (Adaptive _ ) = "Adaptive <adaptive function>"
data BiGUL :: * -> * -> * where
Fail :: String -> BiGUL s v
Skip :: BiGUL s ()
Replace :: BiGUL s s
Prod :: BiGUL s v -> BiGUL s' v' -> BiGUL (s, s') (v, v')
RearrS :: Pat s env con -> Expr env s' -> BiGUL s' v -> BiGUL s v
RearrV :: Pat v env con -> Expr env v' -> BiGUL s v' -> BiGUL s v
Dep :: (Eq v') => BiGUL s v -> (s -> v -> v') -> BiGUL s (v, v')
Case :: [(s -> v -> Bool, CaseBranch s v)] -> BiGUL s v
Compose :: BiGUL s u -> BiGUL u v -> BiGUL s v
infixr 1 `Prod`
instance Show (BiGUL s v) where
show (Fail s) = "Fail: " ++ s
show Skip = "Skip"
show Replace = "Replace"
show (Dep b _) = "(Dep <dependency function> " ++ show b ++ ")"
show (Case bs) = "(Case [" ++ unwords (intersperse "\n" (map (\(_,b) -> "(predicate, " ++ show b ++ ")") bs)) ++ " ])"
show _ = "Unknown BiGUL program in show"
newtype Var a = Var a
instance Show a => Show (Var a) where
show (Var a) = "Var: " ++ show a
data Pat :: * -> * -> * -> * where
PVar :: Eq a => Pat a (Var a) (Maybe a)
PVar' :: Pat a (Var a) (Maybe a)
PConst :: (Eq a) => a -> Pat a () ()
PProd :: Pat a a' a'' -> Pat b b' b'' -> Pat (a, b) (a', b') (a'', b'')
PLeft :: Pat a a' a'' -> Pat (Either a b) a' a''
PRight :: Pat b b' b'' -> Pat (Either a b) b' b''
PIn :: InOut a => Pat (F a) b c -> Pat a b c
instance Show (Pat v e c) where
show PVar = "PVar"
show PVar' = "PVar'"
show (PConst c) = "PConst"
show (PProd rp1 rp2) = "(PProd " ++ show rp1 ++ " " ++ show rp2 ++ ")"
show (PLeft rp) = "(PLeft " ++ show rp ++ ")"
show (PRight rp) = "(PRight " ++ show rp ++ ")"
show (PIn rp) = "(PIn " ++ show rp ++ ")"
deconstruct :: Pat a env con -> a -> Either (PatExprDirError a) env
deconstruct PVar a = return (Var a)
deconstruct PVar' a = return (Var a)
deconstruct (PConst c) a = if c == a then return () else throwError PEDConstantMismatch
deconstruct (PProd patl patr) (al, ar) = liftM2 (,) (liftE PEDProdLeft (deconstruct patl al))
(liftE PEDProdRight (deconstruct patr ar))
deconstruct (PLeft patl) (Left al) = liftE PEDEitherLeft (deconstruct patl al)
deconstruct pat@(PLeft _) a = throwError PEDEitherMismatch
deconstruct (PRight patr) (Right ar) = liftE PEDEitherRight (deconstruct patr ar)
deconstruct pat@(PRight _) a = throwError PEDEitherMismatch
deconstruct (PIn pat) a = liftE PEDIn (deconstruct pat (out a))
construct :: Pat a env con -> env -> a
construct PVar (Var a) = a
construct PVar' (Var a) = a
construct (PConst c) _ = c
construct (PProd patl patr) (al, ar) = (construct patl al, construct patr ar)
construct (PLeft patl) al = Left (construct patl al)
construct (PRight patr) ar = Right (construct patr ar)
construct (PIn pat) a = inn (construct pat a)
fromContainerV :: Pat v env con -> con -> Either (PatExprDirError v) env
fromContainerV PVar Nothing = throwError PEDValueUnrecoverable
fromContainerV PVar (Just v) = return (Var v)
fromContainerV PVar' Nothing = throwError PEDValueUnrecoverable
fromContainerV PVar' (Just v) = return (Var v)
fromContainerV (PConst c) con = return ()
fromContainerV (PProd patl patr) (conl, conr) = liftM2 (,) (liftE PEDProdLeft (fromContainerV patl conl))
(liftE PEDProdRight (fromContainerV patr conr))
fromContainerV (PLeft pat) con = liftE PEDEitherLeft (fromContainerV pat con)
fromContainerV (PRight pat) con = liftE PEDEitherRight (fromContainerV pat con)
fromContainerV (PIn pat) con = liftE PEDIn (fromContainerV pat con)
fromContainerS :: Pat s env con -> env -> con -> env
fromContainerS PVar (Var s) Nothing = (Var s)
fromContainerS PVar (Var s) (Just s') = (Var s')
fromContainerS PVar' (Var s) Nothing = (Var s)
fromContainerS PVar' (Var s) (Just s') = (Var s')
fromContainerS (PConst c) _ _ = ()
fromContainerS (PProd lpat rpat) (env, env') (con, con') = (fromContainerS lpat env con, fromContainerS rpat env' con')
fromContainerS (PLeft pat) env con = fromContainerS pat env con
fromContainerS (PRight pat) env con = fromContainerS pat env con
fromContainerS (PIn pat) env con = fromContainerS pat env con
emptyContainer :: Pat v env con -> con
emptyContainer PVar = Nothing
emptyContainer PVar' = Nothing
emptyContainer (PConst c) = ()
emptyContainer (PProd rpatl rpatr) = (emptyContainer rpatl, emptyContainer rpatr)
emptyContainer (PLeft pat ) = emptyContainer pat
emptyContainer (PRight pat ) = emptyContainer pat
emptyContainer (PIn pat ) = emptyContainer pat
data Direction :: * -> * -> * where
DVar :: Direction (Var a) a
DLeft :: Direction a t -> Direction (a, b) t
DRight :: Direction b t -> Direction (a, b) t
instance Show (Direction a t) where
show DVar = "DVar"
show (DLeft dir) = "(DLeft " ++ show dir ++ ")"
show (DRight dir) = "(DRight " ++ show dir ++ ")"
retrieve :: Direction a t -> a -> t
retrieve DVar (Var x) = x
retrieve (DLeft p) (x, y) = retrieve p x
retrieve (DRight p) (x, y) = retrieve p y
data Expr :: * -> * -> * where
EDir :: Direction orig a -> Expr orig a
EConst :: Eq a => a -> Expr orig a
EIn :: InOut a => Expr orig (F a) -> Expr orig a
EProd :: Expr orig a -> Expr orig b -> Expr orig (a, b)
ELeft :: Expr orig a -> Expr orig (Either a b)
ERight :: Expr orig b -> Expr orig (Either a b)
instance Show (Expr orig a) where
show (EDir dir) = "(EDir " ++ show dir ++ ")"
show (EConst c) = "EConst"
show (EProd e1 e2) = "(EProd " ++ show e1 ++ " " ++ show e2 ++ ")"
show (ELeft e) = "(ELeft " ++ show e ++ ")"
show (ERight e) = "(ERight " ++ show e ++ ")"
show (EIn e) = "(EIn " ++ show e ++ ")"
eval :: Expr env a' -> env -> a'
eval (EDir dir) env = retrieve dir env
eval (EConst c) env = c
eval (EIn expr) env = inn (eval expr env)
eval (EProd exprl exprr) env = (eval exprl env, eval exprr env)
eval (ELeft expr ) env = Left $ eval expr env
eval (ERight expr ) env = Right $ eval expr env
uneval :: Pat a env con -> Expr env a' -> a' -> con -> Either (PatExprDirError a') con
uneval pat (EDir dir) a' con = unevalDir pat dir a' con
uneval pat (EConst c) a' con = if c == a' then return con else throwError PEDConstantMismatch
uneval pat (EIn expr) a' con = liftE PEDIn (uneval pat expr (out a') con)
uneval pat (EProd exprl exprr) (al', ar') con = liftE PEDProdLeft (uneval pat exprl al' con) >>= liftE PEDProdRight . uneval pat exprr ar'
uneval pat (ELeft expr) (Left al') con = liftE PEDEitherLeft (uneval pat expr al' con)
uneval pat expr@(ELeft _) a' con = throwError PEDEitherMismatch
uneval pat (ERight expr) (Right ar') con = liftE PEDEitherRight (uneval pat expr ar' con)
uneval pat expr@(ERight _) a' con = throwError PEDEitherMismatch
unevalDir :: Pat a env con -> Direction env a' -> a' -> con -> Either (PatExprDirError a') con
unevalDir PVar DVar a' (Just a'') = if a' == a''
then return (Just a')
else throwError (PEDIncompatibleUpdates a' a'')
unevalDir PVar DVar a' Nothing = return (Just a')
unevalDir PVar' DVar a' (Just a'') = throwError (PEDMultipleUpdates a' a'')
unevalDir PVar' DVar a' Nothing = return (Just a')
unevalDir (PConst c) _ a' con = return con
unevalDir (PProd patl patr) (DLeft dir) a' (conl, conr) = liftM (, conr) (unevalDir patl dir a' conl)
unevalDir (PProd patl patr) (DRight dir) a' (conl, conr) = liftM (conl ,) (unevalDir patr dir a' conr)
unevalDir (PLeft patl ) dir a' con = unevalDir patl dir a' con
unevalDir (PRight patr ) dir a' con = unevalDir patr dir a' con
unevalDir (PIn pat ) dir a' con = unevalDir pat dir a' con