{-# LANGUAGE DeriveDataTypeable #-}

module Language.Grammars.ZipperAG.Examples.LET.Let_DataTypes_Boilerplate where

import Prelude
import Data.Data
import Data.Generics.Zipper
import Language.Grammars.ZipperAG

-- Links, exactly like in Silver
data Link = IsRootC RootC | IsLetC LetC | IsInC InC | IsListC ListC | IsE E | IsT T | IsF F | Empty
 deriving (Show, Data, Typeable)

-- To create the link, only the type of the
-- subtree matters, so this is a simpler,
-- type-based version of constructor
createLink :: Zipper a -> Link
createLink ag = case (getHole ag :: Maybe RootC) of
                   Just (e) -> IsRootC e
                   _ -> case (getHole ag :: Maybe LetC) of
                          Just (t) -> IsLetC t
                          _ -> case (getHole ag :: Maybe InC) of
                                 Just (f) -> IsInC f
                                 _ -> case (getHole ag :: Maybe ListC) of
                                        Just (f) -> IsListC f
                                        _ -> case (getHole ag :: Maybe E) of
                                               Just (e) -> IsE e
                                               _ -> case (getHole ag :: Maybe T) of
                                                      Just (t) -> IsT t
                                                      _ -> case (getHole ag :: Maybe F) of
                                                             Just (f) -> IsF f

getLink :: Zipper a -> Link
getLink ag = case (getHole ag :: Maybe RootA) of
               Just (RootA _ link) -> link
               _ -> case (getHole ag :: Maybe LetA) of
                      Just (LetA _ _ link) -> link
                      _ -> case (getHole ag :: Maybe InA) of
                             Just (InA _ link) -> link
                             _ -> case (getHole ag :: Maybe ListA) of
                                    Just (ConsLetA _ _ _ link   ) -> link
                                    Just (ConsAssignA _ _ _ link) -> link
                                    Just (EmptyListA link       ) -> link
                                    _ -> case (getHole ag :: Maybe A) of
                                           Just (Plus _ _ link  ) -> link
                                           Just (Minus _ _ link ) -> link
                                           Just (Time _ _ link  ) -> link
                                           Just (Divide _ _ link) -> link
                                           Just (Constant _ link) -> link
                                           Just (Variable _ link) -> link

-- Concrete data type
data RootC = RootC LetC
           deriving (Show, Data, Typeable)

data LetC = LetC ListC InC
          deriving (Show, Data, Typeable)

data InC = InC E
         deriving (Show, Data, Typeable)

data ListC = ConsLetC String LetC ListC
           | ConsAssignC String E ListC
           | EmptyListC
           deriving (Show, Data, Typeable)

data E = Add E T
       | Sub E T
       | Et T
       deriving (Show, Data, Typeable)

data T = Mul T F
       | Div T F
       | Tf F
       deriving (Show, Data, Typeable)

data F = Nest E
       | Neg F
       | Var String
       | Const Int
       deriving (Show, Data, Typeable)

-- Abstract data type
data RootA = RootA LetA Link
           deriving (Show, Data, Typeable)

data LetA = LetA ListA InA Link
          deriving (Show, Data, Typeable)

data InA = InA A Link
         deriving (Show, Data, Typeable)

data ListA = ConsLetA String LetA ListA Link
           | ConsAssignA String A ListA Link
           | EmptyListA Link
           deriving (Show, Data, Typeable)

data A = Plus A A Link
       | Minus A A Link
       | Time A A Link
       | Divide A A Link
       | Variable String Link
       | Constant Int Link
       deriving (Show, Data, Typeable)

-- Ags Boilerplate Code
lexeme_ConsAssignC :: Zipper a -> String
lexeme_ConsAssignC ag = case (getHole ag :: Maybe ListC) of
                          Just(ConsAssignC v _ _) -> v
                          _ -> error "Error in lexeme_ConsAssignC!"

lexeme_InA :: Zipper a -> A
lexeme_InA ag = case (getHole ag :: Maybe InA) of
                  Just (InA a _) -> a

lexeme_ConsLetC :: Zipper a -> String
lexeme_ConsLetC ag = case (getHole ag :: Maybe ListC) of
                       Just(ConsLetC v _ _) -> v
                       _ -> error "Error in lexeme_ConsLetC!"

lexeme_Var :: Zipper a -> String
lexeme_Var ag = case (getHole ag :: Maybe F) of
                  Just (Var s) -> s
                  _ -> error "Error in lexeme_Var!"

lexeme_Const :: Zipper a -> Int
lexeme_Const ag = case (getHole ag :: Maybe F) of
                  Just (Const s) -> s
                  _ -> error "Error in lexeme_Const!"

lexeme_ConsAssignA :: Zipper a -> String
lexeme_ConsAssignA ag = case (getHole ag :: Maybe ListA) of
                          Just(ConsAssignA v _ _ _) -> v
                          _ -> error "Error in lexeme_ConsAssignA!"

lexeme_ConsAssignA_Expr :: Zipper a -> A
lexeme_ConsAssignA_Expr ag = case (getHole ag :: Maybe ListA) of
                              Just(ConsAssignA _ a _ _) -> a
                              _ -> error "Error in lexeme_ConsAssignA_Expr!"

lexeme_ConsLetA :: Zipper a -> String
lexeme_ConsLetA ag = case (getHole ag :: Maybe ListA) of
                       Just(ConsLetA v _ _ _) -> v
                       _ -> error "Error in lexeme_ConsLetA!"

lexeme_Variable :: Zipper a -> String
lexeme_Variable ag = case (getHole ag :: Maybe A) of
                       Just (Variable s _) -> s
                       _ -> error "Error in lexeme_Variable!"

lexeme_Constant :: Zipper a -> Int
lexeme_Constant ag = case (getHole ag :: Maybe A) of
                       Just (Constant s _) -> s
                       _ -> error "Error in lexeme_Constant!"

constructor :: Zipper a -> String
constructor ag = case (getHole ag :: Maybe RootC) of
                   Just (RootC _) -> "RootC"
                   _ -> case (getHole ag :: Maybe LetC) of
                          Just (LetC _ _) -> "LetC"
                          _ -> case (getHole ag :: Maybe InC) of
                                 Just (InC _) -> "InC"
                                 _ -> case (getHole ag :: Maybe ListC) of
                                        Just (ConsLetC _ _ _   ) -> "ConsLetC"
                                        Just (ConsAssignC _ _ _) -> "ConsAssignC"
                                        Just (EmptyListC       ) -> "EmptyListC"
                                        _ -> case (getHole ag :: Maybe E) of
                                               Just (Add _ _) -> "Add"
                                               Just (Sub _ _) -> "Sub"
                                               Just (Et  _  ) -> "Et"
                                               _ -> case (getHole ag :: Maybe T) of
                                                      Just (Mul _ _) -> "Mul"
                                                      Just (Div _ _) -> "Div"
                                                      Just (Tf  _  ) -> "Tf"
                                                      _ -> case (getHole ag :: Maybe F) of
                                                             Just (Nest  _) -> "Nest"
                                                             Just (Neg   _) -> "Neg"
                                                             Just (Const _) -> "Const"
                                                             Just (Var   _) -> "Var"
                                                             _ -> case (getHole ag :: Maybe RootA) of
                                                                    Just (RootA _ _) -> "RootA"
                                                                    _ -> case (getHole ag :: Maybe LetA) of
                                                                           Just (LetA _ _ _) -> "LetA"
                                                                           _ -> case (getHole ag :: Maybe InA) of
                                                                                  Just (InA _ _) -> "InA"
                                                                                  _ -> case (getHole ag :: Maybe ListA) of
                                                                                         Just (ConsLetA _ _ _ _   ) -> "ConsLetA"
                                                                                         Just (ConsAssignA _ _ _ _) -> "ConsAssignA"
                                                                                         Just (EmptyListA _       ) -> "EmptyListA"
                                                                                         _ -> case (getHole ag :: Maybe A) of
                                                                                                Just (Plus _ _ _  ) -> "Plus"
                                                                                                Just (Minus _ _ _ ) -> "Minus"
                                                                                                Just (Time _ _ _  ) -> "Time"
                                                                                                Just (Divide _ _ _) -> "Divide"
                                                                                                Just (Constant _ _) -> "Constant"
                                                                                                Just (Variable _ _) -> "Variable"
                                                                                                _ -> error "Error in constructor!!"