module Language.Subleq.Model.InstructionSet.SubleqR (step, initialMachine, BitReversable(..)) where
import Data.Bits
import Language.Subleq.Model.Prim
import qualified Language.Subleq.Model.Memory as Mem
explosion b 0 = [0]
explosion b x | b + x == b 1 = [b + x]
| x < 0 && (x) < b = [b + x, b 1]
explosion b x = r : explosion b q
where
(q,r) = x `divMod` b
implosion b [s] | s == 0 = 0
| s == b 1 = 1
implosion b (x:xs) = x + b * implosion b xs
extend 0 _ = []
extend _ [] = []
extend 1 (x:xs) = [x]
extend n [x] = x : extend (n 1) [x]
extend n (x:xs) = x : extend (n 1) xs
bitRev n = implosion 2 . reverse . extend n . explosion 2
bitRevFix :: (FiniteBits a) => a -> a
bitRevFix n = foldl setBit zeroBits bs'
where
l = finiteBitSize n
bs = filter (testBit n) [0..(l1)]
bs' = map (\x -> l x 1) bs
bitLen = length . explosion 2
bitRevSub a b = r (r a r b)
where
l = length (explosion 2 a) `max` length (explosion 2 b)
r = bitRev l
r' = bitRev (l + 1)
class BitReversable a where
reversal :: Int -> a -> a
reversalSub :: a -> a -> a
instance BitReversable Integer where
reversal = bitRev
reversalSub a b = r (r a r b)
where
l = length (explosion 2 a) `max` length (explosion 2 b)
r = bitRev l
instance (Num a, FiniteBits a, Bounded a) => BitReversable a where
reversal _ = bitRevFix
reversalSub a b = r (r a r b)
where
r = bitRevFix
step :: (Memory a a m, Num a, Ord a, Integral a, BitReversable a) => Machine a a m Bool
step = do
pc <- getPC
pA <- readMem pc
pB <- readMem $ pc + 1
pC <- readMem $ pc + 2
a <- readMem pA
b <- readMem pB
let b' = if pC < 0 then reversalSub b a else b a
let cond = if pC < 0 then b' == 0 || b' `mod` 2 == 1 else b' <= 0
let pc' = if cond then abs pC else pc + 3
writeMem pB b'
putPC pc'
return $ pC /= 0
initialMachine :: (Memory a a m, Num a, Ord a, Enum a) => SubleqState a w m
initialMachine = (6, Mem.fromAssocList . zip [0..] $ [ 0, 3, 5, 1, 0, 0
, 1, 0, 9
, 2, 0, 12
, 3, 3, 15
, 0, 3, 18
, 0, 0, 1])