on master help sign in
24 files changed+890−338
since splitsnapshots
unifiedsplit
bench/Main.hs+27 exe/Main.hs+1 flake.lock+59 flake.nix+24 package.yaml+24 res/dec.jam+11 src/Data/HashMap/Monadic.hs+155 src/Nock.hs+111−91 src/Nock/Cue.hs+98 src/Nock/Jam.hs+103−99 src/Nock/Jets.hs+23 src/Nock/Mug.hs+34 src/Nock/Parser.hs+6−6 src/Nock/Printer.hs+1−9 src/Nock/Types.hs+114 stack.yaml+3−3 stack.yaml.lock+8−9 tests/Main.hs+30−96 tests/golden/add.hoon+9−13 tests/golden/add.nock+1−1 tests/golden/dec.hoon+9−10 tests/golden/dec.nock+1−1 tests/golden/mul.hoon+37 tests/golden/mul.nock+1
bench/Main.hsnew file+27
@@ -0,0 +1,27 @@
1+module Main (main) where
2+
3+import Control.Monad
4+import Data.ByteString.Lazy qualified as BSL
5+import Data.Function
6+import Data.Text.Lazy.Encoding as TL
7+import Gauge
8+import Nock
9+import Nock.Parser (noun)
10+import System.FilePath.Posix
11+import System.Process.Typed
12+import Test.Tasty.Golden (findByExtension)
13+import Effectful
14+
15+main :: IO ()
16+main = do
17+ files <- findByExtension [".hoon"] "tests/golden"
18+ benchmarks <- forM files $ \hoonFile -> do
19+ hoon <- BSL.readFile hoonFile
20+ nock <-
21+ fmap (Nock.Parser.noun . TL.decodeUtf8 . BSL.dropEnd 6 . BSL.drop 11 . snd)
22+ . readProcessStdout
23+ $ proc "urbit" ["eval"]
24+ & setStdin (byteStringInput hoon)
25+ & setStderr nullStream
26+ pure $ bench (takeBaseName hoonFile) $ nf (runPureEff . tar) $ cell (atom 0) nock
27+ defaultMain benchmarks
exe/Main.hs+1
@@ -1,4 +1,5 @@
11module Main (main) where
22
3+main :: IO ()
34main = pure ()
45
flake.locknew file+59
@@ -0,0 +1,59 @@
1+{
2+ "nodes": {
3+ "flake-utils": {
4+ "inputs": {
5+ "systems": "systems"
6+ },
7+ "locked": {
8+ "lastModified": 1731533236,
9+ "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
10+ "owner": "numtide",
11+ "repo": "flake-utils",
12+ "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
13+ "type": "github"
14+ },
15+ "original": {
16+ "id": "flake-utils",
17+ "type": "indirect"
18+ }
19+ },
20+ "nixpkgs": {
21+ "locked": {
22+ "lastModified": 1746141548,
23+ "narHash": "sha256-IgBWhX7A2oJmZFIrpRuMnw5RAufVnfvOgHWgIdds+hc=",
24+ "owner": "NixOS",
25+ "repo": "nixpkgs",
26+ "rev": "f02fddb8acef29a8b32f10a335d44828d7825b78",
27+ "type": "github"
28+ },
29+ "original": {
30+ "id": "nixpkgs",
31+ "ref": "nixos-unstable",
32+ "type": "indirect"
33+ }
34+ },
35+ "root": {
36+ "inputs": {
37+ "flake-utils": "flake-utils",
38+ "nixpkgs": "nixpkgs"
39+ }
40+ },
41+ "systems": {
42+ "locked": {
43+ "lastModified": 1681028828,
44+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
45+ "owner": "nix-systems",
46+ "repo": "default",
47+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
48+ "type": "github"
49+ },
50+ "original": {
51+ "owner": "nix-systems",
52+ "repo": "default",
53+ "type": "github"
54+ }
55+ }
56+ },
57+ "root": "root",
58+ "version": 7
59+}
flake.nixnew file+24
@@ -0,0 +1,24 @@
1+{
2+ inputs = {
3+ nixpkgs.url = "nixpkgs/nixos-unstable";
4+ flake-utils.url = "flake-utils";
5+ };
6+
7+ outputs = { self, flake-utils, nixpkgs }:
8+ let
9+ supportedSystems =
10+ [ "x86_64-linux" "x86_64-darwin" "aarch64-darwin" "aarch64-linux" ];
11+ compilerVersion = "984";
12+ in flake-utils.lib.eachSystem supportedSystems (system:
13+ let pkgs = import nixpkgs { inherit system; };
14+ in {
15+ devShells.default = pkgs.mkShell {
16+ buildInputs = with pkgs; [
17+ haskell.compiler."ghc${compilerVersion}"
18+ (pkgs.haskell-language-server.override {
19+ supportedGhcVersions = [ compilerVersion ];
20+ })
21+ ];
22+ };
23+ });
24+}
package.yaml+24
@@ -15,6 +15,14 @@ dependencies:
1515 - generic-arbitrary
1616 - tasty-golden
1717 - typed-process
18+ - gauge
19+ - filepath
20+ - deepseq
21+ - effectful
22+ - unordered-containers
23+ - murmur3
24+ - file-embed
25+ - mtl
1826library:
1927 source-dirs: src
2028
@@ -23,9 +31,18 @@ executables:
2331 main: Main.hs
2432 source-dirs: exe
2533
34+benchmarks:
35+ nock-bench:
36+ main: bench/Main.hs
37+
38+ dependencies:
39+ - effectful
40+ - tasty
41+ - nock
2642ghc-options: >
2743 -Weverything
2844 -Wno-unsafe
45+ -Wno-implicit-prelude
2946 -Wno-missing-safe-haskell-mode
3047 -Wno-missing-import-lists
3148 -Wno-missing-kind-signatures
@@ -33,6 +50,8 @@ ghc-options: >
3350 -Wno-missed-specialisations
3451 -Wno-partial-type-signatures
3552 -threaded
53+ -with-rtsopts=-N
54+ -O2
3655
3756language: GHC2021
3857
@@ -60,6 +79,8 @@ default-extensions:
6079- NoFieldSelectors
6180- AllowAmbiguousTypes
6281- ImpredicativeTypes
82+- MagicHash
83+- UnboxedTuples
6384
6485tests:
6586 spec:
@@ -71,3 +92,6 @@ tests:
7192 - nock
7293 - tasty-hspec
7394 - hspec
95+ - effectful
96+ - tasty-quickcheck
97+ - 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/Data/HashMap/Monadic.hsnew file+155
@@ -0,0 +1,155 @@
1+module Data.HashMap.Monadic (MEq (..), insert, lookup) where
2+
3+import Control.Monad.ST (runST)
4+import Data.Bits
5+import Data.Functor ((<&>))
6+import Data.HashMap.Internal
7+ ( Hash,
8+ HashMap (..),
9+ Leaf (..),
10+ bitmapIndexedOrFull,
11+ collision,
12+ hash,
13+ index,
14+ mask,
15+ nextShift,
16+ ptrEq,
17+ sparseIndex,
18+ two,
19+ update32,
20+ )
21+import Data.HashMap.Internal.Array qualified as A
22+import Data.Hashable
23+import Prelude hiding (lookup)
24+
25+class MEq x m where
26+ (===) :: x -> x -> m Bool
27+
28+insert :: (MEq k m, Hashable k, Monad m) => k -> v -> HashMap k v -> m (HashMap k v)
29+insert k v m = insert' (Data.HashMap.Internal.hash k) k v m
30+
31+insert' :: forall m k v. (MEq k m, Monad m) => Hash -> k -> v -> HashMap k v -> m (HashMap k v)
32+insert' h0 k0 v0 m0 = go h0 k0 v0 0 m0
33+ where
34+ -- go :: _ -> _ -> _ -> _ -> _ -> m _
35+ go !h !k x !_ Empty = pure @m $ Leaf h (L k x)
36+ go h k x s t@(Leaf hy l@(L ky y))
37+ | hy == h = do
38+ ky === k >>= \eq ->
39+ if eq
40+ then
41+ if x `ptrEq` y
42+ then pure @m t
43+ else pure @m $ Leaf h (L k x)
44+ else pure $ collision h l (L k x)
45+ | otherwise = pure $ runST (two s h k x hy t)
46+ go h k x s t@(BitmapIndexed b ary)
47+ | b .&. m == 0 =
48+ let !ary' = A.insert ary i $! Leaf h (L k x)
49+ in pure $ bitmapIndexedOrFull (b .|. m) ary'
50+ | otherwise = do
51+ let !st = A.index ary i
52+ !st' <- go h k x (nextShift s) st
53+ if st' `ptrEq` st
54+ then pure t
55+ else pure $ BitmapIndexed b (A.update ary i st')
56+ where
57+ m = mask h s
58+ i = sparseIndex b m
59+ go h k x s t@(Full ary) = do
60+ let !st = A.index ary i
61+ !st' <- go h k x (nextShift s) st
62+ if st' `ptrEq` st
63+ then pure t
64+ else pure $ Full (update32 ary i st')
65+ where
66+ i = index h s
67+ go h k x s t@(Collision hy v)
68+ | h == hy = Collision h <$> (updateOrSnocWith (\a _ -> (# a #)) k x v)
69+ | otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)
70+
71+updateOrSnocWith ::
72+ (MEq k m, Monad m) =>
73+ (v -> v -> (# v #)) ->
74+ k ->
75+ v ->
76+ A.Array (Leaf k v) ->
77+ m (A.Array (Leaf k v))
78+updateOrSnocWith f = updateOrSnocWithKey (const f)
79+{-# INLINEABLE updateOrSnocWith #-}
80+
81+updateOrSnocWithKey ::
82+ (MEq k m, Monad m) =>
83+ (k -> v -> v -> (# v #)) ->
84+ k ->
85+ v ->
86+ A.Array (Leaf k v) ->
87+ m (A.Array (Leaf k v))
88+updateOrSnocWithKey f k0 v0 ary0 = go k0 v0 ary0 0 (A.length ary0)
89+ where
90+ go !k v !ary !i !n
91+ -- Not found, append to the end.
92+ | i >= n = pure $ A.snoc ary $ L k v
93+ | otherwise =
94+ let L kx y = A.index ary i
95+ (# v2 #) = f k v y
96+ in k === kx >>= \eq ->
97+ if eq
98+ then pure $ A.update ary i (L k v2)
99+ else go k v ary (i + 1) n
100+
101+lookup :: (MEq k m, Hashable k, Monad m) => k -> HashMap k v -> m (Maybe v)
102+lookup k m = lookupCont Nothing (\v _i -> Just v) (Data.HashMap.Internal.hash k) k 0 m
103+
104+lookupCont ::
105+ forall m r k v.
106+ (MEq k m, Monad m) =>
107+ r -> -- Absent continuation
108+ (v -> Int -> r) -> -- Present continuation
109+ Hash -> -- The hash of the key
110+ k ->
111+ Int -> -- The offset of the subkey in the hash.
112+ HashMap k v ->
113+ m r
114+lookupCont absent present !h0 !k0 !s0 !m0 = go h0 k0 s0 m0
115+ where
116+ go :: Hash -> k -> Int -> HashMap k v -> m r
117+ go !_ !_ !_ Empty = pure absent
118+ go h k _ (Leaf hx (L kx x))
119+ | h == hx =
120+ k === kx <&> \eq ->
121+ if eq
122+ then present x (-1)
123+ else absent
124+ | otherwise = pure absent
125+ go h k s (BitmapIndexed b v)
126+ | b .&. m == 0 = pure absent
127+ | otherwise =
128+ go h k (nextShift s) (A.index v (sparseIndex b m))
129+ where
130+ m = mask h s
131+ go h k s (Full v) =
132+ go h k (nextShift s) (A.index v (index h s))
133+ go h k _ (Collision hx v)
134+ | h == hx = lookupInArrayCont absent present k v
135+ | otherwise = pure absent
136+
137+lookupInArrayCont ::
138+ forall m r k v.
139+ (MEq k m, Monad m) =>
140+ r ->
141+ (v -> Int -> r) ->
142+ k ->
143+ A.Array (Leaf k v) ->
144+ m r
145+lookupInArrayCont absent present k0 ary0 = go k0 ary0 0 (A.length ary0)
146+ where
147+ go :: k -> A.Array (Leaf k v) -> Int -> Int -> m r
148+ go !k !ary !i !n
149+ | i >= n = pure absent
150+ | otherwise = case A.index ary i of
151+ (L kx v) ->
152+ k === kx >>= \eq ->
153+ if eq
154+ then pure $ present v i
155+ else go k ary (i + 1) n
src/Nock.hs+111−91
@@ -1,30 +1,15 @@
11{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
22
3−module Nock (tar, hax, fas, cell, atom, Annotation (..), Noun, RawNoun (..)) where
4−
5−import Data.Hashable
6−import Debug.Trace (trace, traceShowId)
7−import GHC.Generics (Generic)
8−import GHC.Stack
9−import Numeric.Natural
10−import Test.QuickCheck.Arbitrary.Generic
11−
12−data Annotation = Annotation
13− { hash :: Int
14− }
15− deriving stock (Show)
16−
17−atom :: Natural -> Noun
18−atom nat = Atom nat Annotation {hash = hash nat}
19−
20−cell :: Noun -> Noun -> Noun
21−cell lhs rhs =
22− Cell
23− lhs
24− rhs
25− Annotation
26− { hash = hash ((annotation lhs).hash, (annotation rhs).hash)
27− }
3+module Nock (tar, hax, fas, cell, atom, Annotation (..), Noun) where
4+
5+import Data.Bits
6+import Data.Functor ((<&>))
7+import Effectful
8+import Effectful.State.Static.Local qualified as SEL
9+import GHC.Base
10+import GHC.Num
11+import GHC.Num.BigNat (bigNatAddWord#, bigNatFromWord2#)
12+import Nock.Types
2813
2914sig :: Noun
3015sig = atom 0
@@ -32,84 +17,119 @@ sig = atom 0
3217one :: Noun
3318one = atom 1
3419
35−annotation :: RawNoun ann -> ann
36−annotation (Atom _ ann) = ann
37−annotation (Cell _ _ ann) = ann
20+two :: Noun
21+two = atom 2
3822
39−data RawNoun ann
40− = Atom !Natural ann
41− | Cell (RawNoun ann) (RawNoun ann) ann
42− deriving stock (Generic, Show)
23+three :: Noun
24+three = atom 3
4325
44−instance Eq (RawNoun ann) where
45− (Atom lhs _) == (Atom rhs _) = lhs == rhs
46− (Cell lhslhs lhsrhs _) == (Cell rhslhs rhsrhs _) = lhslhs == rhslhs && lhsrhs == rhsrhs
47− _ == _ = False
26+four :: Noun
27+four = atom 4
4828
49−hashEq :: Noun -> Noun -> Bool
50−hashEq (Atom lhsNat lhsAnn) (Atom rhsNat rhsAnn) =
51− lhsAnn.hash == rhsAnn.hash && lhsNat == rhsNat
52−hashEq (Cell lhslhs lhsrhs lhsAnn) (Cell rhslhs rhsrhs rhsAnn) =
53− lhsAnn.hash == rhsAnn.hash && hashEq lhslhs rhslhs && hashEq lhsrhs rhsrhs
54−hashEq _ _ = False
29+twoThree :: Noun
30+twoThree = cell two three
5531
56−type Noun = RawNoun Annotation
32+sigOne :: Noun
33+sigOne = cell sig one
5734
5835wut :: Noun -> Noun
5936wut Cell {} = sig
6037wut Atom {} = one
6138
6239lus :: Noun -> Noun
63−lus ~(Atom nat _) = atom (nat + 1)
40+lus ~(Atom nat _) = atom $ case nat of
41+ (NS n) -> case addWordC# n 1## of
42+ (# l, 0# #) -> NS l
43+ (# l, c #) -> NB (bigNatFromWord2# (int2Word# c) l)
44+ (NB n) -> NB (bigNatAddWord# n 1##)
6445
65−tis :: Noun -> Noun
66−tis ~(Cell lhs rhs _) = if hashEq lhs rhs then sig else one
46+tis :: Noun -> Noun -> Eff es Noun
47+tis lhs rhs = pure $ if lhs == rhs then sig else one
6748
68−fas :: Noun -> Noun
69−fas ~(Cell ~(Atom lhs _) rhs _) =
49+fas# :: Word# -> Noun -> Noun
50+fas# lhs rhs =
7051 case lhs of
71− 1 -> rhs
72− 2 -> case rhs of
73− (Cell lhs' _ _) -> lhs'
74− _ -> undefined
75− 3 -> case rhs of
52+ 1## -> rhs
53+ 2## -> case rhs of
54+ ~(Cell lhs' _ _) -> lhs'
55+ 3## -> case rhs of
7656 ~(Cell _ rhs' _) -> rhs'
77− n
78− | n > 0 ->
79− let (d, m) = divMod n 2
80− in if m == 0
81− then fas (cell (atom 2) (fas (cell (atom d) rhs)))
82− else fas (cell (atom 3) (fas (cell (atom d) rhs)))
83− _ -> undefined
84−
85−hax :: Noun -> Noun
86−hax ~(Cell ~(Atom n _) ~(Cell b c _) _) =
87− let (a, m) = divMod n 2
88− in case n of
89− 1 -> b
90− _ | m == 0 -> hax (cell (atom a) (cell (cell b (fas (cell (atom $ a + a + 1) c))) c))
91− _ -> hax (cell (atom a) (cell (cell (fas (cell (atom $ a + a) c)) b) c))
92−
93−tar :: Noun -> Noun
94−tar ~(Cell a ~(Cell b c _) _) = case b of
95− Cell x y _ -> cell (tar (cell a (cell x y))) (tar (cell a c))
96− Atom n _ -> case n of
97− 0 -> fas $ cell c a
98− 1 -> c
99− 3 -> wut $ tar $ cell a c
100− 4 -> lus $ tar $ cell a c
57+ n ->
58+ let rest = fas# (uncheckedShiftRL# n 1#) rhs
59+ in case and# 1## n of
60+ 1## -> fas# 3## rest
61+ _ -> fas# 2## rest
62+
63+fas :: Natural -> Noun -> Noun
64+fas (NS w) rhs = fas# w rhs
65+fas n rhs =
66+ let rest = fas (unsafeShiftR n 1) rhs
67+ in if testBit n 0
68+ then fas 3 rest
69+ else fas 2 rest
70+
71+hax# :: Word# -> Noun -> Noun -> Noun
72+hax# 1## b _ = b
73+hax# n b c =
74+ let a = uncheckedShiftRL# n 1#
75+ in case and# n 1## of
76+ 1## -> hax# a (cell (fas# (n `xor#` 1##) c) b) c
77+ _ -> hax# a (cell b (fas# (n `or#` 1##) c)) c
78+
79+hax :: Natural -> Noun -> Noun -> Noun
80+hax (NS n) b c = hax# n b c
81+hax n b c =
82+ let a = unsafeShiftR n 1
83+ in if testBit n 0
84+ then hax a (cell (fas (n - 1) c) b) c
85+ else hax a (cell b (fas (n + 1) c)) c
86+
87+tar :: Noun -> Eff es Noun
88+tar ~(Cell subject ~(Cell a b _) _) = tar' a b subject
89+
90+tar' :: Noun -> Noun -> Noun -> Eff es Noun
91+tar' b c subject = case b of
92+ Cell x y _ -> case c of
93+ ~(Cell l k _) -> cell <$> tar' x y subject <*> tar' l k subject
94+ Atom (NB _) _ -> undefined
95+ Atom (NS n) _ -> case n of
96+ 0## -> case c of
97+ ~(Atom nat _) -> pure $ fas nat subject
98+ 1## -> pure c
99+ 3## -> case c of
100+ ~(Cell l k _) -> wut <$> tar' l k subject
101+ 4## -> case c of
102+ ~(Cell l k _) -> lus <$> tar' l k subject
101103 _ -> case c of
102− ~(Cell x y _) -> case n of
103− 2 -> tar $ cell (tar $ cell a x) (tar $ cell a y)
104− 5 -> tis $ cell (tar $ cell a x) (tar $ cell a y)
105− 7 -> tar $ cell (tar $ cell a x) y
106− 8 -> tar $ cell (cell (tar $ cell a x) a) y
107− 9 -> tar $ cell (tar $ cell a y) $ cell (atom 2) (cell (cell sig one) (cell sig x))
108− 6 -> case y of
109− ~(Cell c' d' _) -> tar $ cell a $ tar $ cell (cell c' d') $ cell sig $ tar $ cell (cell (atom 2) (atom 3)) $ cell sig $ tar $ cell a (cell (atom 4) (cell (atom 4) x))
110− 10 -> case x of
111− ~(Cell b' c' _) -> hax $ cell b' $ cell (tar (cell a c')) $ tar $ cell a y
112− 11 -> case x of
113− Cell _ c' _ -> tar $ cell (cell (tar $ cell a c') (tar $ cell a y)) $ cell sig (atom 3)
114− Atom _ _ -> tar $ cell a y
115− u -> error $ show u
104+ ~(Cell x ~(Cell h j _) _) -> case n of
105+ 2## -> case x of
106+ ~(Cell l k _) ->
107+ tar' l k subject >>= \case
108+ ~formula@(Cell battery ~(Cell sample _ _) _) ->
109+ -- if traceShowId battery == Nock.Jets.add
110+ -- then error "Found it!"
111+ tar' h j subject >>= \case
112+ ~(Cell u v _) -> tar' u v formula
113+ 5## -> case x of
114+ ~(Cell l k _) -> do
115+ p <- tar' h j subject
116+ q <- tar' l k subject
117+ tis p q
118+ 7## -> case x of
119+ ~(Cell l k _) -> tar' l k subject >>= tar' h j
120+ 8## -> case x of
121+ ~(Cell l k _) -> do
122+ p <- tar' l k subject
123+ tar' h j (cell p subject)
124+ 9## -> tar' h j subject >>= tar' two (cell sigOne (cell sig x))
125+ 6## -> do
126+ p <- tar' four (cell four x) subject
127+ q <- tar' sig p twoThree
128+ tar' sig q (cell h j) >>= \case
129+ ~(Cell u v _) -> tar' u v subject
130+ 10## -> case x of
131+ ~(Cell ~(Atom b' _) ~(Cell u v _) _) -> hax b' <$> tar' u v subject <*> tar' h j subject
132+ 11## -> case x of
133+ Cell _ ~(Cell u v _) _ -> tar' h j subject
134+ Atom _ _ -> tar' h j subject
135+ _ -> undefined
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+103−99
@@ -1,124 +1,128 @@
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 Data.Word
15−import Nock
16−import Numeric.Natural
17−
18−type BitParser = StateT (Int, Map Int Noun) BitGet
19−
20−parseBit :: BitParser Bool
21−parseBit = do
22− (counter, m) <- get
23− b <- lift getBool
24− put (counter + 1, m)
25− pure b
26−
27−parseBits :: Int -> BitParser [Bool]
28−parseBits 0 = pure []
29−parseBits n = do
30− b <- parseBit
31− (b :) <$> parseBits (n - 1)
32−
33−getOffset :: BitParser Int
14+import Data.Map.Strict (Map)
15+import Data.Map.Strict qualified as M
16+import GHC.Base (Word (..), Word#, int2Word#, isTrue#, leWord#, plusWord#, timesWord#)
17+import GHC.Int (Int (..))
18+import GHC.Num
19+import Nock.Types
20+
21+type BitPrinterM = StateT (Natural, Map Noun Natural) Put.BitPut
22+
23+class (MonadState (Natural, Map Noun Natural) m) => BitPrinter m where
24+ putBit# :: (BitPrinter m) => Word# -> m ()
25+ putBool :: Bool -> m ()
26+
27+instance BitPrinter (StateT (Natural, Map Noun Natural) Identity) where
28+ putBit# _ = do
29+ (counter, m) <- get
30+ put (counter + 1, m)
31+ putBool _ = do
32+ (counter, m) <- get
33+ put (counter + 1, m)
34+
35+instance BitPrinter BitPrinterM where
36+ putBit# w = do
37+ (counter, m) <- get
38+ lift $ Put.putBool# w
39+ put (counter + 1, m)
40+ putBool b = do
41+ (counter, m) <- get
42+ lift $ Put.putBool b
43+ put (counter + 1, m)
44+
45+getOffset :: (BitPrinter m) => m Natural
3446getOffset = fst <$> get
3547
36−cue :: ByteString -> Noun
37−cue = runGet (runBitGet . withBitOrder LL . flip evalStateT (0, M.empty) $ cue')
48+getMapping :: (BitPrinter m) => m (Map Noun Natural)
49+getMapping = snd <$> get
3850
39−cue' :: BitParser Noun
40−cue' = do
41− offset <- getOffset
42− isNotAtom <- parseBit
43− case isNotAtom of
44− False -> do
45− a' <- rub'
46− let a = atom a'
47− (offset, m) <- get
48− put (offset, M.insert offset a m)
49− pure a
50− True -> do
51− isNotRef <- parseBit
52− case isNotRef of
53− False -> do
54− x <- cue'
55− y <- cue'
56− let c = cell x y
57− (offset, m) <- get
58− put (offset, M.insert offset c m)
59− pure c
60− True -> do
61− ref <- rub'
62− (_, m) <- get
63− case M.lookup (fromIntegral ref) m of
64− Nothing -> undefined
65− Just a -> pure a
51+putMapping :: (BitPrinter m) => Noun -> Natural -> m ()
52+putMapping idx n = do
53+ (offset, m) <- get
54+ put (offset, M.insert idx n m)
6655
6756jam :: Noun -> ByteString
68−jam n = runPut . runBitPut . withBitOrder LL $ jam' n
69−
70−jam' :: Noun -> BitPut ()
71−jam' (Atom n _) = do
72− putBool False
73− mat' n
74−jam' (Cell lhs rhs _) = do
75− putBool True
76− putBool False
77− jam' lhs
78− jam' rhs
57+jam n = runPut . Put.runBitPut . withBitOrder LL . flip evalStateT (0, M.empty) $ jam' n
58+
59+jam' :: (BitPrinter m) => Noun -> m ()
60+jam' n = do
61+ offset <- getOffset
62+ mapping <- getMapping
63+ case M.lookup n mapping of
64+ Nothing -> do
65+ putMapping n offset
66+ case n of
67+ (Atom a _) -> do
68+ putBit# 0##
69+ mat' a
70+ (Cell lhs rhs _) -> do
71+ putBit# 1##
72+ putBit# 0##
73+ jam' lhs
74+ jam' rhs
75+ Just ref -> do
76+ case n of
77+ Cell {} -> do
78+ putBit# 1##
79+ putBit# 1##
80+ mat' ref
81+ (Atom a _) -> do
82+ if isTrue# (matSize a `leWord#` matSize ref)
83+ then do
84+ putBit# 0##
85+ mat' a
86+ else do
87+ putBit# 1##
88+ putBit# 1##
89+ mat' ref
7990
8091mat :: Natural -> ByteString
81−mat n = runPut . runBitPut . withBitOrder LL $ mat' n
92+mat n = runPut . Put.runBitPut . withBitOrder LL . flip evalStateT (0, M.empty) $ mat' n
8293
83−mat' :: Natural -> BitPut ()
84−mat' 0 = putBool True
94+mat' :: (BitPrinter m) => Natural -> m ()
95+mat' 0 = putBit# 1##
8596mat' n = do
86− let bits = numToBits n
87− bitsLength = length bits
88− lengthBits = init $ numToBits bitsLength
89− putBool False
97+ let bitsLength = countBits# n
98+ lengthBits = init $ numToBits (W# bitsLength)
99+ putBit# 0##
90100 putBits $ replicate (length lengthBits) False
91− putBool True
101+ putBit# 1##
92102 putBits lengthBits
93− putBits bits
103+ putNumToBits# n
94104
95−putBits :: [Bool] -> BitPut ()
105+matSize :: Natural -> Word#
106+matSize 0 = 1##
107+matSize n =
108+ let bitsLength = countBits# n
109+ !(I# lengthBits) = length $ init $ numToBits (W# bitsLength)
110+ in 2## `plusWord#` (int2Word# lengthBits `timesWord#` 2##) `plusWord#` bitsLength
111+
112+putBits :: (BitPrinter m) => [Bool] -> m ()
96113putBits [] = pure ()
97114putBits (x : xs) = putBool x >> putBits xs
98115
99−rub :: ByteString -> Natural
100−rub = runGet (runBitGet . withBitOrder LL . flip evalStateT (0, M.empty) $ rub')
101−
102−rub' :: BitParser Natural
103−rub' = 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
113−countZeros n = do
114− b <- parseBit
115− case b of
116− True -> pure n
117− False -> countZeros (n + 1)
118−
119116numToBits :: (Bits a, Integral a) => a -> [Bool]
120117numToBits n | n <= 0 = []
121118numToBits n = ((n .&. 1) == 1) : numToBits (shiftR n 1)
122119
123−bitsToNum :: (Bits a, Integral a) => [Bool] -> a
124−bitsToNum = foldr (\b acc -> shiftL acc 1 .|. if b then 1 else 0) 0
120+countBits# :: Natural -> Word#
121+countBits# (NS 0##) = 0##
122+countBits# n = 1## `plusWord#` countBits# (n `naturalShiftR#` 1##)
123+
124+putNumToBits# :: (BitPrinter m) => Natural -> m ()
125+putNumToBits# (NS 0##) = pure ()
126+putNumToBits# n = case n .&. 1 of
127+ NS w -> putBit# w >> putNumToBits# (n `naturalShiftR#` 1##)
128+ _ -> undefined
src/Nock/Jets.hsnew file+23
@@ -0,0 +1,23 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
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.Cue
9+import Nock.Jam
10+import Nock.Parser qualified
11+import Nock.Types
12+
13+decJam :: ByteString
14+decJam = $(embedFileRelative "res/dec.jam")
15+
16+decNoun :: Noun
17+decNoun = cue $ BSL.fromStrict decJam
18+
19+dec :: Noun
20+dec = 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]"
21+
22+add :: Noun
23+add = Nock.Parser.noun "[ 6 [5 [1 0] 0 12] [0 13] 9 2 10 [6 [8 [9 21 0 7] 9 2 10 [6 0 28] 0 2] 4 0 13] 0 1 ]"
src/Nock/Mug.hsnew file+34
@@ -0,0 +1,34 @@
1+module Nock.Mug (Mug, mugBS, mugAtom, mugBoth) where
2+
3+import Data.Bits
4+import Data.ByteString (ByteString)
5+import Data.ByteString.Builder
6+import Data.ByteString.Lazy (toStrict)
7+import Data.Hash.Murmur (murmur3)
8+import Data.Word (Word32)
9+import Nock.Types
10+
11+type Mug = Word32
12+
13+mugBS :: ByteString -> Word32
14+mugBS = mum 0xcafe_babe 0x7fff
15+
16+mugAtom :: Atom -> Word32
17+mugAtom = mugBS . atomByteString
18+
19+mugBoth :: Word32 -> Word32 -> Word32
20+mugBoth m n =
21+ mum 0xdead_beef 0xfffe $
22+ toStrict $
23+ toLazyByteString (word32LE m <> word32LE n)
24+
25+mum :: Word32 -> Word32 -> ByteString -> Word32
26+mum syd fal key = go syd 0
27+ where
28+ go syd 8 = fal
29+ go syd i =
30+ let haz = murmur3 syd key
31+ ham = shiftR haz 31 `xor` (haz .&. 0x7fff_ffff)
32+ in if ham /= 0
33+ then ham
34+ else go (syd + 1) (i + 1)
src/Nock/Parser.hs+6−6
@@ -1,21 +1,21 @@
11{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
22
3−module Nock.Parser (decode) where
3+module Nock.Parser (noun) where
44
55import Control.Applicative
6−import Data.Text as T
6+import Data.Text.Lazy as TL
77import Data.Void (Void)
8−import Nock
8+import Nock.Types
99import Text.Megaparsec
1010import Text.Megaparsec.Char
1111import Text.Megaparsec.Char.Lexer (decimal)
1212
13−decode :: Text -> Noun
14−decode txt = case Text.Megaparsec.parse (space *> parser <* space) "" . T.filter (\c -> c /= '.') $ txt of
13+noun :: TL.Text -> Noun
14+noun txt = case Text.Megaparsec.parse (space *> parser <* space) "" . TL.filter (\c -> c /= '.') $ txt of
1515 Right non -> non
1616 Left err -> error $ errorBundlePretty err
1717
18−type Parser = Parsec Void Text
18+type Parser = Parsec Void TL.Text
1919
2020parser :: Parser Noun
2121parser = try atomParser <|> cellParser
src/Nock/Printer.hs+1−9
@@ -1,14 +1,6 @@
1−module Nock.Printer (pretty) where
1+module Nock.Printer () where
22
33import Data.Text.Lazy qualified as TL
44import Data.Text.Lazy.Builder qualified as TLB
55import Data.Text.Lazy.Builder.Int qualified as TLB
66import Nock
7−
8−pretty :: RawNoun ann -> TL.Text
9−pretty noun = TLB.toLazyText $ pretty' noun False
10−
11−pretty' :: RawNoun ann -> Bool -> TLB.Builder
12−pretty' (Atom a _) _ = TLB.decimal a
13−pretty' (Cell lhs rhs _) True = pretty' lhs False <> " " <> pretty' rhs True
14−pretty' (Cell lhs rhs _) False = "[" <> pretty' lhs False <> " " <> pretty' rhs True <> "]"
src/Nock/Types.hsnew file+114
@@ -0,0 +1,114 @@
1+module Nock.Types
2+ ( pretty,
3+ Noun (..),
4+ Atom,
5+ atomShortByteString,
6+ atomByteString,
7+ Annotation (..),
8+ atom,
9+ cell,
10+ nounEq,
11+ EqualityCache,
12+ annotation,
13+ )
14+where
15+
16+import Control.DeepSeq
17+import Data.ByteString (ByteString)
18+import Data.ByteString.Short
19+import Data.HashMap.Strict qualified as HM
20+import Data.Text.Lazy qualified as TL
21+import Data.Text.Lazy.Builder qualified as TLB
22+import Data.Text.Lazy.Builder.Int qualified as TLB
23+import Effectful
24+import Effectful.State.Static.Local qualified as SEL
25+import GHC.Generics
26+import GHC.Natural
27+import GHC.Num (Natural (..))
28+import GHC.Num.BigNat (bigNatFromWord#)
29+import System.Mem.StableName
30+import Test.QuickCheck
31+
32+newtype EqualityCache = EqualityCache (HM.HashMap (StableName Noun, StableName Noun) Bool)
33+ deriving newtype (Semigroup, Monoid)
34+
35+nounEq :: (SEL.State EqualityCache :> es, IOE :> es) => Noun -> Noun -> Eff es Bool
36+nounEq x y = do
37+ xName <- liftIO $ makeStableName x
38+ yName <- liftIO $ makeStableName y
39+ EqualityCache cache <- SEL.get
40+ case HM.lookup (xName, yName) cache of
41+ Just res -> pure res
42+ Nothing -> do
43+ res <- case (x, y) of
44+ (Atom xa _, Atom ya _) -> pure $ xa == ya
45+ (Cell xLhs xRhs _, Cell yLhs yRhs _) -> do
46+ lhsRes <- nounEq xLhs yLhs
47+ if lhsRes then nounEq xRhs yRhs else pure False
48+ _ -> pure False
49+ SEL.put $ EqualityCache $ HM.insert (xName, yName) res $ HM.insert (yName, xName) res $ cache
50+ pure res
51+
52+data Annotation = Annotation
53+ deriving stock (Show, Generic)
54+ deriving anyclass (NFData)
55+
56+atom :: Natural -> Noun
57+atom nat = Atom nat Annotation {}
58+
59+cell :: Noun -> Noun -> Noun
60+cell lhs rhs =
61+ Cell
62+ lhs
63+ rhs
64+ Annotation
65+ {
66+ }
67+
68+annotation :: Noun -> Annotation
69+annotation (Atom _ ann) = ann
70+annotation (Cell _ _ ann) = ann
71+
72+type Atom = Natural
73+
74+atomShortByteString :: Atom -> ShortByteString
75+atomShortByteString (NB ba) = SBS ba
76+atomShortByteString (NS w) = SBS (bigNatFromWord# w)
77+
78+atomByteString :: Atom -> ByteString
79+atomByteString = fromShort . atomShortByteString
80+
81+data Noun
82+ = Atom !Atom Annotation
83+ | Cell !Noun !Noun Annotation
84+ deriving stock (Generic)
85+ deriving anyclass (NFData)
86+
87+instance Eq Noun where
88+ (Cell lhsA lhsB _) == (Cell rhsA rhsB _) = lhsA == rhsA && lhsB == rhsB
89+ (Atom a _) == (Atom b _) = a == b
90+ _ == _ = False
91+
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+
98+instance Arbitrary Noun where
99+ arbitrary =
100+ oneof
101+ [ atom <$> arbitrarySizedNatural,
102+ cell <$> arbitrary <*> arbitrary
103+ ]
104+
105+instance Show Noun where
106+ show = TL.unpack . pretty
107+
108+pretty :: Noun -> TL.Text
109+pretty noun = TLB.toLazyText $ pretty' noun False
110+
111+pretty' :: Noun -> Bool -> TLB.Builder
112+pretty' (Atom a _) _ = TLB.decimal a
113+pretty' (Cell lhs rhs _) True = pretty' lhs False <> " " <> pretty' rhs True
114+pretty' (Cell lhs rhs _) False = "[" <> pretty' lhs False <> " " <> pretty' rhs True <> "]"
stack.yaml+3−3
@@ -3,6 +3,7 @@ nix:
33 packages:
44 - zlib
55 - pkg-config
6+ - urbit
67# This file was automatically generated by 'stack init'
78#
89# Some commonly used options have been documented as comments in this file.
@@ -22,8 +23,7 @@ nix:
2223#
2324# resolver: ./custom-snapshot.yaml
2425# resolver: https://example.com/snapshots/2018-01-01.yaml
25−resolver:
26− url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/21/6.yaml
26+resolver: lts-23.21
2727
2828# User packages to be built.
2929# Various formats can be used as shown in the example below.
@@ -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+8−9
@@ -5,20 +5,19 @@
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:
20− sha256: 2e7d4a730d8eb5373b2d383fac84efcf7c81e3b7a5fce71b4c2e19a1768f25a6
21− size: 640239
22− url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/21/6.yaml
23− original:
24− url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/21/6.yaml
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+30−96
@@ -1,114 +1,48 @@
11module Main (main) where
22
3−import Data.ByteString qualified as BS
3+import Control.Monad
44import Data.ByteString.Lazy qualified as BSL
5−import Data.Char qualified as Char
65import Data.Function
7−import Data.Text as T
8−import Data.Text.Encoding qualified as T
9−import Data.Text.IO as T
10−import Data.Text.Lazy as TL
116import Data.Text.Lazy.Encoding as TL
12−import Data.Text.Lazy.IO as TL
13−import Debug.Trace
14−import Debug.Trace (traceShowId)
15−import GHC.Base (unsafeChr)
7+import Effectful
8+import Effectful.State.Static.Local qualified as SEL
169import Nock
10+import Nock.Cue
1711import Nock.Jam
18−import Nock.Parser
12+import Nock.Jets
1913import Nock.Parser qualified
20−import Nock.Printer
14+import Nock.Types
15+import System.FilePath.Posix
2116import System.Process.Typed
22−import Test.Hspec
23−import Test.Hspec.QuickCheck
24−import Test.QuickCheck
2517import Test.Tasty
26−import Test.Tasty.Golden (goldenVsFile, goldenVsString)
27−import Test.Tasty.Hspec
18+import Test.Tasty.Golden
19+import Test.Tasty.HUnit (testCase, (@?=))
20+import Test.Tasty.QuickCheck
2821
2922main :: IO ()
3023main = do
31− spec <- testSpec "nock" specs
24+ spec <- goldenTest
3225 defaultMain $
3326 testGroup
3427 "nock"
35− [ -- spec
36− goldenTest "add",
37− goldenTest "dec"
38− -- goldenVsString "add" "golden/add.nock" "golden/add.result.nock" $
39− -- file <-
40− -- TL.writeFile "golden/add.result.nock" $ Nock.Printer.pretty
28+ [ spec,
29+ testProperty "cue . jam == id" (\noun -> noun === (cue . jam) noun),
30+ testCase "" (decJam @?= BSL.toStrict ((jam . cue) (BSL.fromStrict decJam)))
4131 ]
4232
43−goldenTest :: String -> TestTree
44−goldenTest name = do
45− let source = "tests/golden/" <> name <> ".hoon"
46− let target = "tests/golden/" <> name <> ".nock"
47− goldenVsString name target $ do
48− hoon <- BSL.readFile source
49− (_, BSL.dropEnd 6 . BSL.drop 11 -> output) <-
50− readProcessStdout $
51− proc "/run/current-system/sw/bin/urbit" ["eval"]
52− & setStdin (byteStringInput hoon)
53− let result = TL.encodeUtf8 $ Nock.Printer.pretty $ tar $ Nock.Parser.decode $ T.decodeUtf8 $ BS.toStrict ("[0 " <> output <> "]")
54− print result
55− pure result
56−
57−-- TL.writeFile target (Nock.Printer.pretty . tar $ Nock.Parser.decode inp)
58−
59−specs :: Spec
60−specs = describe "nock" $ do
61− tarTest "[77 [2 [1 42] [1 1 153 218]]]" "[153 218]"
62− tarTest "[42 8 [1 0] 8 [1 6 [5 [0 7] 4 0 6] [0 6] 9 2 [0 2] [4 0 6] 0 7] 9 2 0 1]" "41"
63− tarTest "[4 9 2.398 0 2.047]" "3"
64− tarTest "[2 [1 1 3] 9 36 0 2.047]" "4"
65− tarTest "[[1 2] [7 [9 36 0 2.047] 9 2 0 1]]" "3"
66− tarTest "[50 [4 0 1]]" "51"
67− tarTest "[8 [8 [1 0] [1 6 [5 [1 0] 0 6] [0 0] 8 [1 0] 8 [1 6 [5 [0 30] 4 0 6] [0 6] 9 2 [0 2] [4 0 6] 0 7] 9 2 0 1] 0 1] 9 2 [0 4] [7 [0 3] 1 10] 0 11]" "9"
68− tarTest "[[[4 5] [6 14 15]] [0 7]]" "[14 15]"
69− tarTest "[77 [2 [1 42] [1 1 153 218]]]" "[153 218]"
70− tarTest "[[42 43] [8 [1 0] [8 [1 [6 [5 [0 6] [0 14]] [1 0] [6 [5 [0 6] [0 15]] [1 1] [9 2 [[0 2] [4 0 6] [0 7]]]]]] [9 2 0 1]]]]" "0"
71− tarTest "[8 [9 36 0 2.047] 9 2 10 [6 [7 [0 3] 1 1] 7 [0 3] 1 1] 0 2]" "2"
72− tarTest "[[132 19] [4 0 3]]" "20"
73− fasTest "[1 [531 25 99]]" "[531 25 99]"
74− fasTest "[2 [531 25 99]]" "531"
75− fasTest "[3 [531 25 99]]" "[25 99]"
76− fasTest "[6 [531 25 99]]" "25"
77− haxTest "[2 11 [22 33]]" "[11 33]"
78− haxTest "[3 11 [22 33]]" "[22 11]"
79− haxTest "[4 11 [[22 33] 44]]" "[[11 33] 44]"
80− haxTest "[5 11 [[22 33] 44]]" "[[22 11] 44]"
81− tarTest "[7 [9 36 0 2.047] 9 2 0 1]" "[[22 11] 44]"
82− tarTest "[[[4 5] [6 14 15]] [0 7]]" "[14 15]"
83− tarTest "[[1 3][7 [9 36 0 2.047] 9 2 0 1]]" "4"
84− -- tarTest "[9 36 0 2.047]" "0"
85−
86− prop
87− "rub (mat atom) = atom"
88− ( \(NonNegative (a :: Integer)) (NonNegative (b :: Integer)) (NonNegative (c :: Integer)) ->
89− withMaxSuccess 10000 $
90− let atom = fromInteger (a * b * c * 11)
91− in rub (mat atom) === atom
92− )
93− describe "cue (jam noun) = noun" $ do
94− testJam "[77 [2 [1 42] [1 1 153 218]]]"
95−
96−tarTest :: T.Text -> T.Text -> Spec
97−tarTest source target =
98− it (T.unpack ("*" <> source <> " = " <> target)) $
99− tar (decode source) === decode target
100−
101−haxTest :: T.Text -> T.Text -> Spec
102−haxTest source target =
103− it (T.unpack ("#" <> source <> " = " <> target)) $
104− hax (decode source) == decode target
105−
106−fasTest :: T.Text -> T.Text -> Spec
107−fasTest source target =
108− it (T.unpack ("/" <> source <> " = " <> target)) $
109− fas (decode source) == decode target
110−
111−testJam :: T.Text -> Spec
112−testJam source =
113− it ("cue (jam " ++ T.unpack source ++ ") = source") $
114− cue (jam (decode source)) == decode source
33+goldenTest :: IO TestTree
34+goldenTest = do
35+ files <- findByExtension [".hoon"] "tests/golden"
36+ fmap (testGroup "golden") $ forM files $ \source -> do
37+ let target = replaceExtension source ".nock"
38+ pure $ goldenVsString (takeBaseName source) target $ do
39+ hoon <- BSL.readFile source
40+ nock <-
41+ fmap (Nock.Parser.noun . TL.decodeUtf8 . BSL.dropEnd 6 . BSL.drop 11 . snd)
42+ . readProcessStdout
43+ $ proc "urbit" ["eval"]
44+ & setStdin (byteStringInput hoon)
45+ & setStderr nullStream
46+ noun <- runEff . SEL.evalState (mempty :: EqualityCache) . tar $ cell (atom 0) nock
47+ let result = TL.encodeUtf8 . pretty $ noun
48+ pure result
tests/golden/add.hoon+9−13
@@ -1,19 +1,16 @@
11!=
22=>
33|%
4+++ foo 1
5+++ baz |= x=@ x
46++ dec
5− ~/ %dec
6− :: unsigned decrement by one.
7− |= a=@
8− ~_ leaf+"decrement-underflow"
9− ?< =(0 a)
10− =+ b=0
11− :: decremented integer
12− |- ^- @
13− ?: =(a +(b)) b
14− $(b +(b))
7+|= a=@
8+=/ b 0
9+|- ^- @
10+?. =(a +(b)) $(b +(b)) b
11+++ bar 2
1512++ add
16− ~/ %add
13+ :: ~/ %add
1714 :: unsigned addition
1815 ::
1916 :: a: augend
@@ -24,5 +21,4 @@
2421 ?: =(0 a) b
2522 $(a (dec a), b +(b))
2623--
27−%+ add
28−234 111
24+(add 3 5)
tests/golden/add.nock+1−1
@@ -1 +1 @@
1−345
1+8
tests/golden/dec.hoon+9−10
@@ -1,17 +1,16 @@
11!=
22=>
33|%
4+++ add
5+ |= x=@
6+ x
7+++ bar 4
48++ dec
5−~/ %dec
6−:: unsigned decrement by one.
79|= a=@
8−~_ leaf+"decrement-underflow"
9−?< =(0 a)
10−=+ b=0
11−:: decremented integer
10+=/ b 0
1211|- ^- @
13−?: =(a +(b)) b
14−$(b +(b))
12+?. =(a +(b)) $(b +(b)) b
1513--
16−
17−%- dec 8
14+%-
15+dec
16+5
tests/golden/dec.nock+1−1
@@ -1 +1 @@
1−7
1+4
tests/golden/mul.hoonnew file+37
@@ -0,0 +1,37 @@
1+!=
2+=>
3+|%
4+++ mul
5+ ~/ %mul
6+ :: unsigned multiplication
7+ ::
8+ :: a: multiplicand
9+ :: b: multiplier
10+ |: [a=`@`1 b=`@`1]
11+ :: product
12+ ^- @
13+ =+ c=0
14+ |-
15+ ?: =(0 a) c
16+ $(a (dec a), c (add b c))
17+++ foo 1
18+++ baz |= x=@ x
19+++ dec
20+|= a=@
21+=/ b 0
22+|- ^- @
23+?. =(a +(b)) $(b +(b)) b
24+++ bar 2
25+++ add
26+ :: ~/ %add
27+ :: unsigned addition
28+ ::
29+ :: a: augend
30+ :: b: addend
31+ |= [a=@ b=@]
32+ :: sum
33+ ^- @
34+ ?: =(0 a) b
35+ $(a (dec a), b +(b))
36+--
37+(mul 3 5)
tests/golden/mul.nocknew file+1
@@ -0,0 +1 @@
1+15