feat: partial classfile staging

This commit is contained in:
vegowotenks 2025-07-13 10:00:15 +02:00
parent d692c3a6c0
commit 00898b18dc
10 changed files with 136 additions and 35 deletions

View file

@ -1,5 +1,6 @@
{-# LANGUAGE ImportQualifiedPost #-} {-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeApplications #-}
{-# LANGUAGE DataKinds #-}
module Main (main) where module Main (main) where
import Data.ByteString.Lazy qualified as ByteString import Data.ByteString.Lazy qualified as ByteString
@ -7,8 +8,9 @@ import Data.ByteString.Lazy qualified as ByteString
import Language.Java.Classfile (Classfile) import Language.Java.Classfile (Classfile)
import Language.Java.Classfile.Extract (runExtract) import Language.Java.Classfile.Extract (runExtract)
import Language.Java.Classfile.Extractable (extract) import Language.Java.Classfile.Extractable (extract)
import Language.Java.Classfile.Stage (Stage(Parse))
main :: IO () main :: IO ()
main = do main = do
input <- ByteString.getContents input <- ByteString.getContents
print $ runExtract input (extract @Classfile) print $ runExtract input (extract @(Classfile Parse))

View file

@ -35,6 +35,7 @@ library
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.AsTag
Language.Java.Classfile.Extractable.SizedBytes Language.Java.Classfile.Extractable.SizedBytes
Language.Java.Classfile.Extractable.WithTag Language.Java.Classfile.Extractable.WithTag
Language.Java.Classfile.Fields Language.Java.Classfile.Fields
@ -44,6 +45,7 @@ library
Language.Java.Classfile.Interfaces Language.Java.Classfile.Interfaces
Language.Java.Classfile.Magic Language.Java.Classfile.Magic
Language.Java.Classfile.Methods Language.Java.Classfile.Methods
Language.Java.Classfile.Stage
Language.Java.Classfile.Version Language.Java.Classfile.Version
other-modules: other-modules:
Paths_java_classfile Paths_java_classfile

View file

@ -1,9 +1,19 @@
{-# LANGUAGE DerivingVia #-} {-# LANGUAGE DerivingVia #-}
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeFamilies #-}
module Language.Java.Classfile (Classfile(..)) where module Language.Java.Classfile (Classfile(..)) where
import GHC.Generics (Generic, Generically(Generically)) import GHC.Generics (Generic, Generically(Generically))
import Data.Kind (Type)
import Language.Java.Classfile.Stage (Stage(Parse))
import Language.Java.Classfile.Version (Version) import Language.Java.Classfile.Version (Version)
import Language.Java.Classfile.Magic (Magic) import Language.Java.Classfile.Magic (Magic)
import Language.Java.Classfile.Extractable (Extractable) import Language.Java.Classfile.Extractable (Extractable)
@ -17,11 +27,12 @@ import Language.Java.Classfile.Methods (Methods)
import Language.Java.Classfile.Attributes (Attributes) import Language.Java.Classfile.Attributes (Attributes)
data Classfile = Classfile type Classfile :: Stage -> Type
{ magic :: Magic data Classfile stage = Classfile
{ magic :: Magic stage
, version :: Version , version :: Version
, constantPool :: ConstantPool , constantPool :: ConstantPool stage
, accessFlags :: Flags ClassFlag , accessFlags :: ClassFlags stage
, this :: ClassReference , this :: ClassReference
, super :: ClassReference , super :: ClassReference
, interfaces :: Interfaces , interfaces :: Interfaces
@ -29,5 +40,14 @@ data Classfile = Classfile
, methods :: Methods , methods :: Methods
, attributes :: Attributes , attributes :: Attributes
} }
deriving stock (Generic)
deriving instance (Show (Magic stage), Show (ConstantPool stage), Show (ClassFlags stage)) => Show (Classfile stage)
deriving via Generically (Classfile Parse) instance (Extractable (Classfile Parse))
type ClassFlags :: Stage -> Type
data family ClassFlags stage
newtype instance ClassFlags Parse = ClassFlags (Flags ClassFlag)
deriving stock (Show, Generic) deriving stock (Show, Generic)
deriving Extractable via Generically Classfile deriving Extractable via Generically (ClassFlags Parse)

View file

@ -2,6 +2,10 @@
{-# LANGUAGE InstanceSigs #-} {-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeApplications #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
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)
@ -9,12 +13,19 @@ import Language.Java.Classfile.ConstantPool.Entry (Entry, StorageCount (..), sto
import Language.Java.Classfile.Extractable (Extractable (extract)) import Language.Java.Classfile.Extractable (Extractable (extract))
import Language.Java.Classfile.Extract (Extract, traceIndex, traceType) import Language.Java.Classfile.Extract (Extract, traceIndex, traceType)
import qualified Data.Text as Text import qualified Data.Text as Text
import Language.Java.Classfile.Stage (Stage(..))
import Data.Kind (Type)
newtype ConstantPool = ConstantPool (Array Word16 Entry) type ConstantPool :: Stage -> Type
data family ConstantPool stage
newtype instance ConstantPool Parse = ConstantPool (Array Word16 Entry)
deriving stock (Show) deriving stock (Show)
instance Extractable ConstantPool where data instance ConstantPool Resolve = NoPool
extract :: Extract ConstantPool
instance Extractable (ConstantPool Parse) where
extract :: Extract (ConstantPool Parse)
extract = do extract = do
count <- extract @Word16 count <- extract @Word16

View file

@ -1,12 +1,14 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingVia #-} {-# LANGUAGE DerivingVia #-}
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE LambdaCase #-}
module Language.Java.Classfile.ConstantPool.References (Utf8Reference(..), ClassReference(..), NameAndTypeReference(..), MethodHandleReferenceKind(..), OpaqueReference(..), BootstrapMethodIndex(..)) where module Language.Java.Classfile.ConstantPool.References (Utf8Reference(..), ClassReference(..), NameAndTypeReference(..), MethodHandleReferenceKind(..), OpaqueReference(..), BootstrapMethodIndex(..)) where
import Data.Word (Word16) import Data.Word (Word16, Word8)
import Language.Java.Classfile.Extractable (Extractable) import Language.Java.Classfile.Extractable (Extractable)
import Language.Java.Classfile.Extractable.WithTag (Word8Tag) import Language.Java.Classfile.Extractable.AsTag
import GHC.Generics (Generically(..), Generic) ( TagValue(..), AsTag, AsTag(..) )
newtype Utf8Reference = Utf8Reference Word16 newtype Utf8Reference = Utf8Reference Word16
deriving stock (Show) deriving stock (Show)
@ -29,14 +31,28 @@ newtype BootstrapMethodIndex = BootstrapMethodIndex Word16
deriving newtype Extractable deriving newtype Extractable
data MethodHandleReferenceKind data MethodHandleReferenceKind
= GetField (Word8Tag 1 ()) -- I kind of want to redo this = GetField
| GetStatic (Word8Tag 2 ()) | GetStatic
| PutField (Word8Tag 3 ()) | PutField
| PutStatic (Word8Tag 4 ()) | PutStatic
| InvokeVirtual (Word8Tag 5 ()) | InvokeVirtual
| InvokeStatic (Word8Tag 6 ()) | InvokeStatic
| InvokeSpecial (Word8Tag 7 ()) | InvokeSpecial
| NewInvokeSpecial (Word8Tag 8 ()) | NewInvokeSpecial
| InvokeInterface (Word8Tag 9 ()) | InvokeInterface
deriving stock (Show, Generic) deriving stock (Show, Enum, Bounded)
deriving Extractable via Generically MethodHandleReferenceKind deriving Extractable via AsTag MethodHandleReferenceKind
instance TagValue MethodHandleReferenceKind where
type TagType MethodHandleReferenceKind = Word8
tagOf :: MethodHandleReferenceKind -> TagType MethodHandleReferenceKind
tagOf = \case
GetField -> 1
GetStatic -> 2
PutField -> 3
PutStatic -> 4
InvokeVirtual -> 5
InvokeStatic -> 6
InvokeSpecial -> 7
NewInvokeSpecial -> 8
InvokeInterface -> 9

View file

@ -0,0 +1,30 @@
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
module Language.Java.Classfile.Extractable.AsTag (AsTag(..), TagValue(..)) where
import Data.Kind (Type)
import Language.Java.Classfile.Extractable (Extractable (extract), expectConstant)
import Language.Java.Classfile.Extract (Extract)
import Data.Enum.Util (enumerate)
import Control.Applicative (asum)
import Data.Functor (($>))
import Data.Typeable ( Typeable )
newtype AsTag a = AsTag a
deriving Show
instance (Extractable (TagType a), Bounded a, Enum a, Eq (TagType a), Show (TagType a), Typeable (TagType a), TagValue a ) => Extractable (AsTag a) where
extract :: Extract (AsTag a)
extract = do
let expectTag con = expectConstant (tagOf con) $> con
let allConstructors = expectTag <$> enumerate @a
AsTag <$> asum allConstructors
class TagValue a where
type TagType a :: Type
tagOf :: a -> TagType a

View file

@ -5,13 +5,16 @@
{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE UndecidableInstances #-}
module Language.Java.Classfile.Flags (Flags(..)) where module Language.Java.Classfile.Flags (Flags(..)) where
import Data.Set (Set)
import Language.Java.Classfile.Extractable (Extractable (extract))
import Language.Java.Classfile.Extract (Extract)
import Language.Java.Classfile.Flag (FlagMask(..))
import Data.Enum.Util (enumerate)
import qualified Data.Set as Set
import Data.Bits (Bits((.&.))) import Data.Bits (Bits((.&.)))
import Data.Enum.Util (enumerate)
import Data.Set (Set)
import qualified Data.Set as Set
import Language.Java.Classfile.Extract (Extract)
import Language.Java.Classfile.Extractable (Extractable (extract))
import Language.Java.Classfile.Flag (FlagMask(..))
newtype Flags a = Flags (Set a) newtype Flags a = Flags (Set a)
deriving (Show) deriving (Show)

View file

@ -1,19 +1,31 @@
{-# LANGUAGE InstanceSigs #-} {-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE FlexibleInstances #-}
module Language.Java.Classfile.Magic (Magic(..)) where module Language.Java.Classfile.Magic (Magic(..)) where
import Data.Word (Word32) import Data.Word (Word32)
import Language.Java.Classfile.Extractable (Extractable, extract, expectConstant) import Language.Java.Classfile.Extractable (Extractable, extract, expectConstant)
import Language.Java.Classfile.Extract (Extract) import Language.Java.Classfile.Extract (Extract)
import Data.Hex (Hex (Hex)) import Data.Hex (Hex (Hex))
import Language.Java.Classfile.Stage (Stage(Parse, Resolve))
import Data.Kind (Type)
newtype Magic = Magic (Hex Word32) type Magic :: Stage -> Type
data family Magic stage
newtype instance Magic Parse = Magic (Hex Word32)
deriving Show deriving Show
instance Extractable Magic where data instance Magic Resolve = Cafebabe
extract :: Extract Magic deriving Show
instance Extractable (Magic Parse) where
extract :: Extract (Magic Parse)
extract = Magic . Hex <$> expectConstant 0xCAFEBABE extract = Magic . Hex <$> expectConstant 0xCAFEBABE
-- >>> :set -XOverloadedLists -- >>> :set -XOverloadedLists
-- >>> import Language.Java.Classfile.Extract (runExtract) -- >>> import Language.Java.Classfile.Extract (runExtract)
-- >>> runExtract [0xCA, 0xFE, 0xBA, 0xBE] (Hex <$> (extract :: Extract (Word32))) -- >>> runExtract [0xCA, 0xFE, 0xBA, 0xBE] (Hex <$> (extract :: Extract (Word32)))
-- Just ("",Hex 0xbebafeca) -- Right ("",Hex 0xcafebabe)

View file

@ -0,0 +1,6 @@
{-# LANGUAGE DataKinds #-}
module Language.Java.Classfile.Stage (Stage(..)) where
data Stage
= Parse
| Resolve

View file

@ -1,4 +1,3 @@
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingVia #-} {-# LANGUAGE DerivingVia #-}
module Language.Java.Classfile.Version (Version(..)) where module Language.Java.Classfile.Version (Version(..)) where