{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RecordWildCards #-}

module JVM.Data.Convert.Field where

import Data.Vector qualified as V
import Data.Word (Word16)
import JVM.Data.Abstract.ClassFile.Field qualified as Abs
import JVM.Data.Abstract.ConstantPool (ConstantPoolEntry (..))
import JVM.Data.Convert.AccessFlag (accessFlagsToWord16)
import JVM.Data.Convert.ConstantPool
import JVM.Data.Convert.Monad
import JVM.Data.Convert.Type (fieldTypeDescriptor)
import JVM.Data.Raw.ClassFile qualified as Raw
import Effectful

convertConstantValue :: (ConvertEff r) => Abs.ConstantValue -> Eff r Word16
convertConstantValue :: forall (r :: [Effect]).
ConvertEff r =>
ConstantValue -> Eff r Word16
convertConstantValue =
    (Word16 -> Word16) -> Eff r Word16 -> Eff r Word16
forall a b. (a -> b) -> Eff r a -> Eff r b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Word16 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Eff r Word16 -> Eff r Word16)
-> (ConstantValue -> Eff r Word16) -> ConstantValue -> Eff r Word16
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ConstantPoolEntry -> Eff r Word16
forall (r :: [Effect]).
(ConstantPool :> r) =>
ConstantPoolEntry -> Eff r Word16
findIndexOf (ConstantPoolEntry -> Eff r Word16)
-> (ConstantValue -> ConstantPoolEntry)
-> ConstantValue
-> Eff r Word16
forall b c a. (b -> c) -> (a -> b) -> a -> c
. \case
        Abs.ConstantInteger JVMInt
i -> Int -> ConstantPoolEntry
CPIntegerEntry (JVMInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral JVMInt
i)
        Abs.ConstantFloat JVMFloat
f -> JVMFloat -> ConstantPoolEntry
CPFloatEntry JVMFloat
f
        Abs.ConstantLong JVMLong
l -> Int64 -> ConstantPoolEntry
CPLongEntry (JVMLong -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral JVMLong
l)
        Abs.ConstantDouble JVMDouble
d -> JVMDouble -> ConstantPoolEntry
CPDoubleEntry JVMDouble
d
        Abs.ConstantString JVMString
s -> JVMString -> ConstantPoolEntry
CPStringEntry JVMString
s

convertFieldAttribute :: (ConvertEff  r) => Abs.FieldAttribute -> Eff r Raw.AttributeInfo
convertFieldAttribute :: forall (r :: [Effect]).
ConvertEff r =>
FieldAttribute -> Eff r AttributeInfo
convertFieldAttribute (Abs.ConstantValue ConstantValue
constantValue) = do
    nameIndex <- ConstantPoolEntry -> Eff r Word16
forall (r :: [Effect]).
(ConstantPool :> r) =>
ConstantPoolEntry -> Eff r Word16
findIndexOf (JVMString -> ConstantPoolEntry
CPUTF8Entry JVMString
"ConstantValue")
    constantValueIndex <- convertConstantValue constantValue
    pure $ Raw.AttributeInfo (fromIntegral nameIndex) (Raw.ConstantValueAttribute constantValueIndex)
convertFieldAttribute FieldAttribute
_ = String -> Eff r AttributeInfo
forall a. HasCallStack => String -> a
error String
"convertFieldAttribute"

convertField :: (ConvertEff  r) => Abs.ClassFileField -> Eff r Raw.FieldInfo
convertField :: forall (r :: [Effect]).
ConvertEff r =>
ClassFileField -> Eff r FieldInfo
convertField Abs.ClassFileField{[FieldAccessFlag]
[FieldAttribute]
JVMString
FieldType
fieldAccessFlags :: [FieldAccessFlag]
fieldName :: JVMString
fieldType :: FieldType
fieldAttributes :: [FieldAttribute]
fieldAttributes :: ClassFileField -> [FieldAttribute]
fieldType :: ClassFileField -> FieldType
fieldName :: ClassFileField -> JVMString
fieldAccessFlags :: ClassFileField -> [FieldAccessFlag]
..} = do
    nameIndex <- ConstantPoolEntry -> Eff r Word16
forall (r :: [Effect]).
(ConstantPool :> r) =>
ConstantPoolEntry -> Eff r Word16
findIndexOf (JVMString -> ConstantPoolEntry
CPUTF8Entry JVMString
fieldName)
    descriptorIndex <- findIndexOf (CPUTF8Entry (fieldTypeDescriptor fieldType))
    attributes <- traverse convertFieldAttribute fieldAttributes
    pure $ Raw.FieldInfo (accessFlagsToWord16 fieldAccessFlags) (fromIntegral nameIndex) (fromIntegral descriptorIndex) (V.fromList attributes)