{-# LANGUAGE OverloadedStrings #-}
module Funcons.Operations.Bits where
import Funcons.Operations.Booleans (tobool,frombool)
import Funcons.Operations.Internal
import Control.Monad (join)
import qualified Data.BitVector as BV
library :: (HasValues t, Ord t) => Library t
library = libFromList [
("bit-vector-not", UnaryExpr bit_vector_not)
, ("bit-vector-and", BinaryExpr bit_vector_and)
, ("bit-vector-or", BinaryExpr bit_vector_or)
, ("bit-vector-xor", BinaryExpr bit_vector_xor)
, ("bit-vector-shift-left", BinaryExpr bit_vector_shift_left)
, ("bit-vector-logical-shift-right", BinaryExpr bit_vector_logical_shift_right)
, ("bit-vector-arithmetic-shift-right", BinaryExpr bit_vector_arithmetical_shift_right)
, ("integer-to-bit-vector", BinaryExpr integer_to_bit_vector)
, ("bit-vector-to-integer", UnaryExpr bit_vector_to_integer)
, ("bit-vector-to-natural", UnaryExpr bit_vector_to_natural)
]
bit_vector_not_ :: HasValues t => [OpExpr t] -> OpExpr t
bit_vector_not_ = unaryOp bit_vector_not
bit_vector_not :: HasValues t => OpExpr t -> OpExpr t
bit_vector_not = vUnaryOp "bit-vector-not" op
where op (ADTVal "bit-vector" vals) | Just bv <- apply_to_vec BV.not vals =
Normal $ inject $ ADTVal "bit-vector" bv
op _ = SortErr "bit-vector-not applied to a bit-vector"
bit_vector_and_ :: HasValues t => [OpExpr t] -> OpExpr t
bit_vector_and_ = binaryOp bit_vector_and
bit_vector_and :: HasValues t => OpExpr t -> OpExpr t -> OpExpr t
bit_vector_and = vBinaryOp "bit-vector-and" op
where op (ADTVal "bit-vector" vals1) (ADTVal "bit-vector" vals2) =
case args_to_bools vals1 of
Just bv1 -> case apply_to_vec (\bv2 -> BV.and [BV.fromBits bv1,bv2]) vals2 of
Just bv2 -> Normal $ inject $ ADTVal "bit-vector" bv2
Nothing -> SortErr "second argument of bit-vector-and not a bit-vector"
Nothing -> SortErr "first argument of bit-vector-and not a bit-vector"
op _ _ = SortErr "bit-vector-and not applied to two bit-vectors"
bit_vector_or_ :: HasValues t => [OpExpr t] -> OpExpr t
bit_vector_or_ = binaryOp bit_vector_or
bit_vector_or :: HasValues t => OpExpr t -> OpExpr t -> OpExpr t
bit_vector_or = vBinaryOp "bit-vector-or" op
where op (ADTVal "bit-vector" vals1) (ADTVal "bit-vector" vals2) =
case args_to_bools vals1 of
Just bv1 -> case apply_to_vec (\bv2 -> BV.or [BV.fromBits bv1,bv2]) vals2 of
Just bv2 -> Normal $ inject $ ADTVal "bit-vector" bv2
Nothing -> SortErr "second argument of bit-vector-or not a bit-vector"
Nothing -> SortErr "first argument of bit-vector-or not a bit-vector"
op _ _ = SortErr "bit-vector-or not applied to two bit-vectors"
bit_vector_xor_ :: HasValues t => [OpExpr t] -> OpExpr t
bit_vector_xor_ = binaryOp bit_vector_xor
bit_vector_xor :: HasValues t => OpExpr t -> OpExpr t -> OpExpr t
bit_vector_xor = vBinaryOp "bit-vector-xor" (binary_bit_op "bit-vector-xor" BV.xor)
bit_vector_shift_left_ :: HasValues t => [OpExpr t] -> OpExpr t
bit_vector_shift_left_ = binaryOp bit_vector_shift_left
bit_vector_shift_left :: HasValues t => OpExpr t -> OpExpr t -> OpExpr t
bit_vector_shift_left = vBinaryOp "bit-vector-shift-left" (bit_nat_op "bit-vector-shift-left" BV.shl)
bit_vector_logical_shift_right_ :: HasValues t => [OpExpr t] -> OpExpr t
bit_vector_logical_shift_right_ = binaryOp bit_vector_logical_shift_right
bit_vector_logical_shift_right :: HasValues t => OpExpr t -> OpExpr t -> OpExpr t
bit_vector_logical_shift_right = vBinaryOp "bit-vector-logical-shift-right" (bit_nat_op "bit-vector-logical-shift-right" BV.shr)
bit_vector_arithmetical_shift_right_ :: HasValues t => [OpExpr t] -> OpExpr t
bit_vector_arithmetical_shift_right_ = binaryOp bit_vector_arithmetical_shift_right
bit_vector_arithmetical_shift_right :: HasValues t => OpExpr t -> OpExpr t -> OpExpr t
bit_vector_arithmetical_shift_right = vBinaryOp "bit-vector-arithmetical-shift-right" (bit_nat_op "bit-vector-arithmetical-shift-right" BV.ashr)
bit_vector_to_integer_ :: HasValues t => [OpExpr t] -> OpExpr t
bit_vector_to_integer_ = unaryOp bit_vector_to_integer
bit_vector_to_integer :: HasValues t => OpExpr t -> OpExpr t
bit_vector_to_integer = vUnaryOp "bit-vector-to-integer" op
where op (ADTVal "bit-vector" vals) | Just bits <- args_to_bools vals
= Normal $ inject $ Int $ BV.int (BV.fromBits bits)
op _ = SortErr "bit-vector-to-integer not applied to a bit-vector"
bit_vector_to_natural_ :: HasValues t => [OpExpr t] -> OpExpr t
bit_vector_to_natural_ = unaryOp bit_vector_to_natural
bit_vector_to_natural :: HasValues t => OpExpr t -> OpExpr t
bit_vector_to_natural = vUnaryOp "bit-vector-to-natural" op
where op (ADTVal "bit-vector" vals) | Just bits <- args_to_bools vals
= Normal $ inject $ Nat $ BV.nat (BV.fromBits bits)
op _ = SortErr "bit-vector-to-natural not applied to a bit-vector"
integer_to_bit_vector_ :: HasValues t => [OpExpr t] -> OpExpr t
integer_to_bit_vector_ = binaryOp integer_to_bit_vector
integer_to_bit_vector :: HasValues t => OpExpr t -> OpExpr t -> OpExpr t
integer_to_bit_vector = vBinaryOp "integer-to-bit-vector" op
where op mi mn | Int i <- upcastIntegers mi, Nat n <- upcastNaturals mn
= Normal $ inject $ ADTVal "bit-vector" $ map (inject . tobool) $
BV.toBits (BV.bitVec (fromInteger n) (i `mod` (2 ^ n)))
op _ _ = SortErr "integer-to-bit-vector not applied to an integer and a natural"
apply_to_vec :: HasValues t => (BV.BV -> BV.BV) -> [t] -> Maybe [t]
apply_to_vec app =
fmap (map (inject . tobool) . BV.toBits . app . BV.fromBits) . args_to_bools
args_to_bools :: HasValues t => [t] -> Maybe [Bool]
args_to_bools = sequence . map (join . fmap frombool . project)
binary_bit_op fc app (ADTVal "bit-vector" vals1) (ADTVal "bit-vector" vals2) =
case args_to_bools vals1 of
Just bv1 -> case apply_to_vec (app (BV.fromBits bv1)) vals2 of
Just bv2 -> Normal $ inject $ ADTVal "bit-vector" bv2
Nothing -> SortErr ("second argument of " ++ fc ++ " not a bit-vector")
Nothing -> SortErr ("first argument of " ++ fc ++ " not a bit-vector")
binary_bit_op fc _ _ _ = SortErr (fc ++ " not applied to two bit-vectors")
bit_nat_op fc app (ADTVal "bit-vector" vals1) v2 | Nat n <- upcastNaturals v2 =
case apply_to_vec (flip app (fromInteger n)) vals1 of
Just bv2 -> Normal $ inject $ ADTVal "bit-vector" bv2
Nothing -> SortErr ("first argument of " ++ fc ++ " not a bit-vector")
bit_nat_op fc _ _ _ = SortErr (fc ++ " not applied to a bit-vector and a natural")