{-
-- EPITECH PROJECT, 2026
-- Glados
-- File description:
-- step2MakeClosureLabel
-}

module Compiler.ResolveLabels.Step2MakeClosureLabel (step2MakeClosureLabel) where

import Compiler.Instruction (Instruction(..), instructionSize)
import Data.Text (Text)
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set
import qualified Data.Text as T
import Compiler.ResolveLabels.ResolveLabelsHelpers (computeOffset, checkInt32Range)

step2MakeClosureLabel :: Map.Map Text Int -> Set.Set Int ->
    [Instruction] -> Int -> Text -> Int -> Either Text ([Instruction], Int)
step2MakeClosureLabel :: Map Text Int
-> Set Int
-> [Instruction]
-> Int
-> Text
-> Int
-> Either Text ([Instruction], Int)
step2MakeClosureLabel Map Text Int
labelMap Set Int
starts [Instruction]
out Int
idx Text
name Int
n =
    case Text -> Map Text Int -> Maybe Int
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Text
name Map Text Int
labelMap of
        Maybe Int
Nothing -> Text -> Either Text ([Instruction], Int)
forall a b. a -> Either a b
Left (String -> Text
T.pack String
"Unknown label: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
name)
        Just Int
target ->
            case Int -> Set Int -> Bool
forall a. Ord a => a -> Set a -> Bool
Set.member Int
target Set Int
starts of
                Bool
True -> Int
-> [Instruction]
-> Int
-> Text
-> Int
-> Either Text ([Instruction], Int)
makeClosureResult Int
target [Instruction]
out Int
idx Text
name Int
n
                Bool
False -> Text -> Either Text ([Instruction], Int)
forall a b. a -> Either a b
Left (String -> Text
T.pack
                    String
"MakeClosure target not at instruction boundary")

makeClosureResult :: Int -> [Instruction] -> Int ->
    Text -> Int -> Either Text ([Instruction], Int)
makeClosureResult :: Int
-> [Instruction]
-> Int
-> Text
-> Int
-> Either Text ([Instruction], Int)
makeClosureResult Int
target [Instruction]
out Int
idx Text
name Int
n =
    let mcSize :: Int
mcSize = Instruction -> Int
instructionSize (Int -> Int -> Instruction
MakeClosure Int
0 Int
0)
        off64 :: Int64
off64 = Int -> Int -> Int64
computeOffset Int
target (Int
idx Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
mcSize) in
    case Int64 -> Either Text Int32
checkInt32Range Int64
off64 of
        Left Text
err -> Text -> Either Text ([Instruction], Int)
forall a b. a -> Either a b
Left (String -> Text
T.pack String
"MakeClosure offset for label '"
            Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
name Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack String
"' " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
err)
        Right Int32
off ->
            ([Instruction], Int) -> Either Text ([Instruction], Int)
forall a b. b -> Either a b
Right ([Instruction]
out [Instruction] -> [Instruction] -> [Instruction]
forall a. [a] -> [a] -> [a]
++ [Int -> Int -> Instruction
MakeClosure (Int32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
off) Int
n], Int
idx Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
mcSize)