on master help sign in
not working jam
commit38bd90e92e649f3f58c4fe2c1ce5d2358da48387 authoriko <mail@iko.soy> dateFri 2 May 2025, 23:02 (1 year ago) parent05ceebb
12 files changed+197−121
bench/Main.hs+2−1 flake.lock+3−3 flake.nix+1−1 package.yaml+2 src/Nock.hs+4−4 src/Nock/Cue.hs+98 src/Nock/Jam.hs+71−103 src/Nock/Jets.hs+2−1 src/Nock/Types.hs+6−1 stack.yaml+1−1 stack.yaml.lock+4−4 tests/Main.hs+3−2
bench/Main.hs+2−1
@@ -10,6 +10,7 @@ import Nock.Parser (noun)
1010import System.FilePath.Posix
1111import System.Process.Typed
1212import Test.Tasty.Golden (findByExtension)
13+import Effectful
1314
1415main :: IO ()
1516main = do
@@ -22,5 +23,5 @@ main = do
2223 $ proc "urbit" ["eval"]
2324 & setStdin (byteStringInput hoon)
2425 & setStderr nullStream
25− pure $ bench (takeBaseName hoonFile) $ nf tar $ cell (atom 0) nock
26+ pure $ bench (takeBaseName hoonFile) $ nf (runPureEff . tar) $ cell (atom 0) nock
2627 defaultMain benchmarks
flake.lock+3−3
@@ -19,11 +19,11 @@
1919 },
2020 "nixpkgs": {
2121 "locked": {
22− "lastModified": 1737062831,
23− "narHash": "sha256-Tbk1MZbtV2s5aG+iM99U8FqwxU/YNArMcWAv6clcsBc=",
22+ "lastModified": 1746141548,
23+ "narHash": "sha256-IgBWhX7A2oJmZFIrpRuMnw5RAufVnfvOgHWgIdds+hc=",
2424 "owner": "NixOS",
2525 "repo": "nixpkgs",
26− "rev": "5df43628fdf08d642be8ba5b3625a6c70731c19c",
26+ "rev": "f02fddb8acef29a8b32f10a335d44828d7825b78",
2727 "type": "github"
2828 },
2929 "original": {
flake.nix+1−1
@@ -8,7 +8,7 @@
88 let
99 supportedSystems =
1010 [ "x86_64-linux" "x86_64-darwin" "aarch64-darwin" "aarch64-linux" ];
11− compilerVersion = "966";
11+ compilerVersion = "984";
1212 in flake-utils.lib.eachSystem supportedSystems (system:
1313 let pkgs = import nixpkgs { inherit system; };
1414 in {
package.yaml+2
@@ -22,6 +22,7 @@ dependencies:
2222 - unordered-containers
2323 - murmur3
2424 - file-embed
25+ - mtl
2526library:
2627 source-dirs: src
2728
@@ -35,6 +36,7 @@ benchmarks:
3536 main: bench/Main.hs
3637
3738 dependencies:
39+ - effectful
3840 - tasty
3941 - nock
4042ghc-options: >
src/Nock.hs+4−4
@@ -43,8 +43,8 @@ lus ~(Atom nat _) = atom $ case nat of
4343 (# l, c #) -> NB (bigNatFromWord2# (int2Word# c) l)
4444 (NB n) -> NB (bigNatAddWord# n 1##)
4545
46−tis :: (SEL.State EqualityCache :> es, IOE :> es) => Noun -> Noun -> Eff es Noun
47−tis lhs rhs = nounEq lhs rhs <&> \eq -> if eq then sig else one
46+tis :: Noun -> Noun -> Eff es Noun
47+tis lhs rhs = pure $ if lhs == rhs then sig else one
4848
4949fas# :: Word# -> Noun -> Noun
5050fas# lhs rhs =
@@ -84,10 +84,10 @@ hax n b c =
8484 then hax a (cell (fas (n - 1) c) b) c
8585 else hax a (cell b (fas (n + 1) c)) c
8686
87−tar :: (SEL.State EqualityCache :> es, IOE :> es) => Noun -> Eff es Noun
87+tar :: Noun -> Eff es Noun
8888tar ~(Cell subject ~(Cell a b _) _) = tar' a b subject
8989
90−tar' :: (SEL.State EqualityCache :> es, IOE :> es) => Noun -> Noun -> Noun -> Eff es Noun
90+tar' :: Noun -> Noun -> Noun -> Eff es Noun
9191tar' b c subject = case b of
9292 Cell x y _ -> case c of
9393 ~(Cell l k _) -> cell <$> tar' x y subject <*> tar' l k subject
src/Nock/Cue.hsnew file+98
@@ -0,0 +1,98 @@
1+module Nock.Cue (cue, rub) where
2+
3+import Control.Monad.Trans.Class
4+import Control.Monad.Trans.State
5+import Data.Binary.Bits.BitOrder
6+import Data.Binary.Bits.Get
7+import Data.Binary.Get (runGet)
8+import Data.Bits
9+import Data.ByteString.Lazy (ByteString)
10+import Data.Map (Map)
11+import Data.Map qualified as M
12+import GHC.Base (Int (..), Word (..), Word#, int2Word#, minusWord#, or#, shiftL#, word2Int#)
13+import GHC.Num
14+import Nock.Types
15+
16+type BitParser = StateT (Int, Map Int Noun) BitGet
17+
18+parseBit# :: BitParser Int
19+parseBit# = do
20+ (counter, m) <- get
21+ b <- lift getBool#
22+ put (counter + 1, m)
23+ pure b
24+
25+parseBits# :: Word# -> BitParser Natural
26+parseBits# 0## = pure 0
27+parseBits# n = do
28+ I# b <- parseBit#
29+ rest <- parseBits# (n `minusWord#` 1##)
30+ pure $ (rest `shiftL` 1) `naturalOr` NS (int2Word# b)
31+
32+getOffset :: BitParser Int
33+getOffset = fst <$> get
34+
35+getMapping :: BitParser (Map Int Noun)
36+getMapping = snd <$> get
37+
38+putMapping :: Map Int Noun -> BitParser ()
39+putMapping m = do
40+ (offset, _) <- get
41+ put (offset, m)
42+
43+cue :: ByteString -> Noun
44+cue = runGet (runBitGet . withBitOrder LL . flip evalStateT (0, M.empty) $ cue')
45+
46+cue' :: BitParser Noun
47+cue' = do
48+ offset <- getOffset
49+ I# isNotAtom <- parseBit#
50+ case isNotAtom of
51+ 0# -> do
52+ a' <- rub'
53+ let a = atom a'
54+ m <- getMapping
55+ putMapping $ M.insert offset a m
56+ pure a
57+ _ -> do
58+ I# isRef <- parseBit#
59+ case isRef of
60+ 0# -> do
61+ x <- cue'
62+ y <- cue'
63+ let c = cell x y
64+ m <- getMapping
65+ putMapping $ M.insert offset c m
66+ pure c
67+ _ -> do
68+ ref <- rub'
69+ let ref# = case ref of
70+ NS w -> I# (word2Int# w)
71+ _ -> undefined
72+ m <- getMapping
73+ case M.lookup ref# m of
74+ Nothing -> undefined
75+ Just a -> pure a
76+
77+rub :: ByteString -> Natural
78+rub = runGet (runBitGet . withBitOrder LL . flip evalStateT (0, M.empty) $ rub')
79+
80+rub' :: BitParser Natural
81+rub' = do
82+ parseBit# >>= \case
83+ I# 0# -> do
84+ W# lengthOfLength <- countZeros 0
85+ lengthBits <- parseBits# lengthOfLength
86+ let lengthBits# = case lengthBits of
87+ NS w -> w
88+ _ -> undefined
89+ let lent = lengthBits# `or#` (1## `shiftL#` word2Int# lengthOfLength)
90+ parseBits# lent
91+ _ -> pure 0
92+
93+countZeros :: Word -> BitParser Word
94+countZeros n = do
95+ I# b <- parseBit#
96+ case b of
97+ 0# -> countZeros (n + 1)
98+ _ -> pure n
src/Nock/Jam.hs+71−103
@@ -1,136 +1,109 @@
1−module Nock.Jam (jam, cue, mat, rub) where
1+{-# LANGUAGE NoMonomorphismRestriction #-}
22
3+module Nock.Jam (jam, mat) where
4+
5+import Control.Monad.Identity
6+import Control.Monad.State.Strict (MonadState (..))
37import Control.Monad.Trans.Class
4−import Control.Monad.Trans.State
8+import Control.Monad.Trans.State hiding (get, put)
59import Data.Binary.Bits.BitOrder
6−import Data.Binary.Bits.Get
7−import Data.Binary.Bits.Put
8−import Data.Binary.Get (runGet)
10+import Data.Binary.Bits.Put qualified as Put
911import Data.Binary.Put (runPut)
1012import Data.Bits
1113import Data.ByteString.Lazy (ByteString)
12−import Data.Map (Map)
13−import Data.Map qualified as M
14−import GHC.Base (Int (..), Word (..), Word#, int2Word#, minusWord#, or#, plusWord#, shiftL#, word2Int#)
14+import Data.HashMap.Strict qualified as HM
15+import Data.Map.Strict (Map)
16+import Data.Map.Strict qualified as M
17+import GHC.Base (Word (..), Word#, plusWord#)
1518import GHC.Num
16−import Nock
1719import Nock.Types
1820
19−type BitParser = StateT (Int, Map Int Noun) BitGet
21+type BitPrinterM = StateT (Natural, Map Noun Natural) Put.BitPut
22+
23+newtype SomeBitPrinter a = SomeBitPrinter (forall m. (BitPrinter m) => m a)
24+
25+runSomeBitPrinter :: (BitPrinter m) => SomeBitPrinter a -> m a
26+runSomeBitPrinter (SomeBitPrinter act) = act
2027
21−parseBit# :: BitParser Int
22−parseBit# = do
23− (counter, m) <- get
24− b <- lift getBool#
25− put (counter + 1, m)
26− pure b
28+class (MonadState (Natural, Map Noun Natural) m) => BitPrinter m where
29+ putBit# :: (BitPrinter m) => Word# -> m ()
30+ putBool :: Bool -> m ()
2731
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)
32+instance BitPrinter (StateT (Natural, Map Noun Natural) Identity) where
33+ putBit# _ = do
34+ (counter, m) <- get
35+ put (counter + 1, m)
36+ putBool _ = do
37+ (counter, m) <- get
38+ put (counter + 1, m)
3439
35−getOffset :: BitParser Int
40+instance BitPrinter BitPrinterM where
41+ putBit# w = do
42+ (counter, m) <- get
43+ lift $ Put.putBool# w
44+ put (counter + 1, m)
45+ putBool b = do
46+ (counter, m) <- get
47+ lift $ Put.putBool b
48+ put (counter + 1, m)
49+
50+getOffset :: (BitPrinter m) => m Natural
3651getOffset = fst <$> get
3752
38−getMapping :: BitParser (Map Int Noun)
53+getMapping :: (BitPrinter m) => m (Map Noun Natural)
3954getMapping = snd <$> get
4055
41−putMapping :: Map Int Noun -> BitParser ()
56+putMapping :: (BitPrinter m) => Map Noun Natural -> m ()
4257putMapping m = do
4358 (offset, _) <- get
4459 put (offset, m)
4560
46−cue :: ByteString -> Noun
47−cue = runGet (runBitGet . withBitOrder LL . flip evalStateT (0, M.empty) $ cue')
48−
49−cue' :: BitParser Noun
50−cue' = do
51− offset <- getOffset
52− I# isNotAtom <- parseBit#
53− case isNotAtom of
54− 0# -> do
55− a' <- rub'
56− let a = atom a'
57− m <- getMapping
58− putMapping $ M.insert offset a m
59− pure a
60− _ -> do
61− I# isRef <- parseBit#
62− case isRef of
63− 0# -> do
64− x <- cue'
65− y <- cue'
66− let c = cell x y
67− m <- getMapping
68− putMapping $ M.insert offset c m
69− pure c
70− _ -> do
71− ref <- rub'
72− let ref# = case ref of
73− NS w -> I# (word2Int# w)
74− _ -> undefined
75− m <- getMapping
76− case M.lookup ref# m of
77− Nothing -> undefined
78− Just a -> pure a
79−
8061jam :: Noun -> ByteString
81−jam n = runPut . runBitPut . withBitOrder LL $ jam' n
62+jam n = runPut . Put.runBitPut . withBitOrder LL . flip evalStateT (0, M.empty) $ jam' n
8263
83−jam' :: Noun -> BitPut ()
64+jam' :: (BitPrinter m) => Noun -> m ()
8465jam' (Atom n _) = do
85− putBool# 0##
66+ putBit# 0##
8667 mat' n
87−jam' (Cell lhs rhs _) = do
88− putBool# 1##
89− putBool# 0##
90− jam' lhs
91− jam' rhs
68+jam' n@(Cell lhs rhs _) = do
69+ offset <- getOffset
70+ putBit# 1##
71+ let inlineAct = SomeBitPrinter $ do
72+ putBit# 0##
73+ jam' lhs
74+ jam' rhs
75+ mapping <- getMapping
76+ case M.lookup n mapping of
77+ Nothing -> do
78+ runSomeBitPrinter inlineAct
79+ putMapping $ M.insert n offset mapping
80+ Just ref -> do
81+ s <- get
82+ let refAct = SomeBitPrinter $ do
83+ putBit# 1##
84+ mat' ref
85+ (inlineLength, _) = runIdentity . flip execStateT s . runSomeBitPrinter $ inlineAct
86+ (refLength, _) = runIdentity . flip execStateT s . runSomeBitPrinter $ refAct
87+ if inlineLength < refLength then runSomeBitPrinter inlineAct else runSomeBitPrinter refAct
9288
9389mat :: Natural -> ByteString
94−mat n = runPut . runBitPut . withBitOrder LL $ mat' n
90+mat n = runPut . Put.runBitPut . withBitOrder LL . flip evalStateT (0, M.empty) $ mat' n
9591
96−mat' :: Natural -> BitPut ()
97−mat' 0 = putBool# 1##
92+mat' :: (BitPrinter m) => Natural -> m ()
93+mat' 0 = putBit# 1##
9894mat' n = do
9995 let bitsLength = countBits# n
10096 lengthBits = init $ numToBits (W# bitsLength)
101− putBool# 0##
97+ putBit# 0##
10298 putBits $ replicate (length lengthBits) False
103− putBool# 1##
99+ putBit# 1##
104100 putBits lengthBits
105101 putNumToBits# n
106102
107−putBits :: [Bool] -> BitPut ()
103+putBits :: (BitPrinter m) => [Bool] -> m ()
108104putBits [] = pure ()
109105putBits (x : xs) = putBool x >> putBits xs
110106
111−rub :: ByteString -> Natural
112−rub = runGet (runBitGet . withBitOrder LL . flip evalStateT (0, M.empty) $ rub')
113−
114−rub' :: BitParser Natural
115−rub' = do
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
128−countZeros n = do
129− I# b <- parseBit#
130− case b of
131− 0# -> countZeros (n + 1)
132− _ -> pure n
133−
134107numToBits :: (Bits a, Integral a) => a -> [Bool]
135108numToBits n | n <= 0 = []
136109numToBits n = ((n .&. 1) == 1) : numToBits (shiftR n 1)
@@ -139,13 +112,8 @@ countBits# :: Natural -> Word#
139112countBits# (NS 0##) = 0##
140113countBits# n = 1## `plusWord#` countBits# (n `naturalShiftR#` 1##)
141114
142−putNumToBits# :: Natural -> BitPut ()
115+putNumToBits# :: (BitPrinter m) => Natural -> m ()
143116putNumToBits# (NS 0##) = pure ()
144117putNumToBits# n = case n .&. 1 of
145− NS w -> putBool# w >> putNumToBits# (n `naturalShiftR#` 1##)
118+ NS w -> putBit# w >> putNumToBits# (n `naturalShiftR#` 1##)
146119 _ -> undefined
147−
148−-- ((n .&. 1) == 1) : numToBits (shiftR n 1)
149−
150−bitsToNum :: (Bits a, Integral a) => [Bool] -> a
151−bitsToNum = foldr (\b acc -> shiftL acc 1 .|. if b then 1 else 0) 0
src/Nock/Jets.hs+2−1
@@ -5,7 +5,8 @@ module Nock.Jets (add, dec, decJam, decNoun) where
55import Data.ByteString (ByteString)
66import Data.ByteString.Lazy qualified as BSL
77import Data.FileEmbed (embedFileRelative)
8−import Nock.Jam (cue)
8+import Nock.Jam
9+import Nock.Cue
910import Nock.Parser qualified
1011import Nock.Types
1112
src/Nock/Types.hs+6−1
@@ -13,7 +13,6 @@ module Nock.Types
1313 )
1414where
1515
16−import Control.Applicative
1716import Control.DeepSeq
1817import Data.ByteString (ByteString)
1918import Data.ByteString.Short
@@ -90,6 +89,12 @@ instance Eq Noun where
9089 (Atom a _) == (Atom b _) = a == b
9190 _ == _ = False
9291
92+instance Ord Noun where
93+ Atom {} <= Cell {} = True
94+ Cell {} <= Atom {} = False
95+ Atom n _ <= Atom m _ = n <= m
96+ Cell a b _ <= Cell c d _ = (a, b) <= (c, d)
97+
9398instance Arbitrary Noun where
9499 arbitrary =
95100 oneof
stack.yaml+1−1
@@ -23,7 +23,7 @@ nix:
2323#
2424# resolver: ./custom-snapshot.yaml
2525# resolver: https://example.com/snapshots/2018-01-01.yaml
26−resolver: lts-22.43
26+resolver: lts-23.21
2727
2828# User packages to be built.
2929# Various formats can be used as shown in the example below.
stack.yaml.lock+4−4
@@ -17,7 +17,7 @@ packages:
1717 git: https://github.com/ilyakooo0/binary-bits
1818snapshots:
1919- completed:
20− sha256: 08bd13ce621b41a8f5e51456b38d5b46d7783ce114a50ab604d6bbab0d002146
21− size: 720271
22− url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/43.yaml
23− original: lts-22.43
20+ sha256: f4a61482dcad21151331bf84ec85bee9be43965f143791fa4bb202ac1e443e1b
21+ size: 683833
22+ url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/23/21.yaml
23+ original: lts-23.21
tests/Main.hs+3−2
@@ -7,16 +7,16 @@ import Data.Text.Lazy.Encoding as TL
77import Effectful
88import Effectful.State.Static.Local qualified as SEL
99import Nock
10+import Nock.Cue
1011import Nock.Jam
1112import Nock.Jets
1213import Nock.Parser qualified
13−import Nock.Printer
1414import Nock.Types
1515import System.FilePath.Posix
1616import System.Process.Typed
1717import Test.Tasty
1818import Test.Tasty.Golden
19−import Test.Tasty.HUnit (assertEqual, testCase, (@=?), (@?=))
19+import Test.Tasty.HUnit (testCase, (@?=))
2020import Test.Tasty.QuickCheck
2121
2222main :: IO ()
@@ -27,6 +27,7 @@ main = do
2727 "nock"
2828 [ spec,
2929 testProperty "cue . jam == id" (\noun -> noun === (cue . jam) noun),
30+ testProperty "jam . cue . jam == jam" (\noun -> jam noun === (jam . cue . jam) noun),
3031 testCase "" (decJam @?= BSL.toStrict ((jam . cue) (BSL.fromStrict decJam)))
3132 ]
3233