Compare commits

..

8 commits

21 changed files with 148 additions and 62 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "3rdparty/pretty-parse"]
path = 3rdparty/pretty-parse
url = https://git.jossco.de/vegowotenks/pretty-parse

1
3rdparty/pretty-parse vendored Submodule

@ -0,0 +1 @@
Subproject commit a7bff630fc3e5e140274fb65d6b88b46e7a086eb

View file

@ -4,6 +4,8 @@
module Main (main) where
import Data.ByteString.Lazy qualified as ByteString
import Data.Text.Lazy.IO qualified as LazyTextIO
import Pretty.Serialize qualified as Pretty
import Language.Java.Classfile (Classfile)
import Language.Java.Classfile.Extract (runExtract)
@ -13,4 +15,4 @@ import Language.Java.Classfile.Stage (Stage(Parse))
main :: IO ()
main = do
input <- ByteString.getContents
print $ runExtract input (extract @(Classfile Parse))
LazyTextIO.putStrLn . Pretty.serialize $ runExtract input (extract @(Classfile Parse))

View file

@ -44,12 +44,13 @@ library
Paths_java_classfile
hs-source-dirs:
src
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -Wunused-packages
build-depends:
array
, base >=4.7 && <5
, bytestring
, containers
, pretty-parse
, text
default-language: Haskell2010
@ -59,13 +60,12 @@ executable java-classfile-exe
Paths_java_classfile
hs-source-dirs:
app
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -Wunused-packages -threaded -rtsopts -with-rtsopts=-N
build-depends:
array
, base >=4.7 && <5
base >=4.7 && <5
, bytestring
, containers
, java-classfile
, pretty-parse
, text
default-language: Haskell2010
@ -76,12 +76,9 @@ test-suite java-classfile-test
Paths_java_classfile
hs-source-dirs:
test
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -Wunused-packages -threaded -rtsopts -with-rtsopts=-N
build-depends:
array
, base >=4.7 && <5
base >=4.7 && <5
, bytestring
, containers
, java-classfile
, text
default-language: Haskell2010

View file

@ -19,11 +19,8 @@ synopsis: Multi-Stage classfile parsing and verification.
description: Please see the README on Forgejo at <https://git.jossco.de/vegowotenks/java-classfile#readme>
dependencies:
- array
- base >= 4.7 && < 5
- bytestring
- containers
- text
ghc-options:
- -Wall
@ -35,9 +32,15 @@ ghc-options:
- -Wmissing-home-modules
- -Wpartial-fields
- -Wredundant-constraints
- -Wunused-packages
library:
source-dirs: src
dependencies:
- array
- containers
- pretty-parse
- text
executables:
java-classfile-exe:
@ -49,6 +52,8 @@ executables:
- -with-rtsopts=-N
dependencies:
- java-classfile
- pretty-parse
- text
tests:
java-classfile-test:

View file

@ -11,6 +11,7 @@
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Language.Java.Classfile (Classfile(..)) where
import GHC.Generics (Generic, Generically(Generically))
@ -29,6 +30,7 @@ import Language.Java.Classfile.Fields (Fields)
import Language.Java.Classfile.Methods (Methods)
import Language.Java.Classfile.Attributes (Attributes)
import Data.Word (Word16)
import Pretty.Serialize (PrettySerialize)
-- | 'Stage'-indexed classfile. It can represent a class, an interface or a module.
@ -50,6 +52,7 @@ data Classfile stage = Classfile
deriving instance (Show (Magic stage), Show (ConstantPool stage), Show (ClassFlags stage), Show (Class stage)) => Show (Classfile stage)
deriving via Generically (Classfile Parse) instance (Extractable (Classfile Parse))
deriving via Generically (Classfile Parse) instance (PrettySerialize (Classfile Parse))
type ClassFlags :: Stage -> Type
data family ClassFlags stage
@ -57,18 +60,20 @@ data family ClassFlags stage
newtype instance ClassFlags Parse = ClassFlags (Flags ClassFlag)
deriving stock (Show, Generic)
deriving Extractable via Generically (ClassFlags Parse)
deriving newtype PrettySerialize
data ClassFlag
= Public
| Final
| Super
| Interface
| Abstract
| Synthetic
| Annotation
| Enum
| Module
deriving (Show, Eq, Ord, Enum, Bounded)
= Public -- ^ may be accessed from outside the package
| Final -- ^ no subclasses allowed
| Super -- ^ treat superclass methods special when using InvokeSpecial
| Interface -- ^ is an interface
| Abstract -- ^ abstract, must not be instantiated
| Synthetic -- ^ not present in source code
| Annotation -- ^ is annotation interface
| Enum -- ^ enumerated instances
| Module -- ^ module, not a class
deriving (Show, Eq, Ord, Enum, Bounded, Generic)
deriving PrettySerialize via Generically ClassFlag
instance FlagMask ClassFlag where
type FlagType ClassFlag = Word16

View file

@ -10,6 +10,7 @@ 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(..) )
import Pretty.Serialize (PrettySerialize)
-- | Generic Attribute array used everywhere.
--
@ -17,7 +18,7 @@ import GHC.Generics ( Generic, Generically(..) )
newtype Attributes = Attributes (Array Word16 Attribute)
deriving stock (Show)
deriving newtype Extractable
deriving newtype (Extractable, PrettySerialize)
-- | Unknown Attribute
@ -26,4 +27,4 @@ data Attribute = Attribute
, info :: SizedBytes Word32
}
deriving stock (Show, Generic)
deriving Extractable via Generically Attribute
deriving (Extractable, PrettySerialize) via Generically Attribute

View file

@ -1,6 +1,5 @@
-- | THE constant pool, all the constants in a class file are handled in here.
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE OverloadedStrings #-}
@ -10,6 +9,8 @@
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE DeriveGeneric #-}
module Language.Java.Classfile.ConstantPool (ConstantPool(..)) where
import Data.Word (Word16)
import Data.Array.IArray (Array, listArray)
@ -19,13 +20,19 @@ import Language.Java.Classfile.Extract (Extract, traceIndex, traceType)
import qualified Data.Text as Text
import Language.Java.Classfile.Stage (Stage(..))
import Data.Kind (Type)
import GHC.Generics (Generically(..), Generic)
import Pretty.Serialize (PrettySerialize)
type ConstantPool :: Stage -> Type
data ConstantPool stage where
ConstantPool :: (Array Word16 Entry) -> ConstantPool Parse
NoPool :: ConstantPool Resolve
data family ConstantPool stage
newtype instance ConstantPool Parse = ConstantPool (Array Word16 Entry)
deriving stock (Generic, Show)
deriving via (Generically (ConstantPool Parse)) instance PrettySerialize (ConstantPool Parse)
data instance ConstantPool Resolve = NoPool
deriving instance Show (ConstantPool stage)
-- | 'Stage'-indexed constant-pool. The constant-pool is erased after resolving the class file.

View file

@ -8,6 +8,7 @@
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OrPatterns #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Language.Java.Classfile.ConstantPool.Entry (Entry(..), StorageCount(..), storageCount, MethodHandleInfo(..)) where
import GHC.Generics (Generic, Generically(..))
import Language.Java.Classfile.Extractable (Extractable (extract))
@ -20,6 +21,7 @@ import Language.Java.Classfile.Extract (Extract, bytes)
import qualified Data.Text.Encoding as Text
import qualified Data.ByteString.Lazy as ByteString
import qualified Data.ByteString as StrictByteString
import Pretty.Serialize (PrettySerialize)
-- | A single entry. Double and Long are not followed by something unusable, they are duplicated instead.
@ -60,6 +62,7 @@ data Entry
-- ^ Some package description
deriving stock (Show, Generic)
deriving Extractable via Generically Entry
deriving PrettySerialize via Generically Entry
-- | Holds the invariants of MethodHandles (Only certain references are allowed after some kinds)
--
@ -68,11 +71,13 @@ data Entry
data MethodHandleInfo = MethodHandleInfo MethodHandleReferenceKind OpaqueReference
deriving stock (Show, Generic)
deriving Extractable via Generically MethodHandleInfo
deriving PrettySerialize via Generically MethodHandleInfo
-- | Extractor newtype for a java-utf-text with size tag specified as a type argument.
newtype SizedText sizeType = SizedText Text
deriving stock (Show)
deriving newtype PrettySerialize
instance (Integral sizeType, Extractable sizeType) => Extractable (SizedText sizeType) where
extract :: Extract (SizedText sizeType)

View file

@ -7,6 +7,7 @@
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE DeriveGeneric #-}
module Language.Java.Classfile.ConstantPool.References (Utf8Reference(..), ClassReference(..), NameAndTypeReference(..), MethodHandleReferenceKind(..), OpaqueReference(..), BootstrapMethodIndex(..), Class) where
import Data.Word (Word16, Word8)
import Language.Java.Classfile.Extractable (Extractable)
@ -14,12 +15,15 @@ import Language.Java.Classfile.Extractable.AsTag
( TagValue(..), AsTag, AsTag(..) )
import Language.Java.Classfile.Stage (Stage(..))
import Data.Kind (Type)
import Pretty.Serialize (PrettySerialize)
import GHC.Generics (Generically(..), Generic)
-- | Wrapper for constant-pool reference to text.
newtype Utf8Reference = Utf8Reference Word16
deriving stock (Show)
deriving stock (Show, Generic)
deriving newtype Extractable
deriving PrettySerialize via Generically Utf8Reference
-- | 'Stage'-indexed type, either a Class or only a t'ClassReference'.
@ -30,26 +34,30 @@ type family Class stage where
-- | Reference to a class in a constant-pool. This will resolve into a class.
newtype ClassReference = ClassReference Word16
deriving stock (Show)
deriving stock (Show, Generic)
deriving newtype Extractable
deriving PrettySerialize via Generically ClassReference
-- | Reference to a class in a constant-pool. This will resolve to Name and Type.
newtype NameAndTypeReference = NameAndTypeReference Word16
deriving stock (Show)
deriving stock (Show, Generic)
deriving newtype Extractable
deriving PrettySerialize via Generically NameAndTypeReference
-- | Reference to something in a constant-pool. I will hopefully get rid of this type.
newtype OpaqueReference = OpaqueReference Word16
deriving stock (Show)
deriving stock (Show, Generic)
deriving newtype Extractable
deriving PrettySerialize via Generically OpaqueReference
-- | Reference to a method in the BootstrapMethods class attribute
newtype BootstrapMethodIndex = BootstrapMethodIndex Word16
deriving stock (Show)
deriving stock (Show, Generic)
deriving newtype Extractable
deriving PrettySerialize via Generically BootstrapMethodIndex
-- | A Tag used to determine the type of a MethodHandle
@ -63,8 +71,9 @@ data MethodHandleReferenceKind
| InvokeSpecial
| NewInvokeSpecial
| InvokeInterface
deriving stock (Show, Enum, Bounded)
deriving stock (Show, Enum, Bounded, Generic)
deriving Extractable via AsTag MethodHandleReferenceKind
deriving PrettySerialize via Generically MethodHandleReferenceKind
instance TagValue MethodHandleReferenceKind where
type TagType MethodHandleReferenceKind = Word8

View file

@ -2,19 +2,30 @@
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE DeriveGeneric #-}
module Language.Java.Classfile.Extract (Extract(), bytes, runExtract, expectRaw, expectEqual, traceType, traceConstructor, traceField, traceIndex, Reason(..), Trace(..), Expected(..), Actual(..), TypeName(..)) where
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as ByteString
import Control.Applicative (Alternative (empty, (<|>)))
import Control.Monad (MonadPlus)
import GHC.Generics (Generic, Generically(..))
import Data.ByteString.Lazy (ByteString)
import Data.Text (Text)
import qualified Data.Text as Text
import Data.Typeable (Typeable, typeOf)
import Pretty.Serialize (PrettySerialize)
import qualified Data.ByteString.Lazy as ByteString
import qualified Data.Text as Text
-- | Extractor Monad. Computations running in this monad will automatically keep track of used resources and backtrack arbitrarily.
newtype Extract a = Extract (Continuation a)
deriving (Functor)
deriving anyclass MonadPlus
-- | Functions work wonders when defining monads.
@ -29,15 +40,18 @@ data Reply a
-- | Type Alias for the Show instance
newtype Expected = Expected Text
deriving Show
deriving stock (Show, Generic)
deriving PrettySerialize via Generically Expected
-- | Type Alias for the Show instance
newtype Actual = Actual Text
deriving Show
deriving stock (Show, Generic)
deriving PrettySerialize via Generically Actual
-- | Type Alias for the Show instance
newtype TypeName = TypeName Text
deriving Show
deriving stock (Show, Generic)
deriving PrettySerialize via Generically TypeName
-- | Why did the computation fail?
@ -50,7 +64,8 @@ data Reason
-- ^ Something else went wrong
| Unknown
-- ^ Someone used the 'empty' function from 'Alternative'
deriving Show
deriving stock (Show, Generic)
deriving PrettySerialize via Generically Reason
-- | Where did the computation fail? Calls to these functions are auto-generated by the Generic instances.
@ -59,7 +74,8 @@ data Trace
| InConstructor Text
| InField Text
| AtIndex Word
deriving Show
deriving stock (Show, Generic)
deriving PrettySerialize via Generically Trace
instance Applicative Extract where
-- | Don't consume any input

View file

@ -1,20 +1,22 @@
-- | Read arbitrary bytes prefixed with a length.
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DerivingVia #-}
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
import Pretty.Serialize (PrettySerialize, ShowPrettySerialize(..))
-- | The sizeType type Paramter is used to extract the correct byte count.
newtype SizedBytes sizeType = SizedBytes ByteString
deriving stock Show
deriving PrettySerialize via ShowPrettySerialize (SizedBytes sizeType)
instance (Extractable sizeType, Integral sizeType) => Extractable (SizedBytes sizeType) where
extract :: Extract (SizedBytes sizeType)

View file

@ -16,6 +16,7 @@ import Control.Monad (void)
import Data.Proxy (Proxy(Proxy))
import Data.Typeable ( Typeable )
import Data.Word (Word8)
import Pretty.Serialize (PrettySerialize)
-- | Type alias if you use the same type a lot.
@ -25,7 +26,7 @@ type Word8Tag value a = WithNumericTag value Word8 a
type WithNumericTag :: Natural -> Type -> Type -> Type
newtype WithNumericTag value tagType a = Tagged a
deriving newtype Show
deriving newtype (Show, PrettySerialize)
instance (KnownNat value, Extractable a, Extractable tagType, Eq tagType, Num tagType, Show tagType, Typeable tagType) => Extractable (WithNumericTag value tagType a) where
extract :: Extract (WithNumericTag value tagType a)

View file

@ -14,12 +14,13 @@ import GHC.Generics ( Generically, Generic, Generically(..) )
import Language.Java.Classfile.Flags (Flags, FlagMask (..))
import Language.Java.Classfile.ConstantPool.References (Utf8Reference)
import Language.Java.Classfile.Attributes (Attributes)
import Pretty.Serialize (PrettySerialize)
-- | Word16-Array of Fields.
newtype Fields = Fields (Array Word16 Field)
deriving stock Show
deriving newtype Extractable
deriving newtype (Extractable, PrettySerialize)
-- | All the access flags a field can have
@ -33,7 +34,8 @@ data FieldFlag
| Transient
| Synthetic
| Enumeration -- original "Enum"
deriving stock (Show, Eq, Ord, Enum, Bounded)
deriving stock (Show, Eq, Ord, Enum, Bounded, Generic)
deriving PrettySerialize via Generically FieldFlag
instance FlagMask FieldFlag where
type FlagType FieldFlag = Word16
@ -58,4 +60,4 @@ data Field = Field
, attribute :: Attributes
}
deriving stock (Show, Generic)
deriving Extractable via Generically Field
deriving (Extractable, PrettySerialize) via Generically Field

View file

@ -6,10 +6,13 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeFamilies #-}
module Language.Java.Classfile.Flags (Flags(..), FlagMask(..)) where
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Language.Java.Classfile.Flags (Flags(..), FlagMask(..), containsFlag) where
import Data.Bits (Bits((.&.)))
import Data.Bits (Bits((.&.), zeroBits))
import Data.Enum.Util (enumerate)
import Data.Set (Set)
@ -18,11 +21,15 @@ import qualified Data.Set as Set
import Language.Java.Classfile.Extract (Extract)
import Language.Java.Classfile.Extractable (Extractable (extract))
import Data.Kind (Type)
import Control.Arrow ((>>>))
import qualified Data.List as List
import Pretty.Serialize (PrettySerialize)
-- | Using the 'FlagMask' instance of the type parameter, this will extract all the flags whose mask produced a non-zero value using '.&.'
newtype Flags a = Flags (Set a)
deriving (Show)
deriving newtype PrettySerialize
instance (Extractable (FlagType a), Bounded a, Enum a, Ord a, FlagMask a, Bits (FlagType a), Num (FlagType a)) => Extractable (Flags a) where
extract :: Extract (Flags a)
@ -39,3 +46,13 @@ class FlagMask a where
type FlagType a :: Type
maskOf :: a -> FlagType a
ofMask :: FlagType a -> Set a
default ofMask :: (Enum a, Bounded a, Ord a, Bits (FlagType a)) => FlagType a -> Set a
ofMask mask = List.filter (containsFlag mask)
>>> Set.fromList
$ enumerate @a
containsFlag :: (Bits (FlagType a), FlagMask a) => FlagType a -> a -> Bool
containsFlag mask flag = mask .&. maskOf flag /= zeroBits

View file

@ -8,9 +8,10 @@ import Data.Word (Word16)
import Language.Java.Classfile.ConstantPool.References (ClassReference)
import Language.Java.Classfile.Extractable (Extractable)
import GHC.Generics ( Generic, Generically, Generically(..) )
import Pretty.Serialize (PrettySerialize)
-- | A list of classes something implements.
newtype Interfaces = Interfaces (Array Word16 ClassReference)
deriving stock (Show, Generic)
deriving Extractable via Generically Interfaces
deriving (Extractable, PrettySerialize) via Generically Interfaces

View file

@ -6,6 +6,8 @@
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DerivingVia #-}
module Language.Java.Classfile.Magic (Magic(..)) where
import Data.Word (Word32)
import Language.Java.Classfile.Extractable (Extractable, extract, expectConstant)
@ -13,6 +15,7 @@ import Language.Java.Classfile.Extract (Extract)
import Data.Hex (Hex (Hex))
import Language.Java.Classfile.Stage (Stage(Parse, Resolve))
import Data.Kind (Type)
import Pretty.Serialize (ShowPrettySerialize(ShowPrettySerialize), PrettySerialize)
-- | 'Stage'-indexed Magic type. The 'Resolve' stage is only a unit type.
@ -21,6 +24,9 @@ data Magic stage where
Magic :: Hex Word32 -> Magic Parse
Cafebabe :: Magic Resolve
deriving instance Show (Magic stage)
deriving via ShowPrettySerialize (Magic stage) instance PrettySerialize (Magic stage)
instance Extractable (Magic Parse) where
extract :: Extract (Magic Parse)
extract = Magic . Hex <$> expectConstant 0xCAFEBABE

View file

@ -14,12 +14,13 @@ import Language.Java.Classfile.Extractable (Extractable)
import GHC.Generics ( Generically, Generic, Generically(..) )
import Language.Java.Classfile.ConstantPool.References (Utf8Reference)
import Language.Java.Classfile.Attributes (Attributes)
import Pretty.Serialize (PrettySerialize)
-- | Alias for the methods structure from the constant-pool.
newtype Methods = Methods (Array Word16 Method)
deriving stock (Show)
deriving newtype Extractable
deriving newtype (Extractable, PrettySerialize)
-- | A single method record, contains attributes, name and access flags.
@ -30,7 +31,7 @@ data Method = Method
, attributes :: Attributes
}
deriving stock (Show, Generic)
deriving Extractable via Generically Method
deriving (Extractable, PrettySerialize) via Generically Method
-- | Flags for the method, such as abstract, public or static.
@ -47,7 +48,8 @@ data MethodFlag
| Abstract
| Strict
| Synthetic
deriving stock (Show, Eq, Ord, Enum, Bounded)
deriving stock (Show, Eq, Ord, Enum, Bounded, Generic)
deriving PrettySerialize via Generically MethodFlag
instance FlagMask MethodFlag where
type FlagType MethodFlag = Word16

View file

@ -7,6 +7,7 @@ module Language.Java.Classfile.Version (Version(..)) where
import Data.Word (Word16)
import GHC.Generics (Generic, Generically(Generically))
import Language.Java.Classfile.Extractable (Extractable)
import Pretty.Serialize (PrettySerialize)
-- | Classfile versions only have two components. The minor component is zero since some java version.
@ -15,7 +16,7 @@ data Version = Version
, major :: Word16
}
deriving stock (Show, Generic)
deriving Extractable via Generically Version
deriving (Extractable, PrettySerialize) via Generically Version
-- >>> import Language.Java.Classfile.Extractable (Extractable(extract))
-- >>> import Language.Java.Classfile.Extract (runExtract, Extract)

View file

@ -17,7 +17,8 @@
#
# snapshot: ./custom-snapshot.yaml
# snapshot: https://example.com/snapshots/2024-01-01.yaml
snapshot: nightly-2025-07-10
snapshot:
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/3.yaml
compiler: ghc-9.12.1
# User packages to be built.
@ -31,6 +32,7 @@ compiler: ghc-9.12.1
# - wai
packages:
- .
- 3rdparty/pretty-parse
# Dependency packages to be pulled from upstream that are not in the snapshot.
# These entries can reference officially published versions as well as
# forks / in-progress versions pinned to a git hash. For example:

View file

@ -6,7 +6,8 @@
packages: []
snapshots:
- completed:
sha256: 39e3a4dc79edf153bb0aa6dc4206b1543c0e0f3e3811ec751abdcdf3aaf08887
size: 723871
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2025/7/10.yaml
original: nightly-2025-07-10
sha256: aa97dce5253937e4aa56100a0a9dc1f79a554cf543ad7cfab0afe6ed42de2f31
size: 724941
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/3.yaml
original:
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/3.yaml