{-# LANGUAGE DisambiguateRecordFields #-}
{-# LANGUAGE LexicalNegation #-}

{- | Converts abstract instructions into raw instructions, including resolving labels into offsets.
TODO: this is very inefficient, requiring three passes over the instructions
-}
module H2JVM.Internal.Convert.Instruction (CodeConverterEff, fullyRunCodeConverter, convertInstructions, fullyResolveAbs, ConvertState (..)) where

import Data.List.NonEmpty (NonEmpty)
import Data.Map (Map)
import Data.Maybe
import Data.Word (Word16)
import Effectful
import Effectful.Error.Static
import Effectful.State.Static.Local hiding (modifyM)
import Witch

import Data.List.NonEmpty qualified as NE
import Data.Map qualified as Map

import H2JVM.Builder.Label
import H2JVM.ConstantPool (ConstantPoolEntry (..), FieldRef (..), MethodRef (..))
import H2JVM.Descriptor
import H2JVM.Instruction as Abs (IfCond (..), Instruction, Instruction' (..), LDCEntry (..))
import H2JVM.Internal.Convert.ConstantPool
import H2JVM.Internal.Convert.Monad
import H2JVM.Internal.Raw.Instruction as Raw (Instruction (..))
import H2JVM.Internal.Raw.Types (U1)
import H2JVM.Internal.Util (bug)
import H2JVM.Type

import H2JVM.Internal.Raw.MagicNumbers qualified as MagicNumbers

type CodeConverterEff r = (ConstantPoolEff r, State ConvertState :> r, Error CodeConverterError :> r)

fullyRunCodeConverter :: ConvertEff r' => Eff (State ConvertState : r') a -> Eff r' a
fullyRunCodeConverter :: forall (r' :: [Effect]) a.
ConvertEff r' =>
Eff (State ConvertState : r') a -> Eff r' a
fullyRunCodeConverter Eff (State ConvertState : r') a
r = do
    (a, _) <- ConvertState
-> Eff (State ConvertState : r') a -> Eff r' (a, ConvertState)
forall s (es :: [Effect]) a.
HasCallStack =>
s -> Eff (State s : es) a -> Eff es (a, s)
runState (Word16 -> Map Label Word16 -> ConvertState
ConvertState Word16
0 Map Label Word16
forall k a. Map k a
Map.empty) Eff (State ConvertState : r') a
r
    pure a

data ConvertState = ConvertState
    { ConvertState -> Word16
currentOffset :: Word16
    , ConvertState -> Map Label Word16
labelOffsets :: Map Label Word16
    }

countArguments :: MethodDescriptor -> Int
countArguments :: MethodDescriptor -> Int
countArguments (MethodDescriptor [FieldType]
args ReturnDescriptor
_) = Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ [Int] -> Int
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ((FieldType -> Int) -> [FieldType] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map FieldType -> Int
countArgument [FieldType]
args)
  where
    countArgument :: FieldType -> Int
    countArgument :: FieldType -> Int
countArgument (PrimitiveFieldType PrimitiveType
JDouble) = Int
2
    countArgument (PrimitiveFieldType PrimitiveType
JLong) = Int
2
    countArgument FieldType
_ = Int
1

-- | The size of an instruction in bytes, used for calculating jump offsets
instructionSize :: Abs.Instruction -> Word16
instructionSize :: Instruction -> Word16
instructionSize Instruction
Abs.AALoad = Word16
1
instructionSize (Abs.ALoad Word16
n)
    | Word16
n Word16 -> Word16 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word16
3 = Word16
1
    | Word16
n Word16 -> Word16 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word16
255 = Word16
2
    | Bool
otherwise = Word16
4 -- wide (1) + opcode (1) + index (2)
instructionSize (Abs.AStore Word16
n)
    | Word16
n Word16 -> Word16 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word16
3 = Word16
1
    | Word16
n Word16 -> Word16 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word16
255 = Word16
2
    | Bool
otherwise = Word16
4
instructionSize (Abs.ILoad Word16
n)
    | Word16
n Word16 -> Word16 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word16
3 = Word16
1
    | Word16
n Word16 -> Word16 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word16
255 = Word16
2
    | Bool
otherwise = Word16
4
instructionSize (Abs.IStore Word16
n)
    | Word16
n Word16 -> Word16 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word16
3 = Word16
1
    | Word16
n Word16 -> Word16 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word16
255 = Word16
2
    | Bool
otherwise = Word16
4
instructionSize Instruction
Abs.AReturn = Word16
1
instructionSize Instruction
Abs.ArrayLength = Word16
1
instructionSize Instruction
Abs.AConstNull = Word16
1
instructionSize Instruction
Abs.IAnd = Word16
1
instructionSize (Abs.If IfCond Label
_) = Word16
3
instructionSize (Abs.Instanceof{}) = Word16
3
instructionSize (Abs.InvokeStatic{}) = Word16
3
instructionSize (Abs.InvokeVirtual{}) = Word16
3
instructionSize (Abs.InvokeInterface{}) = Word16
5
instructionSize (Abs.InvokeDynamic{}) = Word16
5
instructionSize (Abs.InvokeSpecial{}) = Word16
3
instructionSize Instruction
Abs.IOr = Word16
1
instructionSize (Abs.Label Label
_) = Word16
0
instructionSize (Abs.LDC LDCEntry
_) = Word16
3
instructionSize (Abs.PutStatic{}) = Word16
3
instructionSize (Abs.GetField{}) = Word16
3
instructionSize (Abs.GetStatic{}) = Word16
3
instructionSize (Abs.PutField{}) = Word16
3
instructionSize (Abs.CheckCast ClassInfoType
_) = Word16
3
instructionSize Instruction
Abs.Return = Word16
1
instructionSize Instruction
Abs.IReturn = Word16
1
instructionSize Instruction
Abs.IConst0 = Word16
1
instructionSize Instruction
Abs.IConst1 = Word16
1
instructionSize Instruction
Abs.Dup = Word16
1
instructionSize (Abs.Goto Label
_) = Word16
3
instructionSize (Abs.New ClassInfoType
_) = Word16
3
instructionSize (Abs.IfICmp IfCond Label
_) = Word16
3
instructionSize Instruction
Abs.IAdd = Word16
1
instructionSize Instruction
Abs.ISub = Word16
1
instructionSize Instruction
Abs.IMul = Word16
1
instructionSize Instruction
Abs.IDiv = Word16
1

convertInstructions :: (CodeConverterEff r, HasCallStack) => NonEmpty Abs.Instruction -> Eff r (NonEmpty Raw.Instruction)
convertInstructions :: forall (r :: [Effect]).
(CodeConverterEff r, HasCallStack) =>
NonEmpty Instruction -> Eff r (NonEmpty Instruction)
convertInstructions NonEmpty Instruction
xs = do
    withOffsets <- NonEmpty Instruction
-> Eff r (NonEmpty (OffsetInstruction Instruction))
forall (r :: [Effect]).
(HasCallStack, CodeConverterEff r) =>
NonEmpty Instruction
-> Eff r (NonEmpty (OffsetInstruction Instruction))
insertAllLabels NonEmpty Instruction
xs
    insts <- traverse (resolveLabel . fmap (fmap UnresolvedLabel)) withOffsets
    finalInsts <- catMaybes <$> traverse convertInstruction (NE.toList insts)
    case NE.nonEmpty finalInsts of
        Just NonEmpty Instruction
ne -> NonEmpty Instruction -> Eff r (NonEmpty Instruction)
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure NonEmpty Instruction
ne
        Maybe (NonEmpty Instruction)
Nothing -> CodeConverterError -> Eff r (NonEmpty Instruction)
forall e (es :: [Effect]) a.
(HasCallStack, Error e :> es, Show e) =>
e -> Eff es a
throwError (CodeConverterError -> Eff r (NonEmpty Instruction))
-> CodeConverterError -> Eff r (NonEmpty Instruction)
forall a b. (a -> b) -> a -> b
$ NonEmpty Instruction -> CodeConverterError
NoValidInstructions NonEmpty Instruction
xs

data MaybeResolvedLabel = ResolvedLabel Word16 | UnresolvedLabel Label

-- | An instruction with a resolved offset.
data OffsetInstruction a
    = -- | an instruction with a real offset
      OffsetInstruction
        -- | the offset.
        Word16
        -- | the instruction.
        a
    | -- | a label pseudo-instruction
      LabelInstruction a
    deriving (OffsetInstruction a -> OffsetInstruction a -> Bool
(OffsetInstruction a -> OffsetInstruction a -> Bool)
-> (OffsetInstruction a -> OffsetInstruction a -> Bool)
-> Eq (OffsetInstruction a)
forall a.
Eq a =>
OffsetInstruction a -> OffsetInstruction a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall a.
Eq a =>
OffsetInstruction a -> OffsetInstruction a -> Bool
== :: OffsetInstruction a -> OffsetInstruction a -> Bool
$c/= :: forall a.
Eq a =>
OffsetInstruction a -> OffsetInstruction a -> Bool
/= :: OffsetInstruction a -> OffsetInstruction a -> Bool
Eq, (forall a b.
 (a -> b) -> OffsetInstruction a -> OffsetInstruction b)
-> (forall a b. a -> OffsetInstruction b -> OffsetInstruction a)
-> Functor OffsetInstruction
forall a b. a -> OffsetInstruction b -> OffsetInstruction a
forall a b. (a -> b) -> OffsetInstruction a -> OffsetInstruction b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b. (a -> b) -> OffsetInstruction a -> OffsetInstruction b
fmap :: forall a b. (a -> b) -> OffsetInstruction a -> OffsetInstruction b
$c<$ :: forall a b. a -> OffsetInstruction b -> OffsetInstruction a
<$ :: forall a b. a -> OffsetInstruction b -> OffsetInstruction a
Functor, Eq (OffsetInstruction a)
Eq (OffsetInstruction a) =>
(OffsetInstruction a -> OffsetInstruction a -> Ordering)
-> (OffsetInstruction a -> OffsetInstruction a -> Bool)
-> (OffsetInstruction a -> OffsetInstruction a -> Bool)
-> (OffsetInstruction a -> OffsetInstruction a -> Bool)
-> (OffsetInstruction a -> OffsetInstruction a -> Bool)
-> (OffsetInstruction a
    -> OffsetInstruction a -> OffsetInstruction a)
-> (OffsetInstruction a
    -> OffsetInstruction a -> OffsetInstruction a)
-> Ord (OffsetInstruction a)
OffsetInstruction a -> OffsetInstruction a -> Bool
OffsetInstruction a -> OffsetInstruction a -> Ordering
OffsetInstruction a -> OffsetInstruction a -> OffsetInstruction a
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall a. Ord a => Eq (OffsetInstruction a)
forall a.
Ord a =>
OffsetInstruction a -> OffsetInstruction a -> Bool
forall a.
Ord a =>
OffsetInstruction a -> OffsetInstruction a -> Ordering
forall a.
Ord a =>
OffsetInstruction a -> OffsetInstruction a -> OffsetInstruction a
$ccompare :: forall a.
Ord a =>
OffsetInstruction a -> OffsetInstruction a -> Ordering
compare :: OffsetInstruction a -> OffsetInstruction a -> Ordering
$c< :: forall a.
Ord a =>
OffsetInstruction a -> OffsetInstruction a -> Bool
< :: OffsetInstruction a -> OffsetInstruction a -> Bool
$c<= :: forall a.
Ord a =>
OffsetInstruction a -> OffsetInstruction a -> Bool
<= :: OffsetInstruction a -> OffsetInstruction a -> Bool
$c> :: forall a.
Ord a =>
OffsetInstruction a -> OffsetInstruction a -> Bool
> :: OffsetInstruction a -> OffsetInstruction a -> Bool
$c>= :: forall a.
Ord a =>
OffsetInstruction a -> OffsetInstruction a -> Bool
>= :: OffsetInstruction a -> OffsetInstruction a -> Bool
$cmax :: forall a.
Ord a =>
OffsetInstruction a -> OffsetInstruction a -> OffsetInstruction a
max :: OffsetInstruction a -> OffsetInstruction a -> OffsetInstruction a
$cmin :: forall a.
Ord a =>
OffsetInstruction a -> OffsetInstruction a -> OffsetInstruction a
min :: OffsetInstruction a -> OffsetInstruction a -> OffsetInstruction a
Ord, Int -> OffsetInstruction a -> ShowS
[OffsetInstruction a] -> ShowS
OffsetInstruction a -> String
(Int -> OffsetInstruction a -> ShowS)
-> (OffsetInstruction a -> String)
-> ([OffsetInstruction a] -> ShowS)
-> Show (OffsetInstruction a)
forall a. Show a => Int -> OffsetInstruction a -> ShowS
forall a. Show a => [OffsetInstruction a] -> ShowS
forall a. Show a => OffsetInstruction a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall a. Show a => Int -> OffsetInstruction a -> ShowS
showsPrec :: Int -> OffsetInstruction a -> ShowS
$cshow :: forall a. Show a => OffsetInstruction a -> String
show :: OffsetInstruction a -> String
$cshowList :: forall a. Show a => [OffsetInstruction a] -> ShowS
showList :: [OffsetInstruction a] -> ShowS
Show)

-- | Inserts the corresponding label offsets into the state.
insertAllLabels :: HasCallStack => CodeConverterEff r => NonEmpty Abs.Instruction -> Eff r (NonEmpty (OffsetInstruction Abs.Instruction))
insertAllLabels :: forall (r :: [Effect]).
(HasCallStack, CodeConverterEff r) =>
NonEmpty Instruction
-> Eff r (NonEmpty (OffsetInstruction Instruction))
insertAllLabels = (Instruction -> Eff r (OffsetInstruction Instruction))
-> NonEmpty Instruction
-> Eff r (NonEmpty (OffsetInstruction Instruction))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> NonEmpty a -> f (NonEmpty b)
traverse (\Instruction
x -> Instruction -> Eff r ()
forall (r :: [Effect]).
(HasCallStack, CodeConverterEff r) =>
Instruction -> Eff r ()
incOffset Instruction
x Eff r ()
-> Eff r (OffsetInstruction Instruction)
-> Eff r (OffsetInstruction Instruction)
forall a b. Eff r a -> Eff r b -> Eff r b
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Instruction -> Eff r (OffsetInstruction Instruction)
forall (r :: [Effect]).
(HasCallStack, CodeConverterEff r) =>
Instruction -> Eff r (OffsetInstruction Instruction)
insertLabel Instruction
x)
  where
    incOffset :: HasCallStack => CodeConverterEff r => Abs.Instruction -> Eff r ()
    incOffset :: forall (r :: [Effect]).
(HasCallStack, CodeConverterEff r) =>
Instruction -> Eff r ()
incOffset (Label Label
_) = () -> Eff r ()
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure () -- Label instructions have no representation in the bytecode, so they don't affect the offset
    incOffset Instruction
inst = do
        offset <- forall s (es :: [Effect]) a.
(HasCallStack, State s :> es) =>
(s -> a) -> Eff es a
gets @ConvertState (.currentOffset)
        let size = Instruction -> Word16
instructionSize Instruction
inst
        modify (\ConvertState
s -> ConvertState
s{currentOffset = offset + size})

    insertLabel :: HasCallStack => CodeConverterEff r => Abs.Instruction -> Eff r (OffsetInstruction Abs.Instruction)
    insertLabel :: forall (r :: [Effect]).
(HasCallStack, CodeConverterEff r) =>
Instruction -> Eff r (OffsetInstruction Instruction)
insertLabel (Label Label
l) = do
        currentOffset <- forall s (es :: [Effect]) a.
(HasCallStack, State s :> es) =>
(s -> a) -> Eff es a
gets @ConvertState (.currentOffset)

        modifyM $ \ConvertState
s -> do
            case Label -> Map Label Word16 -> Maybe Word16
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Label
l ConvertState
s.labelOffsets of
                Just Word16
_ -> CodeConverterError -> Eff r ConvertState
forall e (es :: [Effect]) a.
(HasCallStack, Error e :> es, Show e) =>
e -> Eff es a
throwError (Label -> Word16 -> CodeConverterError
DuplicateLabel Label
l Word16
currentOffset)
                Maybe Word16
Nothing -> do
                    ConvertState -> Eff r ConvertState
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ConvertState
s{labelOffsets = Map.insert l currentOffset s.labelOffsets})
        pure (LabelInstruction (Label l))
    insertLabel Instruction
x = do
        offset <- forall s (es :: [Effect]) a.
(HasCallStack, State s :> es) =>
(s -> a) -> Eff es a
gets @ConvertState (.currentOffset)
        pure (OffsetInstruction (offset - instructionSize x) x)

modifyM :: State s :> r => (s -> Eff r s) -> Eff r ()
modifyM :: forall s (r :: [Effect]).
(State s :> r) =>
(s -> Eff r s) -> Eff r ()
modifyM s -> Eff r s
f = Eff r s
forall s (es :: [Effect]).
(HasCallStack, State s :> es) =>
Eff es s
get Eff r s -> (s -> Eff r s) -> Eff r s
forall a b. Eff r a -> (a -> Eff r b) -> Eff r b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= s -> Eff r s
f Eff r s -> (s -> Eff r ()) -> Eff r ()
forall a b. Eff r a -> (a -> Eff r b) -> Eff r b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= s -> Eff r ()
forall s (es :: [Effect]).
(HasCallStack, State s :> es) =>
s -> Eff es ()
put

-- | Turns labels into offsets where possible
resolveLabel :: CodeConverterEff r => OffsetInstruction (Abs.Instruction' MaybeResolvedLabel) -> Eff r (OffsetInstruction (Abs.Instruction' MaybeResolvedLabel))
resolveLabel :: forall (r :: [Effect]).
CodeConverterEff r =>
OffsetInstruction (Instruction' MaybeResolvedLabel)
-> Eff r (OffsetInstruction (Instruction' MaybeResolvedLabel))
resolveLabel (OffsetInstruction Word16
instOffset Instruction' MaybeResolvedLabel
inst) =
    Word16
-> Instruction' MaybeResolvedLabel
-> OffsetInstruction (Instruction' MaybeResolvedLabel)
forall a. Word16 -> a -> OffsetInstruction a
OffsetInstruction Word16
instOffset (Instruction' MaybeResolvedLabel
 -> OffsetInstruction (Instruction' MaybeResolvedLabel))
-> Eff r (Instruction' MaybeResolvedLabel)
-> Eff r (OffsetInstruction (Instruction' MaybeResolvedLabel))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> case Instruction' MaybeResolvedLabel
inst of
        Abs.If IfCond MaybeResolvedLabel
cond -> IfCond MaybeResolvedLabel -> Instruction' MaybeResolvedLabel
forall label. IfCond label -> Instruction' label
Abs.If (IfCond MaybeResolvedLabel -> Instruction' MaybeResolvedLabel)
-> Eff r (IfCond MaybeResolvedLabel)
-> Eff r (Instruction' MaybeResolvedLabel)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (MaybeResolvedLabel -> Eff r MaybeResolvedLabel)
-> IfCond MaybeResolvedLabel -> Eff r (IfCond MaybeResolvedLabel)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> IfCond a -> f (IfCond b)
traverse MaybeResolvedLabel -> Eff r MaybeResolvedLabel
forall (r :: [Effect]).
CodeConverterEff r =>
MaybeResolvedLabel -> Eff r MaybeResolvedLabel
resolveLabelAbs IfCond MaybeResolvedLabel
cond
        Abs.Goto MaybeResolvedLabel
l -> MaybeResolvedLabel -> Instruction' MaybeResolvedLabel
forall label. label -> Instruction' label
Abs.Goto (MaybeResolvedLabel -> Instruction' MaybeResolvedLabel)
-> Eff r MaybeResolvedLabel
-> Eff r (Instruction' MaybeResolvedLabel)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MaybeResolvedLabel -> Eff r MaybeResolvedLabel
forall (r :: [Effect]).
CodeConverterEff r =>
MaybeResolvedLabel -> Eff r MaybeResolvedLabel
resolveLabelAbs MaybeResolvedLabel
l
        Abs.IfICmp IfCond MaybeResolvedLabel
cond -> IfCond MaybeResolvedLabel -> Instruction' MaybeResolvedLabel
forall label. IfCond label -> Instruction' label
Abs.IfICmp (IfCond MaybeResolvedLabel -> Instruction' MaybeResolvedLabel)
-> Eff r (IfCond MaybeResolvedLabel)
-> Eff r (Instruction' MaybeResolvedLabel)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (MaybeResolvedLabel -> Eff r MaybeResolvedLabel)
-> IfCond MaybeResolvedLabel -> Eff r (IfCond MaybeResolvedLabel)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> IfCond a -> f (IfCond b)
traverse MaybeResolvedLabel -> Eff r MaybeResolvedLabel
forall (r :: [Effect]).
CodeConverterEff r =>
MaybeResolvedLabel -> Eff r MaybeResolvedLabel
resolveLabelAbs IfCond MaybeResolvedLabel
cond
        Instruction' MaybeResolvedLabel
_ -> Instruction' MaybeResolvedLabel
-> Eff r (Instruction' MaybeResolvedLabel)
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction' MaybeResolvedLabel
inst
resolveLabel inst :: OffsetInstruction (Instruction' MaybeResolvedLabel)
inst@(LabelInstruction{}) = OffsetInstruction (Instruction' MaybeResolvedLabel)
-> Eff r (OffsetInstruction (Instruction' MaybeResolvedLabel))
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure OffsetInstruction (Instruction' MaybeResolvedLabel)
inst

fullyResolveAbs :: CodeConverterEff r => Label -> Eff r Word16
fullyResolveAbs :: forall (r :: [Effect]). CodeConverterEff r => Label -> Eff r Word16
fullyResolveAbs Label
l = do
    x <- MaybeResolvedLabel -> Eff r MaybeResolvedLabel
forall (r :: [Effect]).
CodeConverterEff r =>
MaybeResolvedLabel -> Eff r MaybeResolvedLabel
resolveLabelAbs (Label -> MaybeResolvedLabel
UnresolvedLabel Label
l)
    mustBeResolvedAbs x

-- | Attempt to resolve a label to an __absolute__ offset
resolveLabelAbs :: CodeConverterEff r => MaybeResolvedLabel -> Eff r MaybeResolvedLabel
resolveLabelAbs :: forall (r :: [Effect]).
CodeConverterEff r =>
MaybeResolvedLabel -> Eff r MaybeResolvedLabel
resolveLabelAbs r :: MaybeResolvedLabel
r@(ResolvedLabel Word16
_) = MaybeResolvedLabel -> Eff r MaybeResolvedLabel
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure MaybeResolvedLabel
r
resolveLabelAbs (UnresolvedLabel Label
l) = do
    offset <- forall s (es :: [Effect]) a.
(HasCallStack, State s :> es) =>
(s -> a) -> Eff es a
gets @ConvertState (Label -> Map Label Word16 -> Maybe Word16
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Label
l (Map Label Word16 -> Maybe Word16)
-> (ConvertState -> Map Label Word16)
-> ConvertState
-> Maybe Word16
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (.labelOffsets))
    case offset of
        Just Word16
o -> MaybeResolvedLabel -> Eff r MaybeResolvedLabel
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Word16 -> MaybeResolvedLabel
ResolvedLabel Word16
o)
        Maybe Word16
Nothing -> MaybeResolvedLabel -> Eff r MaybeResolvedLabel
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Label -> MaybeResolvedLabel
UnresolvedLabel Label
l)

-- | Attempt to resolve a label to an __absolute__ offset, throwing an error if it cannot be resolved
mustBeResolvedAbs :: CodeConverterEff r => MaybeResolvedLabel -> Eff r Word16
mustBeResolvedAbs :: forall (r :: [Effect]).
CodeConverterEff r =>
MaybeResolvedLabel -> Eff r Word16
mustBeResolvedAbs (ResolvedLabel Word16
i) = Word16 -> Eff r Word16
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Word16
i
mustBeResolvedAbs (UnresolvedLabel Label
l) = CodeConverterError -> Eff r Word16
forall e (es :: [Effect]) a.
(HasCallStack, Error e :> es, Show e) =>
e -> Eff es a
throwError (Label -> CodeConverterError
UnmarkedLabel Label
l)

mustBeResolved :: CodeConverterEff r => Word16 -> MaybeResolvedLabel -> Eff r Word16
mustBeResolved :: forall (r :: [Effect]).
CodeConverterEff r =>
Word16 -> MaybeResolvedLabel -> Eff r Word16
mustBeResolved Word16
instOffset = (Word16 -> Word16) -> Eff r Word16 -> Eff r Word16
forall a b. (a -> b) -> Eff r a -> Eff r b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Word16 -> Word16 -> Word16
forall a. Num a => a -> a -> a
- Word16
instOffset) (Eff r Word16 -> Eff r Word16)
-> (MaybeResolvedLabel -> Eff r Word16)
-> MaybeResolvedLabel
-> Eff r Word16
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MaybeResolvedLabel -> Eff r Word16
forall (r :: [Effect]).
CodeConverterEff r =>
MaybeResolvedLabel -> Eff r Word16
mustBeResolvedAbs

-- | Convert an instruction with a real offset to a raw 'Raw.Instruction'.
convertInstruction :: CodeConverterEff r => OffsetInstruction (Abs.Instruction' MaybeResolvedLabel) -> Eff r (Maybe Raw.Instruction)
convertInstruction :: forall (r :: [Effect]).
CodeConverterEff r =>
OffsetInstruction (Instruction' MaybeResolvedLabel)
-> Eff r (Maybe Instruction)
convertInstruction (OffsetInstruction Word16
_ (Abs.Label MaybeResolvedLabel
_)) = Maybe Instruction -> Eff r (Maybe Instruction)
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe Instruction
forall a. Maybe a
Nothing
convertInstruction (LabelInstruction Instruction' MaybeResolvedLabel
_) = Maybe Instruction -> Eff r (Maybe Instruction)
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe Instruction
forall a. Maybe a
Nothing -- kind of awkward having 2 cases for the same thing here but what can you do
convertInstruction (OffsetInstruction Word16
instOffset Instruction' MaybeResolvedLabel
o) = Instruction -> Maybe Instruction
forall a. a -> Maybe a
Just (Instruction -> Maybe Instruction)
-> Eff r Instruction -> Eff r (Maybe Instruction)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Instruction' MaybeResolvedLabel -> Eff r Instruction
convertInstruction Instruction' MaybeResolvedLabel
o
  where
    convertInstruction :: Instruction' MaybeResolvedLabel -> Eff r Instruction
convertInstruction (Abs.ALoad Word16
0) = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.ALoad0
    convertInstruction (Abs.ALoad Word16
1) = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.ALoad1
    convertInstruction (Abs.ALoad Word16
2) = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.ALoad2
    convertInstruction (Abs.ALoad Word16
3) = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.ALoad3
    convertInstruction (Abs.ALoad Word16
idx)
        | Right U1
i <- forall target source.
TryFrom source target =>
source -> Either (TryFromException source target) target
tryInto @U1 Word16
idx = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (U1 -> Instruction
Raw.ALoad U1
i)
        | Bool
otherwise = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (U1 -> Word16 -> Instruction
Raw.Wide1 U1
MagicNumbers.instruction_aLoad Word16
idx)
    convertInstruction (Abs.AStore Word16
0) = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.AStore0
    convertInstruction (Abs.AStore Word16
1) = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.AStore1
    convertInstruction (Abs.AStore Word16
2) = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.AStore2
    convertInstruction (Abs.AStore Word16
3) = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.AStore3
    convertInstruction (Abs.AStore Word16
idx)
        | Right U1
i <- forall target source.
TryFrom source target =>
source -> Either (TryFromException source target) target
tryInto @U1 Word16
idx = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (U1 -> Instruction
Raw.AStore U1
i)
        | Bool
otherwise = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (U1 -> Word16 -> Instruction
Raw.Wide1 U1
MagicNumbers.instruction_aStore Word16
idx)
    convertInstruction (Abs.ILoad Word16
0) = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.ILoad0
    convertInstruction (Abs.ILoad Word16
1) = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.ILoad1
    convertInstruction (Abs.ILoad Word16
2) = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.ILoad2
    convertInstruction (Abs.ILoad Word16
3) = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.ILoad3
    convertInstruction (Abs.ILoad Word16
idx)
        | Right U1
i <- forall target source.
TryFrom source target =>
source -> Either (TryFromException source target) target
tryInto @U1 Word16
idx = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (U1 -> Instruction
Raw.ILoad U1
i)
        | Bool
otherwise = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (U1 -> Word16 -> Instruction
Raw.Wide1 U1
MagicNumbers.instruction_iLoad Word16
idx)
    convertInstruction (Abs.IStore Word16
0) = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.IStore0
    convertInstruction (Abs.IStore Word16
1) = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.IStore1
    convertInstruction (Abs.IStore Word16
2) = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.IStore2
    convertInstruction (Abs.IStore Word16
3) = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.IStore3
    convertInstruction (Abs.IStore Word16
idx)
        | Right U1
i <- forall target source.
TryFrom source target =>
source -> Either (TryFromException source target) target
tryInto @U1 Word16
idx = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (U1 -> Instruction
Raw.IStore U1
i)
        | Bool
otherwise = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (U1 -> Word16 -> Instruction
Raw.Wide1 U1
MagicNumbers.instruction_iStore Word16
idx)
    convertInstruction Instruction' MaybeResolvedLabel
Abs.ArrayLength = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.ArrayLength
    convertInstruction Instruction' MaybeResolvedLabel
Abs.AALoad = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.AALoad
    convertInstruction Instruction' MaybeResolvedLabel
Abs.AConstNull = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.AConstNull
    convertInstruction (Abs.Instanceof ClassInfoType
t) = do
        idx <- ConstantPoolEntry -> Eff r Word16
forall (r :: [Effect]).
(HasCallStack, ConstantPoolEff r) =>
ConstantPoolEntry -> Eff r Word16
findIndexOf (ClassInfoType -> ConstantPoolEntry
CPClassEntry ClassInfoType
t)
        pure (Raw.Instanceof idx)
    convertInstruction (Abs.InvokeStatic ClassInfoType
c Text
n MethodDescriptor
m) = do
        idx <- ConstantPoolEntry -> Eff r Word16
forall (r :: [Effect]).
(HasCallStack, ConstantPoolEff r) =>
ConstantPoolEntry -> Eff r Word16
findIndexOf (MethodRef -> ConstantPoolEntry
CPMethodRefEntry (ClassInfoType -> Text -> MethodDescriptor -> MethodRef
MethodRef ClassInfoType
c Text
n MethodDescriptor
m))
        pure (Raw.InvokeStatic idx)
    convertInstruction (Abs.InvokeVirtual ClassInfoType
c Text
n MethodDescriptor
m) = do
        idx <- ConstantPoolEntry -> Eff r Word16
forall (r :: [Effect]).
(HasCallStack, ConstantPoolEff r) =>
ConstantPoolEntry -> Eff r Word16
findIndexOf (MethodRef -> ConstantPoolEntry
CPMethodRefEntry (ClassInfoType -> Text -> MethodDescriptor -> MethodRef
MethodRef ClassInfoType
c Text
n MethodDescriptor
m))
        pure (Raw.InvokeVirtual idx)
    convertInstruction (Abs.InvokeInterface ClassInfoType
c Text
n MethodDescriptor
m) = do
        idx <- ConstantPoolEntry -> Eff r Word16
forall (r :: [Effect]).
(HasCallStack, ConstantPoolEff r) =>
ConstantPoolEntry -> Eff r Word16
findIndexOf (MethodRef -> ConstantPoolEntry
CPInterfaceMethodRefEntry (ClassInfoType -> Text -> MethodDescriptor -> MethodRef
MethodRef ClassInfoType
c Text
n MethodDescriptor
m))
        let count = MethodDescriptor -> Int
countArguments MethodDescriptor
m
        pure (Raw.InvokeInterface idx (unsafeInto count))
    convertInstruction (Abs.InvokeSpecial ClassInfoType
c Text
n MethodDescriptor
m) = do
        idx <- ConstantPoolEntry -> Eff r Word16
forall (r :: [Effect]).
(HasCallStack, ConstantPoolEff r) =>
ConstantPoolEntry -> Eff r Word16
findIndexOf (MethodRef -> ConstantPoolEntry
CPMethodRefEntry (ClassInfoType -> Text -> MethodDescriptor -> MethodRef
MethodRef ClassInfoType
c Text
n MethodDescriptor
m))
        pure (Raw.InvokeSpecial idx)
    convertInstruction (Abs.LDC LDCEntry
ldc) = do
        idx <-
            ConstantPoolEntry -> Eff r Word16
forall (r :: [Effect]).
(HasCallStack, ConstantPoolEff r) =>
ConstantPoolEntry -> Eff r Word16
findIndexOf
                ( case LDCEntry
ldc of
                    LDCInt JVMInt
i -> JVMInt -> ConstantPoolEntry
CPIntegerEntry JVMInt
i
                    LDCFloat Float
f -> Float -> ConstantPoolEntry
CPFloatEntry Float
f
                    LDCString Text
s -> Text -> ConstantPoolEntry
CPStringEntry Text
s
                    LDCClass ClassInfoType
c -> ClassInfoType -> ConstantPoolEntry
CPClassEntry ClassInfoType
c
                )

        pure (Raw.LDC_W idx) -- TODO: handle LDC vs LDC_W properly

    -- TODO: this should probably do a bounds check on the index
    convertInstruction (Abs.PutStatic ClassInfoType
c Text
n FieldType
t) = do
        idx <- ConstantPoolEntry -> Eff r Word16
forall (r :: [Effect]).
(HasCallStack, ConstantPoolEff r) =>
ConstantPoolEntry -> Eff r Word16
findIndexOf (FieldRef -> ConstantPoolEntry
CPFieldRefEntry (ClassInfoType -> Text -> FieldType -> FieldRef
FieldRef ClassInfoType
c Text
n FieldType
t))
        pure (Raw.PutStatic idx)
    convertInstruction (Abs.GetField ClassInfoType
c Text
n FieldType
t) = do
        idx <- ConstantPoolEntry -> Eff r Word16
forall (r :: [Effect]).
(HasCallStack, ConstantPoolEff r) =>
ConstantPoolEntry -> Eff r Word16
findIndexOf (FieldRef -> ConstantPoolEntry
CPFieldRefEntry (ClassInfoType -> Text -> FieldType -> FieldRef
FieldRef ClassInfoType
c Text
n FieldType
t))
        pure (Raw.GetField idx)
    convertInstruction (Abs.GetStatic ClassInfoType
c Text
n FieldType
t) = do
        idx <- ConstantPoolEntry -> Eff r Word16
forall (r :: [Effect]).
(HasCallStack, ConstantPoolEff r) =>
ConstantPoolEntry -> Eff r Word16
findIndexOf (FieldRef -> ConstantPoolEntry
CPFieldRefEntry (ClassInfoType -> Text -> FieldType -> FieldRef
FieldRef ClassInfoType
c Text
n FieldType
t))
        pure (Raw.GetStatic idx)
    convertInstruction (Abs.PutField ClassInfoType
c Text
n FieldType
t) = do
        idx <- ConstantPoolEntry -> Eff r Word16
forall (r :: [Effect]).
(HasCallStack, ConstantPoolEff r) =>
ConstantPoolEntry -> Eff r Word16
findIndexOf (FieldRef -> ConstantPoolEntry
CPFieldRefEntry (ClassInfoType -> Text -> FieldType -> FieldRef
FieldRef ClassInfoType
c Text
n FieldType
t))
        pure (Raw.PutField idx)
    convertInstruction Instruction' MaybeResolvedLabel
Abs.AReturn = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.AReturn
    convertInstruction Instruction' MaybeResolvedLabel
Abs.Return = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.Return
    convertInstruction Instruction' MaybeResolvedLabel
Abs.IReturn = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.IReturn
    convertInstruction Instruction' MaybeResolvedLabel
Abs.IConst0 = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.IConst0
    convertInstruction Instruction' MaybeResolvedLabel
Abs.IConst1 = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.IConst1
    convertInstruction Instruction' MaybeResolvedLabel
Abs.Dup = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.Dup
    convertInstruction (Abs.CheckCast ClassInfoType
t) = do
        idx <- ConstantPoolEntry -> Eff r Word16
forall (r :: [Effect]).
(HasCallStack, ConstantPoolEff r) =>
ConstantPoolEntry -> Eff r Word16
findIndexOf (ClassInfoType -> ConstantPoolEntry
CPClassEntry ClassInfoType
t)
        pure (Raw.CheckCast idx)
    convertInstruction (Abs.InvokeDynamic BootstrapMethod
bm Text
n MethodDescriptor
m) = do
        idx <- ConstantPoolEntry -> Eff r Word16
forall (r :: [Effect]).
(HasCallStack, ConstantPoolEff r) =>
ConstantPoolEntry -> Eff r Word16
findIndexOf (BootstrapMethod -> Text -> MethodDescriptor -> ConstantPoolEntry
CPInvokeDynamicEntry BootstrapMethod
bm Text
n MethodDescriptor
m)
        pure (Raw.InvokeDynamic idx)
    convertInstruction (Abs.If IfCond MaybeResolvedLabel
cond) = do
        resolvedCond <- (MaybeResolvedLabel -> Eff r Word16)
-> IfCond MaybeResolvedLabel -> Eff r (IfCond Word16)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> IfCond a -> f (IfCond b)
traverse (Word16 -> MaybeResolvedLabel -> Eff r Word16
forall (r :: [Effect]).
CodeConverterEff r =>
Word16 -> MaybeResolvedLabel -> Eff r Word16
mustBeResolved Word16
instOffset) IfCond MaybeResolvedLabel
cond
        pure $ case resolvedCond of
            Abs.IfEq Word16
l -> Word16 -> Instruction
Raw.IfEq Word16
l
            Abs.IfNe Word16
l -> Word16 -> Instruction
Raw.IfNe Word16
l
            Abs.IfLt Word16
l -> Word16 -> Instruction
Raw.IfLt Word16
l
            Abs.IfGe Word16
l -> Word16 -> Instruction
Raw.IfGe Word16
l
            Abs.IfGt Word16
l -> Word16 -> Instruction
Raw.IfGt Word16
l
            Abs.IfLe Word16
l -> Word16 -> Instruction
Raw.IfLe Word16
l
    convertInstruction (Abs.Goto MaybeResolvedLabel
offset) = Word16 -> Instruction
Raw.Goto (Word16 -> Instruction) -> Eff r Word16 -> Eff r Instruction
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Word16 -> MaybeResolvedLabel -> Eff r Word16
forall (r :: [Effect]).
CodeConverterEff r =>
Word16 -> MaybeResolvedLabel -> Eff r Word16
mustBeResolved Word16
instOffset MaybeResolvedLabel
offset
    convertInstruction (Abs.Label MaybeResolvedLabel
_) = String -> Eff r Instruction
forall a. HasCallStack => String -> a
bug String
"unreachable, should have already been handled"
    convertInstruction (Abs.New ClassInfoType
t) = do
        idx <- ConstantPoolEntry -> Eff r Word16
forall (r :: [Effect]).
(HasCallStack, ConstantPoolEff r) =>
ConstantPoolEntry -> Eff r Word16
findIndexOf (ClassInfoType -> ConstantPoolEntry
CPClassEntry ClassInfoType
t)
        pure (Raw.New idx)
    convertInstruction Instruction' MaybeResolvedLabel
Abs.IAnd = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.IAnd
    convertInstruction Instruction' MaybeResolvedLabel
Abs.IOr = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.IOr
    convertInstruction (Abs.IfICmp IfCond MaybeResolvedLabel
cond) = do
        resolvedCond <- (MaybeResolvedLabel -> Eff r Word16)
-> IfCond MaybeResolvedLabel -> Eff r (IfCond Word16)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> IfCond a -> f (IfCond b)
traverse (Word16 -> MaybeResolvedLabel -> Eff r Word16
forall (r :: [Effect]).
CodeConverterEff r =>
Word16 -> MaybeResolvedLabel -> Eff r Word16
mustBeResolved Word16
instOffset) IfCond MaybeResolvedLabel
cond
        pure $ case resolvedCond of
            Abs.IfEq Word16
l -> Word16 -> Instruction
Raw.IfIcmpEq Word16
l
            Abs.IfNe Word16
l -> Word16 -> Instruction
Raw.IfIcmpNe Word16
l
            Abs.IfLt Word16
l -> Word16 -> Instruction
Raw.IfIcmpLt Word16
l
            Abs.IfGe Word16
l -> Word16 -> Instruction
Raw.IfIcmpGe Word16
l
            Abs.IfGt Word16
l -> Word16 -> Instruction
Raw.IfIcmpGt Word16
l
            Abs.IfLe Word16
l -> Word16 -> Instruction
Raw.IfIcmpLe Word16
l
    convertInstruction Instruction' MaybeResolvedLabel
Abs.IAdd = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.IAdd
    convertInstruction Instruction' MaybeResolvedLabel
Abs.ISub = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.ISub
    convertInstruction Instruction' MaybeResolvedLabel
Abs.IMul = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.IMul
    convertInstruction Instruction' MaybeResolvedLabel
Abs.IDiv = Instruction -> Eff r Instruction
forall a. a -> Eff r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Instruction
Raw.IDiv