{-# LANGUAGE OverloadedStrings #-}

module Funcons.Core.Values.Primitive.BitsBuiltin where

import Funcons.EDSL
import Funcons.Types

import qualified Data.BitVector as BV

library = libFromList [
        ("bits-to-integer", ValueOp stepBits_To_Integer)
    ,   ("integer-to-bits", ValueOp stepInteger_To_Bits)
    ,   ("bits-not", ValueOp stepBits_Not)
    ,   ("bits-or", ValueOp stepBits_Or)
    ,   ("bits-and", ValueOp stepBits_And)
    ,   ("bits-xor", ValueOp stepBits_Xor)
    ,   ("bits-shift-left", ValueOp stepBits_Shift_Left)
    ,   ("bits-logical-shift-right", ValueOp stepBits_Logical_Shift_Right)
    ,   ("bits-arithmetic-shift-right", ValueOp stepBits_Arithmetic_Shift_Right)
    ,   ("bits-to-integer", ValueOp stepBits_To_Integer)
    ,   ("bits-to-natural", ValueOp stepBits_To_Natural)
    ,   ("integer-to-bits", ValueOp stepInteger_To_Bits)
    ]

stepBits_Not [Bit bv] = rewriteTo $ FValue $ Bit $ BV.not bv
stepBits_Not vs        = sortErr (applyFuncon "bits-not" (fvalues vs)) "bits-not not applied to bits"
stepBits_And [Bit bv1, Bit bv2] = rewriteTo $ FValue $ Bit (bv1 BV..&. bv2)
stepBits_And vs = sortErr (applyFuncon "bits-and" (fvalues vs)) "bits-and not applied to bits"

bits_or = applyFuncon "bits-or"
stepBits_Or [Bit bv1, Bit bv2] = rewriteTo $ FValue $ Bit (bv1 BV..|. bv2)
stepBits_Or vs = sortErr (bits_or (fvalues vs)) "bits-or not applied to bits"

bits_xor = applyFuncon "bits-xor"
stepBits_Xor [Bit bv1, Bit bv2] = rewriteTo $ FValue $ Bit (bv1 `BV.xor` bv2)
stepBits_Xor vs = sortErr (bits_xor (fvalues vs)) "bits-xor not applied to bits"

bits_shift_left = applyFuncon "bits-shift-left"
stepBits_Shift_Left [Bit bv1, vn]
    | Nat n <- upcastNaturals vn = rewriteTo $ FValue $ Bit (bv1 `BV.shl` (fromInteger n))
stepBits_Shift_Left vs = sortErr (bits_shift_left (fvalues vs)) "bits-shift not applied to bits"

bits_arithmetic_shift_right = applyFuncon "bits-arithmetic-shift_right"
stepBits_Arithmetic_Shift_Right [Bit bv1, vn]
    | Nat n <- upcastNaturals vn = rewriteTo $ FValue $ Bit (bv1 `BV.ashr` (fromInteger n))
stepBits_Arithmetic_Shift_Right vs = 
    sortErr (bits_arithmetic_shift_right (fvalues vs)) 
        "bits-arithmetic-shift-right not applied to bits"

bits_logical_shift_right = applyFuncon "bits-logical-shift-right"
stepBits_Logical_Shift_Right [Bit bv1, vn]
   | Nat n <- upcastNaturals vn = rewriteTo $ FValue $ Bit (bv1 `BV.shr` (fromInteger n))
stepBits_Logical_Shift_Right vs = 
    sortErr (bits_logical_shift_right (fvalues vs)) "bits-logical-shift-right"

bits_to_integer = applyFuncon "bits-to-integer"
stepBits_To_Integer [Bit bv] = rewriteTo $ int_ $ fromInteger $ (BV.int bv)
stepBits_To_Integer vs = sortErr (bits_to_integer (fvalues vs)) 
    "bits-to-integer not applied to bits"

bits_to_natural = applyFuncon "bits-to-natural"
stepBits_To_Natural [Bit bv] = rewriteTo $ FValue $ mk_naturals (BV.nat bv)
stepBits_To_Natural vs = sortErr (bits_to_natural (fvalues vs)) "bits-to-natural not applied to bits"
integer_to_bits = applyFuncon "integer-to-bits"
stepInteger_To_Bits [vn,vi]
    | (Nat n, Int i) <- (upcastNaturals vn, upcastIntegers vi)
            = rewriteTo $ FValue $ Bit (BV.bitVec (fromInteger n) (i `mod` (2 ^ n)))
stepInteger_To_Bits vs = sortErr (applyFuncon "integer-to-bits" (fvalues vs)) 
    "sort check: integer-to-bits(_:naturals,_:integers)"