1 {-# LANGUAGE FlexibleContexts, TypeFamilies, OverloadedStrings #-}
2 module JVM.Generator where
4 import Control.Monad.State as St
9 import qualified Data.Map as M
10 import qualified Data.Set as S
11 import qualified Data.ByteString.Lazy as B
17 data GState = GState {
18 generated :: [Instruction],
20 doneMethods :: [Method],
21 currentMethod :: Maybe Method}
24 emptyGState = GState {
26 currentPool = listArray (0,0) [CInteger 0],
28 currentMethod = Nothing }
30 type Generate a = State GState a
32 appendPool :: Constant -> Pool -> (Pool, Word16)
34 let list = assocs pool
35 size = fromIntegral (length list)
36 list' = list ++ [(size, c)]
37 in (array (0, size) list',
40 addItem :: Constant -> Generate Word16
42 pool <- St.gets currentPool
43 case lookupPool c pool of
46 let (pool', i) = appendPool c pool
48 St.put $ st {currentPool = pool'}
51 lookupPool :: Constant -> Pool -> Maybe Word16
53 fromIntegral `fmap` findIndex (== c) (elems pool)
55 addNT :: Binary (Signature a) => NameType a -> Generate Word16
56 addNT (NameType name sig) = do
60 addItem (CNameType name bsig)
62 addToPool :: Constant -> Generate Word16
63 addToPool c@(CClass str) = do
66 addToPool c@(CField cls name) = do
67 addToPool (CClass cls)
70 addToPool c@(CMethod cls name) = do
71 addToPool (CClass cls)
74 addToPool c@(CIfaceMethod cls name) = do
75 addToPool (CClass cls)
78 addToPool c@(CString str) = do
81 addToPool c@(CNameType name sig) = do
85 addToPool c = addItem c
87 putInstruction :: Instruction -> Generate ()
88 putInstruction instr = do
90 let code = generated st
91 St.put $ st {generated = code ++ [instr]}
93 i0 :: Instruction -> Generate ()
96 i1 :: (Word16 -> Instruction) -> Constant -> Generate ()
101 startMethod :: B.ByteString -> MethodSignature -> Generate ()
102 startMethod name sig = do
104 let method = Method {
105 methodAccess = S.fromList [ACC_PUBLIC],
107 methodSignature = sig,
108 methodAttrs = M.empty }
109 St.put $ st {generated = [],
110 currentMethod = Just method }
112 endMethod :: Generate ()
114 m <- St.gets currentMethod
115 code <- St.gets genCode
117 Nothing -> fail "endMethod without startMethod!"
119 let method' = method {methodAttrs = M.fromList [("Code", encodeMethod code)] }
121 St.put $ st {generated = [],
122 currentMethod = Nothing,
123 doneMethods = doneMethods st ++ [method']}
125 newMethod :: B.ByteString -> [ArgumentSignature] -> ReturnSignature -> Generate () -> Generate ()
126 newMethod name args ret gen = do
127 startMethod name (MethodSignature args ret)
131 genCode :: GState -> Code
133 codeStackSize = 4096,
136 codeInstructions = generated st,
140 codeAttributes = [] }
142 len = fromIntegral $ B.length $ encodeInstructions (generated st)
144 generate :: B.ByteString -> Generate () -> Class
146 let res = execState gen emptyGState
149 constantPool = currentPool res,
150 classAccess = S.fromList [ACC_PUBLIC],
155 methods = doneMethods res,
156 classAttrs = M.empty }