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.Enum.Util
Data.Hex Data.Hex
Language.Java.Classfile Language.Java.Classfile
Language.Java.Classfile.Attributes
Language.Java.Classfile.ClassFlag Language.Java.Classfile.ClassFlag
Language.Java.Classfile.ConstantPool Language.Java.Classfile.ConstantPool
Language.Java.Classfile.ConstantPool.Entry Language.Java.Classfile.ConstantPool.Entry
Language.Java.Classfile.ConstantPool.References Language.Java.Classfile.ConstantPool.References
Language.Java.Classfile.Extract Language.Java.Classfile.Extract
Language.Java.Classfile.Extractable Language.Java.Classfile.Extractable
Language.Java.Classfile.Extractable.SizedBytes
Language.Java.Classfile.Extractable.WithTag Language.Java.Classfile.Extractable.WithTag
Language.Java.Classfile.Fields
Language.Java.Classfile.Flag Language.Java.Classfile.Flag
Language.Java.Classfile.Flags Language.Java.Classfile.Flags
Language.Java.Classfile.FromBigEndian 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.ClassFlag (ClassFlag)
import Language.Java.Classfile.ConstantPool.References (ClassReference) import Language.Java.Classfile.ConstantPool.References (ClassReference)
import Language.Java.Classfile.Interfaces (Interfaces) import Language.Java.Classfile.Interfaces (Interfaces)
import Language.Java.Classfile.Fields (Fields)
data Classfile = Classfile data Classfile = Classfile
{ magic :: Magic { magic :: Magic
@ -19,6 +20,7 @@ data Classfile = Classfile
, this :: ClassReference , this :: ClassReference
, super :: ClassReference , super :: ClassReference
, interfaces :: Interfaces , interfaces :: Interfaces
, fields :: Fields
} }
deriving stock (Show, Generic) deriving stock (Show, Generic)
deriving Extractable via Generically Classfile 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 DerivingStrategies #-}
{-# LANGUAGE InstanceSigs #-} {-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeApplications #-}
{-# LANGUAGE OverloadedStrings #-}
module Language.Java.Classfile.ConstantPool (ConstantPool(..)) where module Language.Java.Classfile.ConstantPool (ConstantPool(..)) where
import Data.Word (Word16) import Data.Word (Word16)
import Data.Array.IArray (Array, listArray) 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.Extractable (Extractable (extract))
import Language.Java.Classfile.Extract (Extract, traceIndex) import Language.Java.Classfile.Extract (Extract, traceIndex, traceType)
import Control.Monad (forM) import Control.Monad (forM)
import qualified Data.Text as Text
newtype ConstantPool = ConstantPool (Array Word16 Entry) newtype ConstantPool = ConstantPool (Array Word16 Entry)
deriving stock (Show) deriving stock (Show)
@ -16,5 +18,21 @@ instance Extractable ConstantPool where
extract :: Extract ConstantPool extract :: Extract ConstantPool
extract = do extract = do
count <- extract @Word16 count <- extract @Word16
elements <- forM [1..fromIntegral count - 1] $ \ i -> traceIndex i extract
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 pure . ConstantPool $ listArray (1, count - 1) elements

View file

@ -4,7 +4,9 @@
{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE InstanceSigs #-} {-# 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 GHC.Generics (Generic, Generically(..))
import Language.Java.Classfile.Extractable (Extractable (extract)) import Language.Java.Classfile.Extractable (Extractable (extract))
import Language.Java.Classfile.Extractable.WithTag (Word8Tag) import Language.Java.Classfile.Extractable.WithTag (Word8Tag)
@ -55,3 +57,11 @@ instance (Integral sizeType, Extractable sizeType) => Extractable (SizedText siz
Left err -> fail $ show err Left err -> fail $ show err
Right t -> pure $ SizedText t 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) [] then pure $ listArray (1, 0) []
else traceType typeName $ do else traceType typeName $ do
elements <- forM [0..fromIntegral count] $ \ i -> traceIndex i extract elements <- forM [0..fromIntegral count - 1] $ \ i -> traceIndex i extract
pure $ listArray (1, count) elements pure $ listArray (0, count - 1) elements
deriving via Generically () instance Extractable () deriving via Generically () instance Extractable ()
deriving via Generically (a, b) instance (Extractable a, Extractable b) => Extractable (a, b) 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