2019-05-10 05:02:47 +03:00
|
|
|
module Data.Noun.Jam where
|
|
|
|
|
|
|
|
import ClassyPrelude
|
|
|
|
import Data.Noun
|
2019-05-10 05:45:28 +03:00
|
|
|
import Data.Noun.Atom
|
2019-05-10 05:02:47 +03:00
|
|
|
import Data.Noun.Poet
|
|
|
|
import Data.Bits
|
|
|
|
import Control.Lens
|
2019-05-15 04:30:44 +03:00
|
|
|
import Text.Printf
|
2019-05-10 05:02:47 +03:00
|
|
|
|
|
|
|
import Data.Map (Map)
|
|
|
|
import Control.Monad (guard)
|
|
|
|
|
2019-05-15 01:13:18 +03:00
|
|
|
import Test.Tasty
|
|
|
|
import Test.Tasty.TH
|
|
|
|
import Test.Tasty.QuickCheck as QC
|
|
|
|
import Test.QuickCheck
|
|
|
|
|
2019-05-15 04:30:44 +03:00
|
|
|
|
|
|
|
-- Length-Encoded Atoms --------------------------------------------------------
|
|
|
|
|
|
|
|
mat :: Atom -> (Int, Atom)
|
|
|
|
mat 0 = (1, 1)
|
|
|
|
mat atm = (bufWid, buffer)
|
|
|
|
where
|
|
|
|
atmWid = bitWidth atm
|
|
|
|
preWid = bitWidth (toAtom atmWid)
|
|
|
|
bufWid = preWid + preWid + atmWid
|
|
|
|
prefix = shiftL 1 preWid
|
|
|
|
extras = takeBits (preWid-1) $ toAtom atmWid
|
|
|
|
suffix = xor extras (shiftL atm (preWid-1))
|
|
|
|
buffer = bitConcat prefix suffix
|
|
|
|
|
|
|
|
rub :: Cursor -> Maybe (Int, Atom)
|
|
|
|
rub slc@(Cursor idx buf) =
|
|
|
|
leadingZeros slc >>= \case
|
|
|
|
0 -> pure (1, 0)
|
|
|
|
prefix -> pure (sz, val)
|
|
|
|
where
|
|
|
|
widIdx = idx + 1 + prefix
|
|
|
|
width = fromSlice (Slice widIdx (prefix - 1) buf)
|
|
|
|
datIdx = widIdx + (prefix-1)
|
|
|
|
datWid = fromIntegral $ 2^(prefix-1) + width
|
|
|
|
sz = datWid + (2*prefix)
|
|
|
|
val = fromSlice (Slice datIdx datWid buf)
|
|
|
|
|
|
|
|
|
|
|
|
-- Noun Serialization ----------------------------------------------------------
|
2019-05-10 05:02:47 +03:00
|
|
|
|
|
|
|
jam :: Noun -> Atom
|
2019-05-15 01:13:18 +03:00
|
|
|
jam = view _2 . go 0 mempty
|
|
|
|
where
|
2019-05-15 04:30:44 +03:00
|
|
|
insertNoun :: Noun -> Int -> Map Noun Int -> Map Noun Int
|
|
|
|
insertNoun n i tbl = lookup n tbl
|
|
|
|
& maybe tbl (const $ insertMap n i tbl)
|
|
|
|
|
2019-05-15 01:13:18 +03:00
|
|
|
go :: Int -> Map Noun Int -> Noun -> (Int, Atom, Map Noun Int)
|
2019-05-15 04:30:44 +03:00
|
|
|
go idx oldTbl noun =
|
|
|
|
let tbl = insertNoun noun idx oldTbl in
|
|
|
|
case (Nothing :: Maybe Int, noun) of
|
2019-05-15 01:13:18 +03:00
|
|
|
(Just ref, Atom atm) | bitWidth atm <= bitWidth (toAtom ref) ->
|
|
|
|
(1+sz, shiftL res 1, tbl)
|
|
|
|
where (sz, res) = mat atm
|
|
|
|
(Just ref, _) ->
|
|
|
|
(2+sz, xor 3 (shiftL res 2), tbl)
|
|
|
|
where (sz, res) = mat (toAtom ref)
|
|
|
|
(Nothing, Atom atm) ->
|
|
|
|
(1+sz, shiftL res 1, tbl)
|
|
|
|
where (sz, res) = mat atm
|
|
|
|
(Nothing, Cell lef rit) ->
|
|
|
|
(2+lSz+rSz, xor 1 (shiftL (bitConcat lRes rRes) 2), rTbl)
|
|
|
|
where (lSz, lRes, lTbl) = go (idx+2) tbl lef
|
|
|
|
(rSz, rRes, rTbl) = go (idx+lSz) lTbl rit
|
2019-05-10 05:02:47 +03:00
|
|
|
|
2019-05-15 04:30:44 +03:00
|
|
|
|
2019-05-11 00:59:45 +03:00
|
|
|
leadingZeros :: Cursor -> Maybe Int
|
|
|
|
leadingZeros (Cursor idx buf) = go 0
|
2019-05-10 05:02:47 +03:00
|
|
|
where wid = bitWidth buf
|
|
|
|
go n = do guard (n < wid)
|
|
|
|
if bitIdx (idx+n) buf then pure n else go (n+1)
|
|
|
|
|
|
|
|
cue :: Atom -> Maybe Noun
|
|
|
|
cue buf = view _2 <$> go mempty 0
|
|
|
|
where
|
2019-05-11 00:59:45 +03:00
|
|
|
go :: Map Int Noun -> Int -> Maybe (Int, Noun, Map Int Noun)
|
2019-05-10 05:02:47 +03:00
|
|
|
go tbl i =
|
|
|
|
case (bitIdx i buf, bitIdx (i+1) buf) of
|
2019-05-11 00:59:45 +03:00
|
|
|
(False, _ ) -> do (wid,at) <- rub (Cursor (i+1) buf)
|
2019-05-10 05:02:47 +03:00
|
|
|
let r = toNoun at
|
|
|
|
pure (wid+1, r, insertMap i r tbl)
|
|
|
|
(True, False ) -> do (lSz,lef,tbl) <- go tbl (i+2)
|
2019-05-11 00:59:45 +03:00
|
|
|
(rSz,rit,tbl) <- go tbl (i+2+fromIntegral lSz)
|
2019-05-10 05:02:47 +03:00
|
|
|
let r = Cell lef rit
|
|
|
|
pure (2+lSz+rSz, r, insertMap i r tbl)
|
2019-05-11 00:59:45 +03:00
|
|
|
(True, True ) -> do (wid,at) <- rub (Cursor (i+2) buf)
|
|
|
|
r <- lookup (fromIntegral at) tbl
|
2019-05-10 05:02:47 +03:00
|
|
|
pure (2+wid, r, tbl)
|
2019-05-11 00:59:45 +03:00
|
|
|
|
2019-05-15 04:30:44 +03:00
|
|
|
|
|
|
|
-- Tests -----------------------------------------------------------------------
|
|
|
|
|
2019-05-15 01:13:18 +03:00
|
|
|
pills :: [Atom]
|
|
|
|
pills = [ 0x2, 0xc, 0x48, 0x29, 0xc9, 0x299
|
2019-05-15 04:30:44 +03:00
|
|
|
, 0x3170_c7c1, 0x93_c7c1, 0xa_72e0, 0x1bd5_b7dd_e080
|
2019-05-15 01:13:18 +03:00
|
|
|
]
|
|
|
|
|
2019-05-11 00:59:45 +03:00
|
|
|
cueTest :: Maybe [Noun]
|
2019-05-15 01:13:18 +03:00
|
|
|
cueTest = traverse cue pills
|
|
|
|
|
|
|
|
jamTest :: Maybe [Atom]
|
|
|
|
jamTest = fmap jam <$> cueTest
|
|
|
|
|
2019-05-15 04:30:44 +03:00
|
|
|
prop_jamCue :: Noun -> Bool
|
|
|
|
prop_jamCue n = Just n == cue (jam n)
|
|
|
|
|
|
|
|
prop_matRub :: Atom -> Bool
|
|
|
|
prop_matRub atm = matSz==rubSz && rubRes==atm
|
|
|
|
where
|
|
|
|
(matSz, matBuf) = mat atm
|
|
|
|
(rubSz, rubRes) = fromMaybe (0,0) (rub $ Cursor 0 matBuf)
|
2019-05-15 01:13:18 +03:00
|
|
|
|
|
|
|
main :: IO ()
|
|
|
|
main = $(defaultMainGenerator)
|
|
|
|
|
|
|
|
-- ?: =(0 a)
|
|
|
|
-- [1 1]
|
|
|
|
-- =+ b=(met 0 a)
|
|
|
|
-- =+ c=(met 0 b)
|
|
|
|
-- :- (add (add c c) b)
|
|
|
|
-- (cat 0 (bex c) (mix (end 0 (dec c) b) (lsh 0 (dec c) a)))
|
|
|
|
|
|
|
|
-- |= a/@
|
|
|
|
-- ^- {p/@ q/@}
|
|
|
|
-- ?: =(0 a)
|
|
|
|
-- [1 1]
|
|
|
|
-- =+ b=(met 0 a)
|
|
|
|
-- =+ c=(met 0 b)
|
|
|
|
-- :- (add (add c c) b)
|
|
|
|
-- (cat 0 (bex c) )
|
|
|
|
|
|
|
|
-- ++ jam
|
|
|
|
-- |= a/*
|
|
|
|
-- ^- @
|
|
|
|
-- =+ b=0
|
|
|
|
-- =+ m=`(map * @)`~
|
|
|
|
-- =< q
|
|
|
|
-- |- ^- {p/@ q/@ r/(map * @)}
|
|
|
|
-- =+ c=(~(get by m) a)
|
|
|
|
-- ?~ c
|
|
|
|
-- => .(m (~(put by m) a b))
|
|
|
|
-- ?: ?=(@ a)
|
|
|
|
-- =+ d=(mat a)
|
|
|
|
-- [(add 1 p.d) (lsh 0 1 q.d) m]
|
|
|
|
-- => .(b (add 2 b))
|
|
|
|
-- =+ d=$(a -.a)
|
|
|
|
-- =+ e=$(a +.a, b (add b p.d), m r.d)
|
|
|
|
-- [(add 2 (add p.d p.e)) (mix 1 (lsh 0 2 (cat 0 q.d q.e))) r.e]
|
|
|
|
-- ?: ?&(?=(@ a) (lte (met 0 a) (met 0 u.c)))
|
|
|
|
-- =+ d=(mat a)
|
|
|
|
-- [(add 1 p.d) (lsh 0 1 q.d) m]
|
|
|
|
-- =+ d=(mat u.c)
|
|
|
|
-- [(add 2 p.d) (mix 3 (lsh 0 2 q.d)) m]
|