# LANGUAGE FlexibleInstances #
# LANGUAGE DeriveFunctor #

module FVL.EvalAST
( Expr(..)
, RVal(..)
, valueTransform
, showCons
, evalTransform
) where

import FVL.Algebra
import qualified FVL.FAST as FAST

data Expr a b
    = CInt Integer
    | CBool Bool
    | CVar String
    | Add b b
    | Sub b b
    | Mul b b
    | Div b b
    | And b b
    | Or b b
    | Not b
    | Equal b b
    | Less b b
    | Empty
    | Cons b b
    | If b a a
    | Function String a
    | Appl b a
    | LetRec String String a a
    | Case b a String String a
    deriving Functor

showCons' :: LazyFix Expr -> [LazyFix Expr]
showCons' (Fx' (x `Cons` y)) = x : showCons' y
showCons' e = [e]

showCons :: LazyFix Expr -> String
showCons e = "[" ++ (foldr combine "\b\b" (showCons' e)) ++ "]"
    where combine (Fx' Empty) b = b
          combine a b = show a ++ ", " ++ b

instance Show (LazyFix Expr) where
    show (Fx' (CInt n)) = show n
    show (Fx' (CBool b)) = show b
    show (Fx' (CVar s)) = s
    show (Fx' (x `Add` y)) = show x ++ " + " ++ show y
    show (Fx' (x `Sub` y)) = show x ++ " - " ++ show y
    show (Fx' (x `Mul` y)) = show x ++ " * " ++ show y
    show (Fx' (x `Div` y)) = show x ++ " / " ++ show y
    show (Fx' (x `And` y)) = show x ++ " && " ++ show y
    show (Fx' (x `Or` y)) = show x ++ " || " ++ show y
    show (Fx' (Not x)) = "!" ++ (case x of
        (Fx' (CBool b)) -> show b
        (Fx' (CVar s)) -> s
        _ -> "(" ++ show x ++ ")")
    show (Fx' (x `Equal` y)) = show x ++ " = " ++ show y
    show (Fx' (x `Less` y)) = show x ++ " < " ++ show y
    show (Fx' Empty) = "[]"
    show (Fx' (x `Cons` y)) = showCons . Fx' $ x `Cons` y
    show (Fx' (If p x y)) = "If " ++ show p ++ " Then " ++ show x ++ " Else " ++ show y
    show (Fx' (Function x p)) = "Function " ++ x ++ " -> " ++ show p
    show (Fx' (Appl f x)) = (case f of
        (Fx' (CInt n)) -> show n ++ " "
        (Fx' (CBool b)) -> show b ++ " "
        (Fx' (CVar s)) -> s ++ " "
        (Fx' (Appl _ _)) -> show f ++ " "
        _ -> "(" ++ show f ++ ") ") ++ (case x of
            (Fx' (CInt n)) -> show n
            (Fx' (CBool b)) -> show b
            (Fx' (CVar s)) -> s
            (Fx' (Appl _ _)) -> show x
            _ -> "(" ++ show x ++ ")")
    show (Fx' (LetRec f x p e))
        = "Let Rec " ++ f ++ " " ++ x ++ " = " ++ show p ++ " In " ++ show e
    show (Fx' (Case p x s t y)) = "Case " ++ show x ++ " Of [] -> " ++ show x
        ++ " | (" ++ s ++ ", " ++ t ++ ") -> " ++ show y

data RVal = RInt Integer
          | RBool Bool
          | RFunction String (LazyFix Expr)
          | REmpty
          | RCons RVal RVal

valueTransform :: RVal -> LazyFix Expr
valueTransform (RInt n) = Fx' $ CInt n
valueTransform (RBool b) = Fx' $ CBool b
valueTransform (RFunction s p) = Fx' $ Function s p
valueTransform REmpty = Fx' $ Empty
valueTransform (RCons x y) = Fx' $ Cons (valueTransform x) (valueTransform y)

instance Show RVal where
    show = show . valueTransform

alg :: Algebra FAST.Expr (LazyFix Expr)
alg (FAST.CInt n) = Fx' $ CInt n
alg (FAST.CBool b) = Fx' $ CBool b
alg (FAST.CVar s) = Fx' $ CVar s
alg (FAST.Add x y) = Fx' $ Add x y
alg (FAST.Sub x y) = Fx' $ Sub x y
alg (FAST.Mul x y) = Fx' $ Mul x y
alg (FAST.Div x y) = Fx' $ Div x y
alg (FAST.And x y) = Fx' $ And x y
alg (FAST.Or x y) = Fx' $ Or x y
alg (FAST.Not x) = Fx' $ Not x
alg (FAST.Equal x y) = Fx' $ Equal x y
alg (FAST.Less x y) = Fx' $ Less x y
alg (FAST.Empty) = Fx' $ Empty
alg (FAST.Cons x y) = Fx' $ Cons x y
alg (FAST.If p x y) = Fx' $ If p x y
alg (FAST.Function s p) = Fx' $ Function s p
alg (FAST.Appl f x) = Fx' $ Appl f x
alg (FAST.LetRec f x p e) = Fx' $ LetRec f x p e
alg (FAST.Case p x s t y) = Fx' $ Case p x s t y

evalTransform :: Fix FAST.Expr -> LazyFix Expr
evalTransform = cata alg


# LANGUAGE FlexibleInstances #
# LANGUAGE DeriveFunctor #

module FVL.EvalAST
( Expr(..)
, RVal(..)
, valueTransform
, showCons
, evalTransform
) where

import FVL.Algebra
import qualified FVL.FAST as FAST

data Expr a b
    = CInt Integer
    | CBool Bool
    | CVar String
    | Add b b
    | Sub b b
    | Mul b b
    | Div b b
    | And b b
    | Or b b
    | Not b
    | Equal b b
    | Less b b
    | Empty
    | Cons b b
    | If b a a
    | Function String a
    | Appl b a
    | LetRec String String a a
    | Case b a String String a
    deriving Functor

showCons' :: LazyFix Expr -> [LazyFix Expr]
showCons' (Fx' (x `Cons` y)) = x : showCons' y
showCons' e = [e]

showCons :: LazyFix Expr -> String
showCons e = "[" ++ (foldr combine "\b\b" (showCons' e)) ++ "]"
    where combine (Fx' Empty) b = b
          combine a b = show a ++ ", " ++ b

instance Show (LazyFix Expr) where
    show (Fx' (CInt n)) = show n
    show (Fx' (CBool b)) = show b
    show (Fx' (CVar s)) = s
    show (Fx' (x `Add` y)) = show x ++ " + " ++ show y
    show (Fx' (x `Sub` y)) = show x ++ " - " ++ show y
    show (Fx' (x `Mul` y)) = show x ++ " * " ++ show y
    show (Fx' (x `Div` y)) = show x ++ " / " ++ show y
    show (Fx' (x `And` y)) = show x ++ " && " ++ show y
    show (Fx' (x `Or` y)) = show x ++ " || " ++ show y
    show (Fx' (Not x)) = "!" ++ (case x of
        (Fx' (CBool b)) -> show b
        (Fx' (CVar s)) -> s
        _ -> "(" ++ show x ++ ")")
    show (Fx' (x `Equal` y)) = show x ++ " = " ++ show y
    show (Fx' (x `Less` y)) = show x ++ " < " ++ show y
    show (Fx' Empty) = "[]"
    show (Fx' (x `Cons` y)) = showCons . Fx' $ x `Cons` y
    show (Fx' (If p x y)) = "If " ++ show p ++ " Then " ++ show x ++ " Else " ++ show y
    show (Fx' (Function x p)) = "Function " ++ x ++ " -> " ++ show p
    show (Fx' (Appl f x)) = (case f of
        (Fx' (CInt n)) -> show n ++ " "
        (Fx' (CBool b)) -> show b ++ " "
        (Fx' (CVar s)) -> s ++ " "
        (Fx' (Appl _ _)) -> show f ++ " "
        _ -> "(" ++ show f ++ ") ") ++ (case x of
            (Fx' (CInt n)) -> show n
            (Fx' (CBool b)) -> show b
            (Fx' (CVar s)) -> s
            (Fx' (Appl _ _)) -> show x
            _ -> "(" ++ show x ++ ")")
    show (Fx' (LetRec f x p e))
        = "Let Rec " ++ f ++ " " ++ x ++ " = " ++ show p ++ " In " ++ show e
    show (Fx' (Case p x s t y)) = "Case " ++ show x ++ " Of [] -> " ++ show x
        ++ " | (" ++ s ++ ", " ++ t ++ ") -> " ++ show y

data RVal = RInt Integer
          | RBool Bool
          | RFunction String (LazyFix Expr)
          | REmpty
          | RCons RVal RVal

valueTransform :: RVal -> LazyFix Expr
valueTransform (RInt n) = Fx' $ CInt n
valueTransform (RBool b) = Fx' $ CBool b
valueTransform (RFunction s p) = Fx' $ Function s p
valueTransform REmpty = Fx' $ Empty
valueTransform (RCons x y) = Fx' $ Cons (valueTransform x) (valueTransform y)

instance Show RVal where
    show = show . valueTransform

alg :: Algebra FAST.Expr (LazyFix Expr)
alg (FAST.CInt n) = Fx' $ CInt n
alg (FAST.CBool b) = Fx' $ CBool b
alg (FAST.CVar s) = Fx' $ CVar s
alg (FAST.Add x y) = Fx' $ Add x y
alg (FAST.Sub x y) = Fx' $ Sub x y
alg (FAST.Mul x y) = Fx' $ Mul x y
alg (FAST.Div x y) = Fx' $ Div x y
alg (FAST.And x y) = Fx' $ And x y
alg (FAST.Or x y) = Fx' $ Or x y
alg (FAST.Not x) = Fx' $ Not x
alg (FAST.Equal x y) = Fx' $ Equal x y
alg (FAST.Less x y) = Fx' $ Less x y
alg (FAST.Empty) = Fx' $ Empty
alg (FAST.Cons x y) = Fx' $ Cons x y
alg (FAST.If p x y) = Fx' $ If p x y
alg (FAST.Function s p) = Fx' $ Function s p
alg (FAST.Appl f x) = Fx' $ Appl f x
alg (FAST.LetRec f x p e) = Fx' $ LetRec f x p e
alg (FAST.Case p x s t y) = Fx' $ Case p x s t y

evalTransform :: Fix FAST.Expr -> LazyFix Expr
evalTransform = cata alg

