keelung-0.9.0.0: src/Keelung/Syntax/Encode.hs
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
-- | Module for encoding Keelung syntax
module Keelung.Syntax.Encode
( Encode (..),
runHeapM,
encode',
Expr (..),
)
where
import Control.Monad.Reader
import Data.Array.Unboxed qualified as Array
import Data.IntMap qualified as IntMap
import GHC.TypeLits (KnownNat)
import Keelung.Heap
import Keelung.Syntax (widthOf)
import Keelung.Syntax qualified as Syntax
import Keelung.Syntax.Encode.Syntax
--------------------------------------------------------------------------------
-- | MultiParam version of 'Encode'
class Encode' a b where
-- | Encode a Keelung expression
encode' :: a -> HeapM b
instance Encode' Syntax.Boolean Boolean where
encode' expr = case expr of
Syntax.Boolean b -> return $ ValB b
Syntax.VarB var -> return $ VarB var
Syntax.VarBI var -> return $ VarBI var
Syntax.VarBP var -> return $ VarBP var
Syntax.And x y -> AndB <$> encode' x <*> encode' y
Syntax.Or x y -> OrB <$> encode' x <*> encode' y
Syntax.Xor x y -> XorB <$> encode' x <*> encode' y
Syntax.Not x -> NotB <$> encode' x
Syntax.IfB p x y -> IfB <$> encode' p <*> encode' x <*> encode' y
Syntax.EqB x y -> EqB <$> encode' x <*> encode' y
Syntax.EqF x y -> EqF <$> encode' x <*> encode' y
Syntax.EqU x y -> EqU (widthOf x) <$> encode' x <*> encode' y
Syntax.BitU x i -> BitU (widthOf x) <$> encode' x <*> pure i
instance Encode' Syntax.Field Field where
encode' expr = case expr of
Syntax.Integer n -> return $ ValF n
Syntax.Rational n -> return $ ValFR n
Syntax.VarF var -> return $ VarF var
Syntax.VarFI var -> return $ VarFI var
Syntax.VarFP var -> return $ VarFP var
Syntax.Add x y -> AddF <$> encode' x <*> encode' y
Syntax.Sub x y -> SubF <$> encode' x <*> encode' y
Syntax.Mul x y -> MulF <$> encode' x <*> encode' y
Syntax.Div x y -> DivF <$> encode' x <*> encode' y
Syntax.IfF p x y -> IfF <$> encode' p <*> encode' x <*> encode' y
Syntax.BtoF b -> BtoF <$> encode' b
instance KnownNat w => Encode' (Syntax.UInt w) UInt where
encode' expr = case expr of
Syntax.UInt n -> return $ ValU (widthOf expr) n
Syntax.VarU var -> return $ VarU (widthOf expr) var
Syntax.VarUI var -> return $ VarUI (widthOf expr) var
Syntax.VarUP var -> return $ VarUP (widthOf expr) var
Syntax.AddU x y -> AddU (widthOf x) <$> encode' x <*> encode' y
Syntax.SubU x y -> SubU (widthOf x) <$> encode' x <*> encode' y
Syntax.MulU x y -> MulU (widthOf x) <$> encode' x <*> encode' y
Syntax.AndU x y -> AndU (widthOf expr) <$> encode' x <*> encode' y
Syntax.OrU x y -> OrU (widthOf expr) <$> encode' x <*> encode' y
Syntax.XorU x y -> XorU (widthOf expr) <$> encode' x <*> encode' y
Syntax.NotU x -> NotU (widthOf expr) <$> encode' x
Syntax.IfU p x y -> IfU (widthOf expr) <$> encode' p <*> encode' x <*> encode' y
Syntax.RoLU w i x -> RoLU w i <$> encode' x
Syntax.ShLU w i x -> ShLU w i <$> encode' x
Syntax.SetU x i b -> SetU (widthOf expr) <$> encode' x <*> pure i <*> encode' b
Syntax.BtoU n -> BtoU (widthOf expr) <$> encode' n
--------------------------------------------------------------------------------
-- | Typeclass for encoding stuff into something Keelung can understand
class Encode a where
encode :: a -> HeapM Expr
instance Encode Syntax.Boolean where
encode expr = Boolean <$> encode' expr
instance Encode Syntax.Field where
encode expr = Field <$> encode' expr
instance KnownNat w => Encode (Syntax.UInt w) where
encode expr = UInt <$> encode' expr
instance Encode () where
encode expr = case expr of
() -> return Unit
instance Encode t => Encode (ArrM t) where
encode expr = case expr of
ArrayRef _ len addr -> readArray addr len
instance Encode t => Encode [t] where
encode xs = Array . Array.listArray (0, length xs - 1) <$> mapM encode xs
instance (Encode a, Encode b) => Encode (a, b) where
encode (a, b) = do
a' <- encode a
b' <- encode b
return $ Array $ Array.listArray (0, 1) [a', b']
--------------------------------------------------------------------------------
-- | Reader Monad for Heap lookups
type HeapM = Reader Heap
-- | Run a HeapM computation
runHeapM :: Heap -> HeapM a -> a
runHeapM h m = runReader m h
-- | Read an array from the heap
readArray :: Addr -> Int -> HeapM Expr
readArray addr len = Array <$> mapM (readHeap addr) indices
where
indices :: Array.Array Int Int
indices = Array.listArray (0, pred len) [0 .. pred len]
readHeap :: Addr -> Int -> HeapM Expr
readHeap addr' i = do
heap <- ask
case IntMap.lookup addr' heap of
Nothing -> error "HeapM: address not found"
Just (elemType, array) -> case IntMap.lookup i array of
Nothing -> error "HeapM: index ouf of bounds"
Just addr'' -> case elemType of
ElemF -> return $ Field $ VarF addr''
ElemB -> return $ Boolean $ VarB addr''
ElemU w -> return $ UInt $ VarU w addr''
ElemArr _ len' -> readArray addr'' len'
EmptyArr -> readArray addr'' 0