
Basic Data Operation

This is a basic data operation. It represents a fundamental action on a basic data type.
You may see other such operations in the Basic Data Operations category, or:


Integer Operations
Arithmetic |
Comparison
Boolean Operations
Bitwise |
Logical
String Operations
Concatenation |
Interpolation |
Comparison |
Matching
Memory Operations
Pointers & references |
Addresses




Task

Write a routine to perform a bitwise AND, OR, and XOR on two integers, a bitwise NOT on the first integer, a left shift, right shift, right arithmetic shift, left rotate, and right rotate.

All shifts and rotates should be done on the first integer with a shift/rotate amount of the second integer.

If any operation is not available in your language, note it.




use AppleScript version "2.4"
use framework "Foundation"
use scripting additions
 
-- BIT OPERATIONS FOR APPLESCRIPT (VIA JAVASCRIPT FOR AUTOMATION)
 
-- bitAND :: Int -> Int -> Int
on bitAND(x, y)
    jsOp2("&", x, y)
end bitAND
 
-- bitOR :: Int -> Int -> Int
on bitOR(x, y)
    jsOp2("|", x, y)
end bitOR
 
-- bitXOr :: Int -> Int -> Int
on bitXOR(x, y)
    jsOp2("^", x, y)
end bitXOR
 
-- bitNOT :: Int -> Int
on bitNOT(x)
    jsOp1("~", x)
end bitNOT
 
-- (<<) :: Int -> Int -> Int
on |<<|(x, y)
    if 31 < y then
        0
    else
        jsOp2("<<", x, y)
    end if
end |<<|
 
-- Logical right shift
-- (>>>) :: Int -> Int -> Int
on |>>>|(x, y)
    jsOp2(">>>", x, y)
end |>>>|
 
-- Arithmetic right shift
-- (>>) :: Int -> Int -> Int
on |>>|(x, y)
    jsOp2(">>", x, y)
end |>>|
 
 
-- TEST ----------------------------------------------------------
on run
    -- Using an ObjC interface to Javascript for Automation
 
    set strClip to bitWise(255, 170)
    set the clipboard to strClip
    strClip
end run
 
-- bitWise :: Int -> Int -> String
on bitWise(a, b)
    set labels to {"a AND b", "a OR b", "a XOR b", "NOT a", ¬
        "a << b", "a >>> b", "a >> b"}
    set xs to {bitAND(a, b), bitOR(a, b), bitXOR(a, b), bitNOT(a), ¬
        |<<|(a, b), |>>>|(a, b), |>>|(a, b)}
 
    script asBin
        property arrow : " -> "
        on |λ|(x, y)
            justifyRight(8, space, x) & arrow & ¬
                justifyRight(14, space, y as text) & arrow & showBinary(y)
        end |λ|
    end script
 
    unlines({"32 bit signed integers   (in two's complement binary encoding)", "", ¬
        unlines(zipWith(asBin, ¬
            {"a = " & a as text, "b = " & b as text}, {a, b})), "", ¬
        unlines(zipWith(asBin, labels, xs))})
end bitWise
 
-- CONVERSIONS AND DISPLAY
 
-- bitsFromInt :: Int -> Either String [Bool]
on bitsFromIntLR(x)
    script go
        on |λ|(n, d, bools)
            set xs to {0 ≠ d} & bools
            if n > 0 then
                |λ|(n div 2, n mod 2, xs)
            else
                xs
            end if
        end |λ|
    end script
 
    set a to abs(x)
    if (2.147483647E+9) < a then
        |Left|("Integer overflow – maximum is (2 ^ 31) - 1")
    else
        set bs to go's |λ|(a div 2, a mod 2, {})
        if 0 > x then
            |Right|(replicate(32 - (length of bs), true) & ¬
                binSucc(map(my |not|, bs)))
        else
            set bs to go's |λ|(a div 2, a mod 2, {})
            |Right|(replicate(32 - (length of bs), false) & bs)
        end if
    end if
end bitsFromIntLR
 
-- Successor function (+1) for unsigned binary integer
 
-- binSucc :: [Bool] -> [Bool]
on binSucc(bs)
    script succ
        on |λ|(a, x)
            if a then
                if x then
                    Tuple(a, false)
                else
                    Tuple(x, true)
                end if
            else
                Tuple(a, x)
            end if
        end |λ|
    end script
 
    set tpl to mapAccumR(succ, true, bs)
    if |1| of tpl then
        {true} & |2| of tpl
    else
        |2| of tpl
    end if
end binSucc
 
-- showBinary :: Int -> String
on showBinary(x)
    script showBin
        on |λ|(xs)
            script bChar
                on |λ|(b)
                    if b then
                        "1"
                    else
                        "0"
                    end if
                end |λ|
            end script
 
            map(bChar, xs)
        end |λ|
    end script
    bindLR(my bitsFromIntLR(x), showBin)
end showBinary
 
 
-- JXA ------------------------------------------------------------------
 
--jsOp2 :: String -> a -> b -> c
on jsOp2(strOp, a, b)
    bindLR(evalJSLR(unwords({a as text, strOp, b as text})), my |id|) as integer
end jsOp2
 
--jsOp2 :: String -> a -> b
on jsOp1(strOp, a)
    bindLR(evalJSLR(unwords({strOp, a as text})), my |id|) as integer
end jsOp1
 
-- evalJSLR :: String -> Either String a
on evalJSLR(strJS)
    try -- NB if gJSC is global it must be released 
        -- (e.g. set to null) at end of script
        gJSC's evaluateScript
    on error
        set gJSC to current application's JSContext's new()
        log ("new JSC")
    end try
    set v to unwrap((gJSC's evaluateScript:(strJS))'s toObject())
    if v is missing value then
        |Left|("JS evaluation error")
    else
        |Right|(v)
    end if
end evalJSLR
 
-- GENERIC FUNCTIONS --------------------------------------------------
 
-- Left :: a -> Either a b
on |Left|(x)
    {type:"Either", |Left|:x, |Right|:missing value}
end |Left|
 
-- Right :: b -> Either a b
on |Right|(x)
    {type:"Either", |Left|:missing value, |Right|:x}
end |Right|
 
-- Tuple (,) :: a -> b -> (a, b)
on Tuple(a, b)
    {type:"Tuple", |1|:a, |2|:b, length:2}
end Tuple
 
-- Absolute value.
-- abs :: Num -> Num
on abs(x)
    if 0 > x then
        -x
    else
        x
    end if
end abs
 
-- bindLR (>>=) :: Either a -> (a -> Either b) -> Either b
on bindLR(m, mf)
    if missing value is not |Right| of m then
        mReturn(mf)'s |λ|(|Right| of m)
    else
        m
    end if
end bindLR
 
-- foldr :: (a -> b -> b) -> b -> [a] -> b
on foldr(f, startValue, xs)
    tell mReturn(f)
        set v to startValue
        set lng to length of xs
        repeat with i from lng to 1 by -1
            set v to |λ|(item i of xs, v, i, xs)
        end repeat
        return v
    end tell
end foldr
 
-- id :: a -> a
on |id|(x)
    x
end |id|
 
-- justifyRight :: Int -> Char -> String -> String
on justifyRight(n, cFiller, strText)
    if n > length of strText then
        text -n thru -1 of ((replicate(n, cFiller) as text) & strText)
    else
        strText
    end if
end justifyRight
 
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
    tell mReturn(f)
        set lng to length of xs
        set lst to {}
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs, i, xs)
        end repeat
        return lst
    end tell
end map
 
-- 'The mapAccumR function behaves like a combination of map and foldr; 
--  it applies a function to each element of a list, passing an accumulating 
--  parameter from |Right| to |Left|, and returning a final value of this 
--  accumulator together with the new list.' (see Hoogle)
-- mapAccumR :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
on mapAccumR(f, acc, xs)
    script
        on |λ|(x, a, i)
            tell mReturn(f) to set pair to |λ|(|1| of a, x, i)
            Tuple(|1| of pair, (|2| of pair) & |2| of a)
        end |λ|
    end script
    foldr(result, Tuple(acc, []), xs)
end mapAccumR
 
-- min :: Ord a => a -> a -> a
on min(x, y)
    if y < x then
        y
    else
        x
    end if
end min
 
-- Lift 2nd class handler function into 1st class script wrapper 
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    if class of f is script then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn
 
-- not :: Bool -> Bool
on |not|(p)
    not p
end |not|
 
-- Egyptian multiplication - progressively doubling a list, appending
-- stages of doubling to an accumulator where needed for binary 
-- assembly of a target length
-- replicate :: Int -> a -> [a]
on replicate(n, a)
    set out to {}
    if n < 1 then return out
    set dbl to {a}
 
    repeat while (n > 1)
        if (n mod 2) > 0 then set out to out & dbl
        set n to (n div 2)
        set dbl to (dbl & dbl)
    end repeat
    return out & dbl
end replicate
 
-- unlines :: [String] -> String
on unlines(xs)
    set {dlm, my text item delimiters} to ¬
        {my text item delimiters, linefeed}
    set str to xs as text
    set my text item delimiters to dlm
    str
end unlines
 
-- unwords :: [String] -> String
on unwords(xs)
    set {dlm, my text item delimiters} to {my text item delimiters, space}
    set s to xs as text
    set my text item delimiters to dlm
    return s
end unwords
 
-- unwrap :: NSObject -> a
on unwrap(objCValue)
    if objCValue is missing value then
        missing value
    else
        set ca to current application
        item 1 of ((ca's NSArray's arrayWithObject:objCValue) as list)
    end if
end unwrap
 
-- zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
on zipWith(f, xs, ys)
    set lng to min(length of xs, length of ys)
    if 1 > lng then return {}
    set lst to {}
    tell mReturn(f)
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs, item i of ys)
        end repeat
        return lst
    end tell
end zipWith