feat: Field and attribute parsing

This commit is contained in:
vegowotenks 2025-07-12 23:17:24 +02:00
parent 62b537a93f
commit f9fbedc87a
8 changed files with 136 additions and 7 deletions

View file

@ -28,13 +28,16 @@ library
Data.Enum.Util
Data.Hex
Language.Java.Classfile
Language.Java.Classfile.Attributes
Language.Java.Classfile.ClassFlag
Language.Java.Classfile.ConstantPool
Language.Java.Classfile.ConstantPool.Entry
Language.Java.Classfile.ConstantPool.References
Language.Java.Classfile.Extract
Language.Java.Classfile.Extractable
Language.Java.Classfile.Extractable.SizedBytes
Language.Java.Classfile.Extractable.WithTag
Language.Java.Classfile.Fields
Language.Java.Classfile.Flag
Language.Java.Classfile.Flags
Language.Java.Classfile.FromBigEndian

View file

@ -10,6 +10,7 @@ import Language.Java.Classfile.Flags (Flags)
import Language.Java.Classfile.ClassFlag (ClassFlag)
import Language.Java.Classfile.ConstantPool.References (ClassReference)
import Language.Java.Classfile.Interfaces (Interfaces)
import Language.Java.Classfile.Fields (Fields)
data Classfile = Classfile
{ magic :: Magic
@ -19,6 +20,7 @@ data Classfile = Classfile
, this :: ClassReference
, super :: ClassReference
, interfaces :: Interfaces
, fields :: Fields
}
deriving stock (Show, Generic)
deriving Extractable via Generically Classfile

View file

@ -0,0 +1,21 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE DeriveGeneric #-}
module Language.Java.Classfile.Attributes (Attributes(..), Attribute(..)) where
import Data.Array.IArray (Array)
import Data.Word (Word16, Word32)
import Language.Java.Classfile.Extractable (Extractable)
import Language.Java.Classfile.ConstantPool.References (Utf8Reference)
import Language.Java.Classfile.Extractable.SizedBytes (SizedBytes)
import GHC.Generics ( Generic, Generically(..) )
newtype Attributes = Attributes (Array Word16 Attribute)
deriving stock (Show)
deriving newtype Extractable
data Attribute = Attribute
{ name :: Utf8Reference
, info :: SizedBytes Word32
}
deriving stock (Show, Generic)
deriving Extractable via Generically Attribute

View file

@ -1,13 +1,15 @@
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE OverloadedStrings #-}
module Language.Java.Classfile.ConstantPool (ConstantPool(..)) where
import Data.Word (Word16)
import Data.Array.IArray (Array, listArray)
import Language.Java.Classfile.ConstantPool.Entry (Entry)
import Language.Java.Classfile.ConstantPool.Entry (Entry, StorageCount (..), storageCount)
import Language.Java.Classfile.Extractable (Extractable (extract))
import Language.Java.Classfile.Extract (Extract, traceIndex)
import Language.Java.Classfile.Extract (Extract, traceIndex, traceType)
import Control.Monad (forM)
import qualified Data.Text as Text
newtype ConstantPool = ConstantPool (Array Word16 Entry)
deriving stock (Show)
@ -16,5 +18,21 @@ instance Extractable ConstantPool where
extract :: Extract ConstantPool
extract = do
count <- extract @Word16
elements <- forM [1..fromIntegral count - 1] $ \ i -> traceIndex i extract
pure . ConstantPool $ listArray (1, count - 1) elements
let typeName = Text.concat
[ "ConstantPool ("
, Text.pack . show $ count
, ")"
]
let extractElements index end
| index == end = pure []
| otherwise = do
element <- traceIndex index extract
case storageCount element of
Once -> (element:) <$> extractElements (succ index) end
Twice -> ([element, element] <>) <$> extractElements (index + 2) end
traceType typeName $ do
elements <- extractElements 1 (fromIntegral count)
pure . ConstantPool $ listArray (1, count - 1) elements

View file

@ -4,7 +4,9 @@
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE InstanceSigs #-}
module Language.Java.Classfile.ConstantPool.Entry (Entry(..)) where
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OrPatterns #-}
module Language.Java.Classfile.ConstantPool.Entry (Entry(..), StorageCount(..), storageCount) where
import GHC.Generics (Generic, Generically(..))
import Language.Java.Classfile.Extractable (Extractable (extract))
import Language.Java.Classfile.Extractable.WithTag (Word8Tag)
@ -55,3 +57,11 @@ instance (Integral sizeType, Extractable sizeType) => Extractable (SizedText siz
Left err -> fail $ show err
Right t -> pure $ SizedText t
data StorageCount = Once | Twice
storageCount :: Entry -> StorageCount
storageCount = \case
(Double _ ; Long _) -> Twice
_ -> Once

View file

@ -78,8 +78,8 @@ instance (Extractable index, Extractable element, Ix index, Integral index, Show
then pure $ listArray (1, 0) []
else traceType typeName $ do
elements <- forM [0..fromIntegral count] $ \ i -> traceIndex i extract
pure $ listArray (1, count) elements
elements <- forM [0..fromIntegral count - 1] $ \ i -> traceIndex i extract
pure $ listArray (0, count - 1) elements
deriving via Generically () instance Extractable ()
deriving via Generically (a, b) instance (Extractable a, Extractable b) => Extractable (a, b)

View file

@ -0,0 +1,20 @@
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Language.Java.Classfile.Extractable.SizedBytes (SizedBytes(..)) where
import Data.ByteString (ByteString)
import Language.Java.Classfile.Extractable (Extractable (..))
import Language.Java.Classfile.Extract (Extract, bytes)
import qualified Data.ByteString as StrictByteString
import qualified Data.ByteString.Lazy as ByteString
newtype SizedBytes sizeType = SizedBytes ByteString
deriving stock Show
instance (Extractable sizeType, Integral sizeType) => Extractable (SizedBytes sizeType) where
extract :: Extract (SizedBytes sizeType)
extract = do
size <- extract @sizeType
SizedBytes . StrictByteString.concat . ByteString.toChunks <$> bytes (fromIntegral size)

View file

@ -0,0 +1,55 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE LambdaCase #-}
module Language.Java.Classfile.Fields (Fields(..)) where
import Data.Array.IArray (Array)
import Data.Word (Word16)
import Language.Java.Classfile.Extractable (Extractable)
import GHC.Generics ( Generically, Generic, Generically(..) )
import Language.Java.Classfile.Flags (Flags)
import Language.Java.Classfile.Flag (FlagMask (..))
import Language.Java.Classfile.ConstantPool.References (Utf8Reference)
import Language.Java.Classfile.Attributes (Attributes)
newtype Fields = Fields (Array Word16 Field)
deriving stock Show
deriving newtype Extractable
data FieldFlag
= Public
| Private
| Protected
| Static
| Final
| Volatile
| Transient
| Synthetic
| Enumeration -- original "Enum"
deriving stock (Show, Eq, Ord, Enum, Bounded)
instance FlagMask FieldFlag where
type FlagType FieldFlag = Word16
maskOf :: FieldFlag -> FlagType FieldFlag
maskOf = \case
Public -> 0x0001
Private -> 0x0002
Protected -> 0x0004
Static -> 0x0008
Final -> 0x0010
Volatile -> 0x0040
Transient -> 0x0080
Synthetic -> 0x1000
Enumeration -> 0x4000
data Field = Field
{ flags :: Flags FieldFlag
, name :: Utf8Reference
, descriptor :: Utf8Reference
, attribute :: Attributes
}
deriving stock (Show, Generic)
deriving Extractable via Generically Field