on master help sign in
commit05ceebb14677e141ccdbe5b5e6b3afa7c3062b90 authoriko <mail@iko.soy> dateSun 26 Jan 2025, 04:28 (2 years ago) parenta885947
9 files changed+149−56
package.yaml+3 res/dec.jam+11 src/Nock/Jam.hs+71−44 src/Nock/Jets.hs+13−1 src/Nock/Mug.hs+5−2 src/Nock/Types.hs+27 stack.yaml+1−1 stack.yaml.lock+4−4 tests/Main.hs+14−4
package.yaml+3
@@ -21,6 +21,7 @@ dependencies:
2121 - effectful
2222 - unordered-containers
2323 - murmur3
24+ - file-embed
2425library:
2526 source-dirs: src
2627
@@ -90,3 +91,5 @@ tests:
9091 - tasty-hspec
9192 - hspec
9293 - effectful
94+ - tasty-quickcheck
95+ - tasty-hunit
res/dec.jamnew file+11
@@ -0,0 +1,11 @@
1+�~[Y����lea��K��qpr�r�qpy�r�v�rpwpz�6x=�;89x9�<�98;�;�� r��!�.�b�46T�A�8��-a>̡bl��d� Z�C�:��0׳
2+� Xsql��`q؅�P)&�o��d� ZP>$� �A2d-��D ;$����1H� ��]�� ��9��0ׇlf�,l���:v���~A�x���.܆J1!\B:H� ��],H6��Cq� D ;a|�`�9���b��5�t�FF��C V���;sq؅�p��� �b���d �r8ɐA���� ����R��!�Y�I7xlt��L<�`����f��,n�~C ��889x:�=x:89x9h\<� �^.�v��C �]� ��p�n��`C���.$����1H� ���p�Ϊ����q(�d� ZP>$�?����<Ի�\b��5�t�Gf'��C ~A���\vA� |9���!Yq��f�pҍ^[~81X���2�8��`A20*�C�B9\0�lf '�8���ه3���_l��'�lf '�8�����3������avC�bC�=T��],�p*����P)�]؅]� �␈9��,�d� Z/$n� � 2��P�� ذ�3H� ����~�`18dk����9��![s(��lf '�8�ѡ�3������a ����C
3+�fr��f�pҍ�z81X���;sq� ��Ú�!�Y�I7xgt��L<�`�_l�3�ݐ�8$+1��N�q�kKsg�!�/6����7lL��ͬ���7�p&b0��`Ý���56�?���A�8>^.N.>��0ׇ �!-��j$C��n8����x� D {H�.�C 1��N�q���g�!+6T��A�� =T� ��P$�[���A���A2P�18��� ;փd� Z�áu�`��m8�̡bb��`��J�86T��
4+�!V�7��V��J�\��%��]+6���9� X��A2d-���� X���!�ha'�>\0�` �>H� �����p�V�18�`����A��R,��ݰ3��n�J7T�C���a�w� �����~��! � ����` �6� �pwq�� ����` �ɐA����a���C V��
5+� X� �_�C�pN*Ƅ��A��`�7���-�szlXV:��V�18�`lX�_*�� X� ;�+6T��9=~á8$w��P<l��~�7+�b� ذB�8�0] � U�i~Xa?���A�a�q��Rz,��]� ��p��� ��j=� ��P?mkv�6\��Jqh�16�����a���C *�� X؅ݰ3}X3�P1���~��
6+� +���` ��b����V�18�`A��R,���pg� ��a����
7+�!�`C�X ��P<��
8+�! � +�`C�X ��P\~áu��C +�b��`�
9+�� �P)��nؙ^C����o8��d��:��M�C��A�����ɡ��a���C ����A�a����~���`�
10+�� XC���ڹ6�cq��{� X� ����a����~��!�`�
11+�� �P)��nؙ��e��~��~��! � �P)�]��ȡblh�:��-FcC��av�6�C��P)�aC���>���|��d� Z�A� 8W�� 2�vá5����C���s��!�Y�I7xca��L<�`����a7\��ǰ҂�ǰ ����� W� �����],H��P$C��n��]x̰ ��k��]�C���l�D;$��á8H� ��]� ;��`A2�á8H� ��ݐ�9t�=\0�oع�8�!�ha~��� 2���`C�C7�C ]x��9�`3k8����<��� � �P)�]� �Z7T�C[� �v� �_7ԏ�l�D;64�$C��.����A��1����v.��.΃d� Z؅߰sy�d{��{�`�!�Y�I7xma��L<�`��e�
src/Nock/Jam.hs+71−44
@@ -11,56 +11,69 @@ import Data.Bits
1111import Data.ByteString.Lazy (ByteString)
1212import Data.Map (Map)
1313import Data.Map qualified as M
14+import GHC.Base (Int (..), Word (..), Word#, int2Word#, minusWord#, or#, plusWord#, shiftL#, word2Int#)
15+import GHC.Num
1416import Nock
1517import Nock.Types
16−import Numeric.Natural
1718
1819type BitParser = StateT (Int, Map Int Noun) BitGet
1920
20−parseBit :: BitParser Bool
21−parseBit = do
21+parseBit# :: BitParser Int
22+parseBit# = do
2223 (counter, m) <- get
23− b <- lift getBool
24+ b <- lift getBool#
2425 put (counter + 1, m)
2526 pure b
2627
27−parseBits :: Int -> BitParser [Bool]
28−parseBits 0 = pure []
29−parseBits n = do
30− b <- parseBit
31− (b :) <$> parseBits (n - 1)
28+parseBits# :: Word# -> BitParser Natural
29+parseBits# 0## = pure 0
30+parseBits# n = do
31+ I# b <- parseBit#
32+ rest <- parseBits# (n `minusWord#` 1##)
33+ pure $ (rest `shiftL` 1) `naturalOr` NS (int2Word# b)
3234
3335getOffset :: BitParser Int
3436getOffset = fst <$> get
3537
38+getMapping :: BitParser (Map Int Noun)
39+getMapping = snd <$> get
40+
41+putMapping :: Map Int Noun -> BitParser ()
42+putMapping m = do
43+ (offset, _) <- get
44+ put (offset, m)
45+
3646cue :: ByteString -> Noun
3747cue = runGet (runBitGet . withBitOrder LL . flip evalStateT (0, M.empty) $ cue')
3848
3949cue' :: BitParser Noun
4050cue' = do
4151 offset <- getOffset
42− isNotAtom <- parseBit
52+ I# isNotAtom <- parseBit#
4353 case isNotAtom of
44− False -> do
54+ 0# -> do
4555 a' <- rub'
4656 let a = atom a'
47− (offset, m) <- get
48− put (offset, M.insert offset a m)
57+ m <- getMapping
58+ putMapping $ M.insert offset a m
4959 pure a
50− True -> do
51− isNotRef <- parseBit
52− case isNotRef of
53− False -> do
60+ _ -> do
61+ I# isRef <- parseBit#
62+ case isRef of
63+ 0# -> do
5464 x <- cue'
5565 y <- cue'
5666 let c = cell x y
57− (offset, m) <- get
58− put (offset, M.insert offset c m)
67+ m <- getMapping
68+ putMapping $ M.insert offset c m
5969 pure c
60− True -> do
70+ _ -> do
6171 ref <- rub'
62− (_, m) <- get
63− case M.lookup (fromIntegral ref) m of
72+ let ref# = case ref of
73+ NS w -> I# (word2Int# w)
74+ _ -> undefined
75+ m <- getMapping
76+ case M.lookup ref# m of
6477 Nothing -> undefined
6578 Just a -> pure a
6679
@@ -69,11 +82,11 @@ jam n = runPut . runBitPut . withBitOrder LL $ jam' n
6982
7083jam' :: Noun -> BitPut ()
7184jam' (Atom n _) = do
72− putBool False
85+ putBool# 0##
7386 mat' n
7487jam' (Cell lhs rhs _) = do
75− putBool True
76− putBool False
88+ putBool# 1##
89+ putBool# 0##
7790 jam' lhs
7891 jam' rhs
7992
@@ -81,16 +94,15 @@ mat :: Natural -> ByteString
8194mat n = runPut . runBitPut . withBitOrder LL $ mat' n
8295
8396mat' :: Natural -> BitPut ()
84−mat' 0 = putBool True
97+mat' 0 = putBool# 1##
8598mat' n = do
86− let bits = numToBits n
87− bitsLength = length bits
88− lengthBits = init $ numToBits bitsLength
89− putBool False
99+ let bitsLength = countBits# n
100+ lengthBits = init $ numToBits (W# bitsLength)
101+ putBool# 0##
90102 putBits $ replicate (length lengthBits) False
91− putBool True
103+ putBool# 1##
92104 putBits lengthBits
93− putBits bits
105+ putNumToBits# n
94106
95107putBits :: [Bool] -> BitPut ()
96108putBits [] = pure ()
@@ -101,24 +113,39 @@ rub = runGet (runBitGet . withBitOrder LL . flip evalStateT (0, M.empty) $ rub')
101113
102114rub' :: BitParser Natural
103115rub' = do
104− parseBit >>= \case
105− True -> pure 0
106− False -> do
107− lengthOfLength <- countZeros 0
108− lengthBits <- (++ [True]) <$> parseBits lengthOfLength
109− let lent = bitsToNum lengthBits
110− bitsToNum <$> parseBits lent
111−
112−countZeros :: Int -> BitParser Int
116+ parseBit# >>= \case
117+ I# 0# -> do
118+ W# lengthOfLength <- countZeros 0
119+ lengthBits <- parseBits# lengthOfLength
120+ let lengthBits# = case lengthBits of
121+ NS w -> w
122+ _ -> undefined
123+ let lent = lengthBits# `or#` (1## `shiftL#` word2Int# lengthOfLength)
124+ parseBits# lent
125+ _ -> pure 0
126+
127+countZeros :: Word -> BitParser Word
113128countZeros n = do
114− b <- parseBit
129+ I# b <- parseBit#
115130 case b of
116− True -> pure n
117− False -> countZeros (n + 1)
131+ 0# -> countZeros (n + 1)
132+ _ -> pure n
118133
119134numToBits :: (Bits a, Integral a) => a -> [Bool]
120135numToBits n | n <= 0 = []
121136numToBits n = ((n .&. 1) == 1) : numToBits (shiftR n 1)
122137
138+countBits# :: Natural -> Word#
139+countBits# (NS 0##) = 0##
140+countBits# n = 1## `plusWord#` countBits# (n `naturalShiftR#` 1##)
141+
142+putNumToBits# :: Natural -> BitPut ()
143+putNumToBits# (NS 0##) = pure ()
144+putNumToBits# n = case n .&. 1 of
145+ NS w -> putBool# w >> putNumToBits# (n `naturalShiftR#` 1##)
146+ _ -> undefined
147+
148+-- ((n .&. 1) == 1) : numToBits (shiftR n 1)
149+
123150bitsToNum :: (Bits a, Integral a) => [Bool] -> a
124151bitsToNum = foldr (\b acc -> shiftL acc 1 .|. if b then 1 else 0) 0
src/Nock/Jets.hs+13−1
@@ -1,8 +1,20 @@
1−module Nock.Jets (add, dec) where
1+{-# LANGUAGE TemplateHaskell #-}
22
3+module Nock.Jets (add, dec, decJam, decNoun) where
4+
5+import Data.ByteString (ByteString)
6+import Data.ByteString.Lazy qualified as BSL
7+import Data.FileEmbed (embedFileRelative)
8+import Nock.Jam (cue)
39import Nock.Parser qualified
410import Nock.Types
511
12+decJam :: ByteString
13+decJam = $(embedFileRelative "res/dec.jam")
14+
15+decNoun :: Noun
16+decNoun = cue $ BSL.fromStrict decJam
17+
618dec :: Noun
719dec = Nock.Parser.noun "[8 [1 0] 8 [1 6 [5 [0 30] 4 0 6] [0 6] 9 2 10 [6 4 0 6] 0 1] 9 2 0 1]"
820
src/Nock/Mug.hs+5−2
@@ -1,6 +1,9 @@
1−module Nock.Mug () where
1+module Nock.Mug (Mug, mugBS, mugAtom, mugBoth) where
22
3+import Data.Bits
34import Data.ByteString (ByteString)
5+import Data.ByteString.Builder
6+import Data.ByteString.Lazy (toStrict)
47import Data.Hash.Murmur (murmur3)
58import Data.Word (Word32)
69import Nock.Types
@@ -11,7 +14,7 @@ mugBS :: ByteString -> Word32
1114mugBS = mum 0xcafe_babe 0x7fff
1215
1316mugAtom :: Atom -> Word32
14−mugAtom = mugBS . atomBytes
17+mugAtom = mugBS . atomByteString
1518
1619mugBoth :: Word32 -> Word32 -> Word32
1720mugBoth m n =
src/Nock/Types.hs+27
@@ -2,6 +2,8 @@ module Nock.Types
22 ( pretty,
33 Noun (..),
44 Atom,
5+ atomShortByteString,
6+ atomByteString,
57 Annotation (..),
68 atom,
79 cell,
@@ -11,7 +13,10 @@ module Nock.Types
1113 )
1214where
1315
16+import Control.Applicative
1417import Control.DeepSeq
18+import Data.ByteString (ByteString)
19+import Data.ByteString.Short
1520import Data.HashMap.Strict qualified as HM
1621import Data.Text.Lazy qualified as TL
1722import Data.Text.Lazy.Builder qualified as TLB
@@ -20,7 +25,10 @@ import Effectful
2025import Effectful.State.Static.Local qualified as SEL
2126import GHC.Generics
2227import GHC.Natural
28+import GHC.Num (Natural (..))
29+import GHC.Num.BigNat (bigNatFromWord#)
2330import System.Mem.StableName
31+import Test.QuickCheck
2432
2533newtype EqualityCache = EqualityCache (HM.HashMap (StableName Noun, StableName Noun) Bool)
2634 deriving newtype (Semigroup, Monoid)
@@ -64,12 +72,31 @@ annotation (Cell _ _ ann) = ann
6472
6573type Atom = Natural
6674
75+atomShortByteString :: Atom -> ShortByteString
76+atomShortByteString (NB ba) = SBS ba
77+atomShortByteString (NS w) = SBS (bigNatFromWord# w)
78+
79+atomByteString :: Atom -> ByteString
80+atomByteString = fromShort . atomShortByteString
81+
6782data Noun
6883 = Atom !Atom Annotation
6984 | Cell !Noun !Noun Annotation
7085 deriving stock (Generic)
7186 deriving anyclass (NFData)
7287
88+instance Eq Noun where
89+ (Cell lhsA lhsB _) == (Cell rhsA rhsB _) = lhsA == rhsA && lhsB == rhsB
90+ (Atom a _) == (Atom b _) = a == b
91+ _ == _ = False
92+
93+instance Arbitrary Noun where
94+ arbitrary =
95+ oneof
96+ [ atom <$> arbitrarySizedNatural,
97+ cell <$> arbitrary <*> arbitrary
98+ ]
99+
73100instance Show Noun where
74101 show = TL.unpack . pretty
75102
stack.yaml+1−1
@@ -51,7 +51,7 @@ extra-deps:
5151# - git: https://github.com/hsyl20/binary-bits.git
5252# commit: 8aa66ff52166ff283b66c7c322108fcb4aa55192
5353- git: https://github.com/ilyakooo0/binary-bits
54− commit: f58ae476ff50dfc277f8dd603142b7ce864b8e03
54+ commit: 21adca7da6e378c8e3cc7bb1afa9dd441a721016
5555# Override default flag values for local packages and extra-deps
5656# flags: {}
5757
stack.yaml.lock+4−4
@@ -5,15 +5,15 @@
55
66packages:
77- completed:
8− commit: f58ae476ff50dfc277f8dd603142b7ce864b8e03
8+ commit: 21adca7da6e378c8e3cc7bb1afa9dd441a721016
99 git: https://github.com/ilyakooo0/binary-bits
1010 name: binary-bits
1111 pantry-tree:
12− sha256: d4886449b9be758d88537eb50a5f9e7c456398c4e1a0b38eb6a2eba07ce71300
13− size: 808
12+ sha256: b6f354e26ca7563ad73a3234cd43918ba8edfb5bee7c5e5f8a9173c9109bba66
13+ size: 907
1414 version: '0.6'
1515 original:
16− commit: f58ae476ff50dfc277f8dd603142b7ce864b8e03
16+ commit: 21adca7da6e378c8e3cc7bb1afa9dd441a721016
1717 git: https://github.com/ilyakooo0/binary-bits
1818snapshots:
1919- completed:
tests/Main.hs+14−4
@@ -4,7 +4,11 @@ import Control.Monad
44import Data.ByteString.Lazy qualified as BSL
55import Data.Function
66import Data.Text.Lazy.Encoding as TL
7+import Effectful
8+import Effectful.State.Static.Local qualified as SEL
79import Nock
10+import Nock.Jam
11+import Nock.Jets
812import Nock.Parser qualified
913import Nock.Printer
1014import Nock.Types
@@ -12,18 +16,24 @@ import System.FilePath.Posix
1216import System.Process.Typed
1317import Test.Tasty
1418import Test.Tasty.Golden
15−import Effectful
16−import Effectful.State.Static.Local qualified as SEL
19+import Test.Tasty.HUnit (assertEqual, testCase, (@=?), (@?=))
20+import Test.Tasty.QuickCheck
1721
1822main :: IO ()
1923main = do
2024 spec <- goldenTest
21− defaultMain $ spec
25+ defaultMain $
26+ testGroup
27+ "nock"
28+ [ spec,
29+ testProperty "cue . jam == id" (\noun -> noun === (cue . jam) noun),
30+ testCase "" (decJam @?= BSL.toStrict ((jam . cue) (BSL.fromStrict decJam)))
31+ ]
2232
2333goldenTest :: IO TestTree
2434goldenTest = do
2535 files <- findByExtension [".hoon"] "tests/golden"
26− fmap (testGroup "nock") $ forM files $ \source -> do
36+ fmap (testGroup "golden") $ forM files $ \source -> do
2737 let target = replaceExtension source ".nock"
2838 pure $ goldenVsString (takeBaseName source) target $ do
2939 hoon <- BSL.readFile source