H2JVM - A Haskell Library for writing JVM Bytecode
Looks good and plainly written, I’ll bookmark it for next time I do something with the JVM
Browsed around and reviewed a little, have a few random suggestions
You can avoid the possibility of an UnmarkedLabel error using a MonadFix instance and rec or mdo
emitNewLabel = do
label <- newLabel
emit $ JVM.Label label
pure label
mdo
emit $ JVM.IfICmp (IfGt trueLabel)
emit JVM.IConst0
emit $ Goto endLabel
emit JVM.IConst1
trueLabel <- emitNewLabel
emit JVM.IConst1
endLabel <- emitNewLabel
pure ()
I’d rather use rec to spell out the scope, but this case is better with mdo because the labels are used throughout
In CodeState instead of storing a list in reverse order you can use a DList Instruction
Code that uses IfCond is repetitive because it’s denormalised
data IfCond label = IfEq label | IfNe label | IfLt label | IfGe label | IfGt label | IfLe label
Instead you can factor:
1 x +1 x +1 x +1 x +1 x +1 x = (1+1+1+1+1+1)x = 6 x
data If label = If Cond label
data Cond = Eq | Ne | Lt | Ge | Gt | Le
Can also keep the current patterns with synonyms like pattern IfEq label = If Eq label and a {-# COMPLETE #-} pragma
In clauses of Pretty instances like this
pretty (InvokeSpecial c n d) =
"invokespecial" <+> pretty c <> "." <> pretty n <> pretty d
I like to use ViewPatterns (or a synonym) so the shape of the output is less cluttered by calls to pretty, and it’s only called once if used more than once
pretty (InvokeSpecial (pretty -> c) (pretty -> n) (pretty -> d)) =
"invokespecial" <+> c <> "." <> n <> d
I dunno how “pretty” you actually want for the pretty-printing to be, but I find that Pretty instances in general tend to overuse the explicit non-breaking horizontal (hcat, hsep, <>, <+>) and vertical (vcat, vsep) layouts without enough grouping, and should rather use the grouped combinators that allow breaks between all (cat, sep, surround softline', surround softline) or between any (fillCat, fillSep)
Discussion in the ATmosphere