{-|
Module      : Htcc.Parser.ConstructionData.Scope.Enumerator
Description : The Data type of typedef and its utilities used in parsing
Copyright   : (c) roki, 2019
License     : MIT
Maintainer  : falgon53@yahoo.co.jp
Stability   : experimental
Portability : POSIX

The Data type of variables and its utilities used in parsing
-}
{-# LANGUAGE DeriveGeneric, OverloadedStrings #-}
module Htcc.Parser.ConstructionData.Scope.Enumerator (
    Enumerator (..),
    Enumerators,
    add
) where

import           Control.DeepSeq                                 (NFData (..))
import qualified Data.Map                                        as M
import qualified Data.Text                                       as T
import           GHC.Generics                                    (Generic (..))

import qualified Htcc.CRules.Types                               as CT
import           Htcc.Parser.AST.Core                            (Treealizable (..),
                                                                  atNumLit)
import           Htcc.Parser.ConstructionData.Scope.ManagedScope
import           Htcc.Parser.ConstructionData.Scope.Utils        (internalCE)
import qualified Htcc.Tokenizer.Token                            as HT

-- | The data type of a enumerator
data Enumerator i = Enumerator
    {
        Enumerator i -> i
enVal        :: i, -- ^ The value of enumerator
        Enumerator i -> StorageClass i
enUnderlying :: CT.StorageClass i -- ^ The underlying type of this enumerator
    } deriving (Enumerator i -> Enumerator i -> Bool
(Enumerator i -> Enumerator i -> Bool)
-> (Enumerator i -> Enumerator i -> Bool) -> Eq (Enumerator i)
forall i. Eq i => Enumerator i -> Enumerator i -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Enumerator i -> Enumerator i -> Bool
$c/= :: forall i. Eq i => Enumerator i -> Enumerator i -> Bool
== :: Enumerator i -> Enumerator i -> Bool
$c== :: forall i. Eq i => Enumerator i -> Enumerator i -> Bool
Eq, Eq (Enumerator i)
Eq (Enumerator i) =>
(Enumerator i -> Enumerator i -> Ordering)
-> (Enumerator i -> Enumerator i -> Bool)
-> (Enumerator i -> Enumerator i -> Bool)
-> (Enumerator i -> Enumerator i -> Bool)
-> (Enumerator i -> Enumerator i -> Bool)
-> (Enumerator i -> Enumerator i -> Enumerator i)
-> (Enumerator i -> Enumerator i -> Enumerator i)
-> Ord (Enumerator i)
Enumerator i -> Enumerator i -> Bool
Enumerator i -> Enumerator i -> Ordering
Enumerator i -> Enumerator i -> Enumerator i
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall i. Ord i => Eq (Enumerator i)
forall i. Ord i => Enumerator i -> Enumerator i -> Bool
forall i. Ord i => Enumerator i -> Enumerator i -> Ordering
forall i. Ord i => Enumerator i -> Enumerator i -> Enumerator i
min :: Enumerator i -> Enumerator i -> Enumerator i
$cmin :: forall i. Ord i => Enumerator i -> Enumerator i -> Enumerator i
max :: Enumerator i -> Enumerator i -> Enumerator i
$cmax :: forall i. Ord i => Enumerator i -> Enumerator i -> Enumerator i
>= :: Enumerator i -> Enumerator i -> Bool
$c>= :: forall i. Ord i => Enumerator i -> Enumerator i -> Bool
> :: Enumerator i -> Enumerator i -> Bool
$c> :: forall i. Ord i => Enumerator i -> Enumerator i -> Bool
<= :: Enumerator i -> Enumerator i -> Bool
$c<= :: forall i. Ord i => Enumerator i -> Enumerator i -> Bool
< :: Enumerator i -> Enumerator i -> Bool
$c< :: forall i. Ord i => Enumerator i -> Enumerator i -> Bool
compare :: Enumerator i -> Enumerator i -> Ordering
$ccompare :: forall i. Ord i => Enumerator i -> Enumerator i -> Ordering
$cp1Ord :: forall i. Ord i => Eq (Enumerator i)
Ord, Int -> Enumerator i -> ShowS
[Enumerator i] -> ShowS
Enumerator i -> String
(Int -> Enumerator i -> ShowS)
-> (Enumerator i -> String)
-> ([Enumerator i] -> ShowS)
-> Show (Enumerator i)
forall i. Show i => Int -> Enumerator i -> ShowS
forall i. Show i => [Enumerator i] -> ShowS
forall i. Show i => Enumerator i -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Enumerator i] -> ShowS
$cshowList :: forall i. Show i => [Enumerator i] -> ShowS
show :: Enumerator i -> String
$cshow :: forall i. Show i => Enumerator i -> String
showsPrec :: Int -> Enumerator i -> ShowS
$cshowsPrec :: forall i. Show i => Int -> Enumerator i -> ShowS
Show, (forall x. Enumerator i -> Rep (Enumerator i) x)
-> (forall x. Rep (Enumerator i) x -> Enumerator i)
-> Generic (Enumerator i)
forall x. Rep (Enumerator i) x -> Enumerator i
forall x. Enumerator i -> Rep (Enumerator i) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall i x. Rep (Enumerator i) x -> Enumerator i
forall i x. Enumerator i -> Rep (Enumerator i) x
$cto :: forall i x. Rep (Enumerator i) x -> Enumerator i
$cfrom :: forall i x. Enumerator i -> Rep (Enumerator i) x
Generic)

instance NFData i => NFData (Enumerator i)

instance Treealizable Enumerator where
    treealize :: Enumerator i -> ATree i
treealize (Enumerator val :: i
val _) = i -> ATree i
forall i. i -> ATree i
atNumLit i
val

instance ManagedScope (Enumerator i) where
    lookup :: Text -> Map Text (Enumerator i) -> Maybe (Enumerator i)
lookup = Text -> Map Text (Enumerator i) -> Maybe (Enumerator i)
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup
    fallBack :: Map Text (Enumerator i)
-> Map Text (Enumerator i) -> Map Text (Enumerator i)
fallBack = Map Text (Enumerator i)
-> Map Text (Enumerator i) -> Map Text (Enumerator i)
forall a b. a -> b -> a
const
    initial :: Map Text (Enumerator i)
initial = Map Text (Enumerator i)
forall k a. Map k a
M.empty

-- | The typedefs data typedefs
type Enumerators i = M.Map T.Text (Enumerator i)

-- | Given the flag (when that is added function, it is `True`. otherwise `False`), type, identifier token, and `Enumerators`,
-- if the specified identifier already exists in the same scope,
-- return an error message and its location as a pair.
-- Otherwise, add a new tag to `Enumerators` and return it.
-- If the token does not indicate an identifier, an error indicating internal compiler error is returned.
add :: Num i => CT.StorageClass i -> HT.TokenLC i -> i -> Enumerators i -> Either (ASTError i) (Enumerators i)
add :: StorageClass i
-> TokenLC i
-> i
-> Enumerators i
-> Either (ASTError i) (Enumerators i)
add t :: StorageClass i
t cur :: TokenLC i
cur@(_, HT.TKIdent ident :: Text
ident) val :: i
val sts :: Enumerators i
sts = case Text -> Enumerators i -> Maybe (Enumerator i)
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Text
ident Enumerators i
sts of
    Just _  -> ASTError i -> Either (ASTError i) (Enumerators i)
forall a b. a -> Either a b
Left ("redeclaration of enumerator '" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
ident Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "'", TokenLC i
cur) -- ODR
    Nothing -> Enumerators i -> Either (ASTError i) (Enumerators i)
forall a b. b -> Either a b
Right (Enumerators i -> Either (ASTError i) (Enumerators i))
-> Enumerators i -> Either (ASTError i) (Enumerators i)
forall a b. (a -> b) -> a -> b
$ Text -> Enumerator i -> Enumerators i -> Enumerators i
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert Text
ident (i -> StorageClass i -> Enumerator i
forall i. i -> StorageClass i -> Enumerator i
Enumerator i
val StorageClass i
t) Enumerators i
sts
add _ _ _ _ = ASTError i -> Either (ASTError i) (Enumerators i)
forall a b. a -> Either a b
Left (Text
internalCE, (i -> i -> TokenLCNums i
forall i. i -> i -> TokenLCNums i
HT.TokenLCNums 0 0, Token i
forall i. Token i
HT.TKEmpty))