packages feed

hs-java-0.1: JVM/Types.hs

{-# LANGUAGE TypeFamilies, StandaloneDeriving, FlexibleInstances, FlexibleContexts, UndecidableInstances #-}
-- | This module declares `high-level' data types for Java classes, methods etc.
module JVM.Types where

import Codec.Binary.UTF8.String hiding (encode, decode)
import Control.Applicative
import Data.Array
import Data.Binary
import Data.Binary.Put
import qualified Data.ByteString.Lazy as B
import Data.Char
import Data.String
import qualified Data.Set as S
import qualified Data.Map as M

import JVM.ClassFile

instance IsString B.ByteString where
  fromString s = B.pack $ map (fromIntegral . ord) $ encodeString s

toString :: B.ByteString -> String
toString bstr = decodeString $ map (chr . fromIntegral) $ B.unpack bstr

-- | Constant pool
type Pool = Array Word16 Constant

asize :: (Ix i) => Array i e -> Int
asize = length . elems

showListIx :: (Show a) => [a] -> String
showListIx list = unlines $ zipWith s [1..] list
  where s i x = show i ++ ":\t" ++ show x

class HasAttributes a where
  attributes :: a -> Attributes

-- | Java class
data Class = Class {
  constantPool :: Pool,
  classAccess :: Access,
  this :: B.ByteString,        -- ^ this class name
  super :: Maybe B.ByteString, -- ^ super class name
  implements :: [B.ByteString], -- ^ implemented interfaces
  fields :: [Field],
  methods :: [Method],
  classAttrs :: Attributes
  }
  deriving (Eq, Show)

instance HasAttributes Class where
  attributes = classAttrs

class HasSignature a where
  type Signature a

-- | Name and signature pair. Used for methods and fields.
data NameType a = NameType {
  ntName :: B.ByteString,
  ntSignature :: Signature a }

instance Show (Signature a) => Show (NameType a) where
  show (NameType n t) = toString n ++ ": " ++ show t

deriving instance Eq (Signature a) => Eq (NameType a)

-- | Constant pool item
data Constant =
    CClass B.ByteString
  | CField {refClass :: B.ByteString, fieldNameType :: NameType Field}
  | CMethod {refClass :: B.ByteString, nameType :: NameType Method}
  | CIfaceMethod {refClass :: B.ByteString, nameType :: NameType Method}
  | CString B.ByteString
  | CInteger Word32
  | CFloat Float
  | CLong Integer
  | CDouble Double
  | CNameType B.ByteString B.ByteString
  | CUTF8 {getString :: B.ByteString}
  | CUnicode {getString :: B.ByteString}
  deriving (Eq)

className ::  Constant -> B.ByteString
className (CClass s) = s
className x = error $ "Not a class: " ++ show x

instance Show Constant where
  show (CClass name) = "class " ++ toString name
  show (CField cls nt) = "field " ++ toString cls ++ "." ++ show nt
  show (CMethod cls nt) = "method " ++ toString cls ++ "." ++ show nt
  show (CIfaceMethod cls nt) = "interface method " ++ toString cls ++ "." ++ show nt
  show (CString s) = "String \"" ++ toString s ++ "\""
  show (CInteger x) = show x
  show (CFloat x) = show x
  show (CLong x) = show x
  show (CDouble x) = show x
  show (CNameType name tp) = toString name ++ ": " ++ toString tp
  show (CUTF8 s) = "UTF8 \"" ++ toString s ++ "\""
  show (CUnicode s) = "Unicode \"" ++ toString s ++ "\""

-- | Class field
data Field = Field {
  fieldAccess :: Access,
  fieldName :: B.ByteString,
  fieldSignature :: FieldSignature,
  fieldAttrs :: Attributes }
  deriving (Eq, Show)

instance HasSignature Field where
  type Signature Field = FieldSignature

instance HasAttributes Field where
  attributes = fieldAttrs

-- | Class method
data Method = Method {
  methodAccess :: Access,
  methodName :: B.ByteString,
  methodSignature :: MethodSignature,
  methodAttrs :: Attributes }
  deriving (Eq, Show)

instance HasSignature Method where
  type Signature Method = MethodSignature

instance HasAttributes Method where
  attributes = methodAttrs

-- | Set of access flags
type Access = S.Set AccessFlag

-- | Access flags. Used for classess, methods, variables.
data AccessFlag =
    ACC_PUBLIC 	     -- ^ 0x0001 Visible for all
  | ACC_PRIVATE 	   -- ^ 0x0002 Visible only for defined class
  | ACC_PROTECTED 	 -- ^ 0x0004 Visible only for subclasses
  | ACC_STATIC 	     -- ^ 0x0008 Static method or variable
  | ACC_FINAL 	     -- ^ 0x0010 No further subclassing or assignments
  | ACC_SYNCHRONIZED -- ^ 0x0020 Uses monitors
  | ACC_VOLATILE 	   -- ^ 0x0040 Could not be cached
  | ACC_TRANSIENT 	 -- ^ 0x0080 
  | ACC_NATIVE 	     -- ^ 0x0100 Implemented in other language
  | ACC_INTERFACE 	 -- ^ 0x0200 Class is interface
  | ACC_ABSTRACT 	   -- ^ 0x0400 
  deriving (Eq, Show, Ord, Enum)

-- | Generic attribute
data Attribute = Attribute {
  attrName :: B.ByteString,
  attrValue :: B.ByteString }
  deriving (Eq, Show)

-- | Set of attributes
type Attributes = M.Map B.ByteString B.ByteString

instance (Binary (Signature a)) => Binary (NameType a) where
  put (NameType n t) = putLazyByteString n >> put t

  get = NameType <$> get <*> get

byteString ::  (Binary t) => t -> B.ByteString
byteString x = runPut (put x)