on master help sign in
Merge pull request #1 from ilyakooo0/iko/decon

Noun deconstruction

commit9e0e39abb4714caf0439d8d8fd57a970b0f88a55 authoriko <mail@iko.soy> dateThu 1 Jun 2023, 17:35 (3 years ago) parent38a906d05d6554
2 files changed+334
src/Urbit/Deconstructor.elm+249 tests/Test/Urbit.elm+85
src/Urbit/Deconstructor.elmnew file+249
@@ -0,0 +1,249 @@
1+module Urbit.Deconstructor exposing
2+ ( Deconstructor
3+ , alt
4+ , bytes
5+ , cell
6+ , const
7+ , cord
8+ , float32
9+ , float64
10+ , int
11+ , list
12+ , llec
13+ , map
14+ , oneOf
15+ , run
16+ , runBytes
17+ , sig
18+ , signedInt
19+ , tape
20+ , tar
21+ )
22+
23+import Bitwise
24+import Bytes exposing (Bytes, Endianness(..))
25+import Bytes.Decode as BD
26+import Bytes.Extra
27+import Urbit exposing (..)
28+
29+
30+type Deconstructor a b
31+ = Deconstructor (Noun -> a -> Maybe b)
32+
33+
34+run : Deconstructor (a -> a) a -> Noun -> Maybe a
35+run (Deconstructor f) noun =
36+ f noun identity
37+
38+
39+runBytes : Deconstructor (a -> a) a -> Bytes -> Maybe a
40+runBytes (Deconstructor f) bs =
41+ cue bs
42+ |> Maybe.andThen
43+ (\noun -> f noun identity)
44+
45+
46+const : Deconstructor (a -> a) a -> a -> Deconstructor c c
47+const (Deconstructor f) value =
48+ Deconstructor
49+ (\noun c ->
50+ case f noun identity of
51+ Just a ->
52+ if a == value then
53+ Just c
54+
55+ else
56+ Nothing
57+
58+ Nothing ->
59+ Nothing
60+ )
61+
62+
63+cord : Deconstructor (String -> a) a
64+cord =
65+ Deconstructor
66+ (\x f ->
67+ case x of
68+ Atom bs ->
69+ BD.decode (BD.string (Bytes.width bs)) bs
70+ |> Maybe.map f
71+
72+ Cell _ ->
73+ Nothing
74+ )
75+
76+
77+tape : Deconstructor (String -> a) a
78+tape =
79+ list cord |> fmap String.concat
80+
81+
82+int : Deconstructor (Int -> a) a
83+int =
84+ Deconstructor
85+ (\x f ->
86+ case x of
87+ Atom bs ->
88+ Bytes.Extra.toByteValues bs
89+ |> List.foldr
90+ (\b acc -> Bitwise.shiftLeftBy 8 acc |> Bitwise.or b)
91+ 0
92+ |> f
93+ |> Just
94+
95+ Cell _ ->
96+ Nothing
97+ )
98+
99+
100+signedInt : Deconstructor (Int -> a) a
101+signedInt =
102+ int
103+ |> fmap
104+ (\i ->
105+ if Bitwise.and 1 i == 1 then
106+ -(Bitwise.shiftRightBy 1 (1 + i))
107+
108+ else
109+ Bitwise.shiftRightBy 1 i
110+ )
111+
112+
113+float32 : Deconstructor (Float -> a) a
114+float32 =
115+ Deconstructor
116+ (\x f ->
117+ case x of
118+ Atom bs ->
119+ BD.decode (BD.float32 LE) bs
120+ |> Maybe.map f
121+
122+ Cell _ ->
123+ Nothing
124+ )
125+
126+
127+float64 : Deconstructor (Float -> a) a
128+float64 =
129+ Deconstructor
130+ (\x f ->
131+ case x of
132+ Atom bs ->
133+ BD.decode (BD.float64 LE) bs
134+ |> Maybe.map f
135+
136+ Cell _ ->
137+ Nothing
138+ )
139+
140+
141+bytes : Deconstructor (Bytes -> a) a
142+bytes =
143+ Deconstructor
144+ (\n f ->
145+ case n of
146+ Atom bs ->
147+ f bs |> Just
148+
149+ Cell _ ->
150+ Nothing
151+ )
152+
153+
154+sig : Deconstructor a a
155+sig =
156+ Deconstructor
157+ (\n a ->
158+ case n of
159+ Atom b ->
160+ if (Bytes.Extra.toByteValues b |> List.filter (\x -> x /= 0)) == [] then
161+ Just a
162+
163+ else
164+ Nothing
165+
166+ Cell _ ->
167+ Nothing
168+ )
169+
170+
171+list : Deconstructor (a -> a) a -> Deconstructor (List a -> b) b
172+list (Deconstructor f) =
173+ Deconstructor
174+ (\n g ->
175+ let
176+ go n_ =
177+ case n_ of
178+ Atom _ ->
179+ Just []
180+
181+ Cell ( el, tail ) ->
182+ Maybe.map2 (\a b -> a :: b) (f el identity) (go tail)
183+ in
184+ go n |> Maybe.map g
185+ )
186+
187+
188+alt : Deconstructor a b -> Deconstructor a b -> Deconstructor a b
189+alt (Deconstructor f) (Deconstructor g) =
190+ Deconstructor
191+ (\n a ->
192+ case f n a of
193+ Just x ->
194+ Just x
195+
196+ Nothing ->
197+ g n a
198+ )
199+
200+
201+oneOf : List (Deconstructor a b) -> Deconstructor a b
202+oneOf l =
203+ case l of
204+ [] ->
205+ Deconstructor (\_ _ -> Nothing)
206+
207+ x :: xs ->
208+ alt x (oneOf xs)
209+
210+
211+tar : Deconstructor a a
212+tar =
213+ Deconstructor (\_ a -> Just a)
214+
215+
216+llec : Deconstructor a b -> Deconstructor b c -> Deconstructor a c
217+llec (Deconstructor r) (Deconstructor l) =
218+ Deconstructor
219+ (\noun a ->
220+ case noun of
221+ Cell ( lhs, rhs ) ->
222+ r rhs a |> Maybe.andThen (\b -> l lhs b)
223+
224+ Atom _ ->
225+ Nothing
226+ )
227+
228+
229+cell : Deconstructor a b -> Deconstructor b c -> Deconstructor a c
230+cell (Deconstructor l) (Deconstructor r) =
231+ Deconstructor
232+ (\noun a ->
233+ case noun of
234+ Cell ( lhs, rhs ) ->
235+ l lhs a |> Maybe.andThen (\b -> r rhs b)
236+
237+ Atom _ ->
238+ Nothing
239+ )
240+
241+
242+map : a -> Deconstructor a b -> Deconstructor (b -> c) c
243+map a (Deconstructor f) =
244+ Deconstructor (\noun g -> f noun a |> Maybe.map g)
245+
246+
247+fmap : (a -> b) -> Deconstructor (a -> c) c -> Deconstructor (b -> c) c
248+fmap f (Deconstructor g) =
249+ Deconstructor (\noun h -> g noun (f >> h))
tests/Test/Urbit.elm+85
@@ -10,6 +10,7 @@ import List.Extra as List
1010import Test exposing (..)
1111import Test.Utils exposing (..)
1212import Urbit exposing (..)
13+import Urbit.Deconstructor as D
1314
1415
1516tests : Test
@@ -64,6 +65,90 @@ tests =
6465 )
6566 )
6667 ]
68+ , describe "Decon"
69+ [ test "[1 2]"
70+ (\() ->
71+ Expect.equal
72+ (Just ( 1, 2 ))
73+ (D.runBytes
74+ (D.cell D.int D.int |> D.map Tuple.pair)
75+ (Bytes.fromByteValues [ 0x31, 0x12 ])
76+ )
77+ )
78+ , test "[4 ~[1 2 3]]"
79+ (\() ->
80+ Expect.equal
81+ (Just ( 4, [ 1, 2, 3 ] ))
82+ (D.runBytes
83+ (D.cell D.int (D.list D.int) |> D.map Tuple.pair)
84+ (Bytes.fromByteValues [ 0x61, 0xC6, 0x21, 0x43, 0x0B ])
85+ )
86+ )
87+ , test "[.8 .11]"
88+ (\() ->
89+ Expect.equal
90+ (Just ( 8, 11 ))
91+ (D.runBytes
92+ (D.cell D.float32 D.float32 |> D.map Tuple.pair)
93+ (Bytes.fromByteValues [ 0x01, 0x1F, 0x00, 0x00, 0x20, 0x08, 0x7C, 0x00, 0x00, 0x98, 0x20 ])
94+ )
95+ )
96+ , test "[8 'hi']"
97+ (\() ->
98+ Expect.equal
99+ (Just ( 8, "hi" ))
100+ (D.runBytes
101+ (D.cell D.int D.cord |> D.map Tuple.pair)
102+ (Bytes.fromByteValues [ 0x41, 0x10, 0x3C, 0x5A, 0x1A ])
103+ )
104+ )
105+ , test "[8 \"hi\"]"
106+ (\() ->
107+ Expect.equal
108+ (Just ( 8, "hi" ))
109+ (D.runBytes
110+ (D.cell D.int D.tape |> D.map Tuple.pair)
111+ (Bytes.fromByteValues [ 0x41, 0x30, 0x38, 0x3A, 0x78, 0x5A ])
112+ )
113+ )
114+ , describe "sum types"
115+ [ test "[%tape \"hi\"]"
116+ (\() ->
117+ Expect.equal
118+ (Just "hi")
119+ (D.runBytes
120+ (D.oneOf
121+ [ D.cell (D.const D.cord "tape") D.tape
122+ , D.cell (D.const D.cord "cord") D.cord
123+ ]
124+ )
125+ (Bytes.fromByteValues [ 0x01, 0x9F, 0x2E, 0x0C, 0xAE, 0x1C, 0x1C, 0x1D, 0x3C, 0x2D ])
126+ )
127+ )
128+ , test "[%cord 'hi']"
129+ (\() ->
130+ Expect.equal
131+ (Just "hi")
132+ (D.runBytes
133+ (D.oneOf
134+ [ D.cell (D.const D.cord "tape") D.tape
135+ , D.cell (D.const D.cord "cord") D.cord
136+ ]
137+ )
138+ (Bytes.fromByteValues [ 0x01, 0x7F, 0xEC, 0x4D, 0x8E, 0x0C, 0x1E, 0x2D, 0x0D ])
139+ )
140+ )
141+ ]
142+ , test "[--8 -8]"
143+ (\() ->
144+ Expect.equal
145+ (Just ( 8, -8 ))
146+ (D.runBytes
147+ (D.cell D.signedInt D.signedInt |> D.map Tuple.pair)
148+ (Bytes.fromByteValues [ 0xC1, 0x20, 0xE4, 0x01 ])
149+ )
150+ )
151+ ]
67152 ]
68153
69154