diff --git a/java-classfile.cabal b/java-classfile.cabal index abee9b8..873be6e 100644 --- a/java-classfile.cabal +++ b/java-classfile.cabal @@ -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 diff --git a/src/Language/Java/Classfile.hs b/src/Language/Java/Classfile.hs index 00507bb..3b89665 100644 --- a/src/Language/Java/Classfile.hs +++ b/src/Language/Java/Classfile.hs @@ -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 diff --git a/src/Language/Java/Classfile/Attributes.hs b/src/Language/Java/Classfile/Attributes.hs new file mode 100644 index 0000000..425b28e --- /dev/null +++ b/src/Language/Java/Classfile/Attributes.hs @@ -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 diff --git a/src/Language/Java/Classfile/ConstantPool.hs b/src/Language/Java/Classfile/ConstantPool.hs index 946706a..38a35d9 100644 --- a/src/Language/Java/Classfile/ConstantPool.hs +++ b/src/Language/Java/Classfile/ConstantPool.hs @@ -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 diff --git a/src/Language/Java/Classfile/ConstantPool/Entry.hs b/src/Language/Java/Classfile/ConstantPool/Entry.hs index e8b5ef7..804a9a4 100644 --- a/src/Language/Java/Classfile/ConstantPool/Entry.hs +++ b/src/Language/Java/Classfile/ConstantPool/Entry.hs @@ -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 + + diff --git a/src/Language/Java/Classfile/Extractable.hs b/src/Language/Java/Classfile/Extractable.hs index 109e7d4..a2617f4 100644 --- a/src/Language/Java/Classfile/Extractable.hs +++ b/src/Language/Java/Classfile/Extractable.hs @@ -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) diff --git a/src/Language/Java/Classfile/Extractable/SizedBytes.hs b/src/Language/Java/Classfile/Extractable/SizedBytes.hs new file mode 100644 index 0000000..21d8dbf --- /dev/null +++ b/src/Language/Java/Classfile/Extractable/SizedBytes.hs @@ -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) + diff --git a/src/Language/Java/Classfile/Fields.hs b/src/Language/Java/Classfile/Fields.hs new file mode 100644 index 0000000..e7bf4f8 --- /dev/null +++ b/src/Language/Java/Classfile/Fields.hs @@ -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