{-
-- EPITECH PROJECT, 2025
-- Glados
-- File description:
-- CompilerState
-}

{-|
Module : Compiler.CompilerState
Description : Core types and state for the Compiler logic.
Stability : stable
-}
module Compiler.CompilerState
    ( CompilerState(..)
    , SymTable
    , ScopeType(..)
    , createCompilerState
    ) where

import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Sequence (Seq)
import qualified Data.Sequence as Seq
import Data.Text (Text)

import Compiler.PsInstruction (PsInstruction(..))

-- | Defines the memory scope of a variable.
--
-- @details
--   This enumeration is used in the symbol table to determine which
--   VM instruction (LOAD_GLOBAL, LOAD_LOCAL, or LOAD_CAPTURE) should be
--   emitted when a symbol is referenced.
--
data ScopeType 
    = ScopeGlobal   -- ^ Global variable (LOAD_GLOBAL)
    | ScopeLocal    -- ^ Local argument or variable (LOAD_LOCAL)
    | ScopeCapture  -- ^ Variable captured by a closure (LOAD_CAPTURE)
    deriving (Int -> ScopeType -> ShowS
[ScopeType] -> ShowS
ScopeType -> String
(Int -> ScopeType -> ShowS)
-> (ScopeType -> String)
-> ([ScopeType] -> ShowS)
-> Show ScopeType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ScopeType -> ShowS
showsPrec :: Int -> ScopeType -> ShowS
$cshow :: ScopeType -> String
show :: ScopeType -> String
$cshowList :: [ScopeType] -> ShowS
showList :: [ScopeType] -> ShowS
Show, ScopeType -> ScopeType -> Bool
(ScopeType -> ScopeType -> Bool)
-> (ScopeType -> ScopeType -> Bool) -> Eq ScopeType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ScopeType -> ScopeType -> Bool
== :: ScopeType -> ScopeType -> Bool
$c/= :: ScopeType -> ScopeType -> Bool
/= :: ScopeType -> ScopeType -> Bool
Eq)

-- | Symbol table mapping textual names to their scope and index.
--
-- @details
--   SymTable stores the mapping required to resolve variable names to
--   concrete memory indices. 
--     - ScopeType: Determines which LOAD instruction to use.
--     - MemoryIndex: The integer offset in the stack/heap.
--     - TypeName: The string representation of the variable's type.
--
type SymTable = Map Text (ScopeType, Int, Text)

-- | Compiler state holding code buffers and symbol information.
--
-- @details
--   The CompilerState maintains two code buffers: 'csCode' for the current
--   block being compiled (e.g., main or current function body) and 'csFuncs'
--   for accumulating the code of defined functions and lambdas that will be
--   appended at the end of the binary.
--
-- @return
--   N/A (this documents the type)
--
data CompilerState = CompilerState
    { CompilerState -> Seq PsInstruction
csCode      :: (Seq PsInstruction)      -- ^ Generated code (in natural order)
    , CompilerState -> Seq PsInstruction
csFuncs     :: Seq PsInstruction        -- ^ Compiled functions' buffer
    , CompilerState -> SymTable
csSymbols   :: SymTable                 -- ^ Local variable mapping
    , CompilerState -> Map Text [(Text, Text)]
csStructs   :: Map Text [(Text, Text)]  -- ^ Struct definitions (Name -> Field Names in order)
    , CompilerState -> Int
csNextIndex :: Int                      -- ^ Next available local index
    , CompilerState -> Int
csLabelCnt  :: Int                      -- ^ Counter for unique label generation
    , CompilerState -> ScopeType
csScopeContext :: ScopeType             -- ^ Scope context (used to determine variables scopes)
    , CompilerState -> Int
csCurrentArgCount :: Int                -- ^ Number of args on the stack (atomic return clean)
    , CompilerState -> [Text]
csLoopExits :: [Text]                   -- ^ Stack of loop exit labels (for break)
    } deriving (Int -> CompilerState -> ShowS
[CompilerState] -> ShowS
CompilerState -> String
(Int -> CompilerState -> ShowS)
-> (CompilerState -> String)
-> ([CompilerState] -> ShowS)
-> Show CompilerState
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CompilerState -> ShowS
showsPrec :: Int -> CompilerState -> ShowS
$cshow :: CompilerState -> String
show :: CompilerState -> String
$cshowList :: [CompilerState] -> ShowS
showList :: [CompilerState] -> ShowS
Show, CompilerState -> CompilerState -> Bool
(CompilerState -> CompilerState -> Bool)
-> (CompilerState -> CompilerState -> Bool) -> Eq CompilerState
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CompilerState -> CompilerState -> Bool
== :: CompilerState -> CompilerState -> Bool
$c/= :: CompilerState -> CompilerState -> Bool
/= :: CompilerState -> CompilerState -> Bool
Eq)

-- | Initial, empty compiler state.
--
-- @details
--   Provides a fresh CompilerState with no code, an empty symbol table, the
--   next local index set to 0 and the label counter set to 0.
--
-- @return
--   A 'CompilerState' initialized for a new compilation unit.
--
createCompilerState :: CompilerState
createCompilerState :: CompilerState
createCompilerState = CompilerState
    { csCode :: Seq PsInstruction
csCode = Seq PsInstruction
forall a. Seq a
Seq.empty
    , csFuncs :: Seq PsInstruction
csFuncs = Seq PsInstruction
forall a. Seq a
Seq.empty
    , csSymbols :: SymTable
csSymbols = SymTable
forall k a. Map k a
Map.empty
    , csStructs :: Map Text [(Text, Text)]
csStructs = Map Text [(Text, Text)]
forall k a. Map k a
Map.empty
    , csNextIndex :: Int
csNextIndex = Int
0
    , csLabelCnt :: Int
csLabelCnt = Int
0
    , csScopeContext :: ScopeType
csScopeContext = ScopeType
ScopeGlobal
    , csCurrentArgCount :: Int
csCurrentArgCount = Int
0
    , csLoopExits :: [Text]
csLoopExits = [] }