@@ -1,27 +1,72 @@
11module Ur.Deconstructor exposing
22 ( Deconstructor
3− , alt
4− , bigint
5− , bytes
6− , cell
7− , const
8− , cord
9− , float32
10− , float64
11− , ignore
12− , int
13− , list
14− , llec
3+ , run, runBytes
4+ , cell, list, oneOf, const
155 , map
16− , oneOf
17− , run
18− , runBytes
19− , sig
20− , signedInt
21− , tape
22− , tar
6+ , int, signedInt, bigint
7+ , float32, float64
8+ , cord, tape
9+ , bytes, sig, ignore, tar
2310 )
2411
12+{-| This module provides an API to deconstruct `Noun`s into arbitrary Elm data structures.
13+
14+The principal (and types) are very similar to `Url.Parser` from `elm/url`.
15+
16+You would parse a `[%edit cord @]` like this:
17+
18+ type alias Edit = {text : String, id: Int}
19+
20+ (D.cell (D.const D.cord "edit") (D.cell D.int D.cord)) |> D.map Edit
21+
22+When you `map` a `Deconstructor` the function you pass to `map` will accept exactly the number of arguments
23+that "captured" values in exacly the order they occured in the `Deconstructor`.
24+
25+In our case we `map` the `Edit` type, which accepts exaclty two arguments because there are two `Deconstructor`s
26+that "capture" a value: `D.int` and `D.cord`.
27+
28+@docs Deconstructor
29+
30+
31+# Running a `Deconstructor`
32+
33+@docs run, runBytes
34+
35+
36+# Higher-order `Deconstructor`s
37+
38+@docs cell, list, oneOf, const
39+
40+
41+# Mapping a `Deconstructor`
42+
43+@docs map
44+
45+
46+# Numbers
47+
48+
49+## `Int`a
50+
51+@docs int, signedInt, bigint
52+
53+
54+## `Float`s
55+
56+@docs float32, float64
57+
58+
59+# `String`s
60+
61+@docs cord, tape
62+
63+
64+# Miscellaneous
65+
66+@docs bytes, sig, ignore, tar
67+
68+-}
69+
2570import BigInt exposing (BigInt)
2671import BigInt.Bytes
2772import Bitwise
@@ -29,18 +74,25 @@ import Bytes exposing (Bytes, Endianness(..))
2974import Bytes.Decode as BD
3075import Bytes.Encode as BE
3176import Bytes.Extra
32−import Ur exposing (..)
77+import Ur.Jam exposing (cue)
78+import Ur.Types exposing (..)
3379
3480
81+{-| A `Noun` deconstructor.
82+-}
3583type Deconstructor a b
3684 = Deconstructor (Noun -> a -> Maybe b)
3785
3886
87+{-| Executes a `Deconstructor` on a `Noun`.
88+-}
3989run : Deconstructor (a -> a) a -> Noun -> Maybe a
4090run (Deconstructor f) noun =
4191 f noun identity
4292
4393
94+{-| Executes a deconstructor on a `jam`med `Noun`.
95+-}
4496runBytes : Deconstructor (a -> a) a -> Bytes -> Maybe a
4597runBytes (Deconstructor f) bs =
4698 cue bs
@@ -48,6 +100,15 @@ runBytes (Deconstructor f) bs =
48100 (\noun -> f noun identity)
49101
50102
103+{-| Asserts that the value at the current position should be exactly equal to the second argument.
104+
105+The first argument is a `Deconstructor` for the gven tyoe.
106+
107+The second argument is the value to compare with.
108+
109+This is useful to match on `term`s when there are multiple possible cases in a head-tagged union.
110+
111+-}
51112const : Deconstructor (a -> a) a -> a -> Deconstructor c c
52113const (Deconstructor f) value =
53114 Deconstructor
@@ -65,6 +126,8 @@ const (Deconstructor f) value =
65126 )
66127
67128
129+{-| Extracts a `cord` at the current location.
130+-}
68131cord : Deconstructor (String -> a) a
69132cord =
70133 Deconstructor
@@ -79,11 +142,18 @@ cord =
79142 )
80143
81144
145+{-| Extracts a `tape` at the current location.
146+-}
82147tape : Deconstructor (String -> a) a
83148tape =
84149 list cord |> fmap String.concat
85150
86151
152+{-| Extracts a 32-bit unsigned `Int` at the given location.
153+
154+If the `Atom` at the current location is larger than 32 bits the the behaviour is undefined.
155+
156+-}
87157int : Deconstructor (Int -> a) a
88158int =
89159 Deconstructor
@@ -113,6 +183,8 @@ int =
113183 )
114184
115185
186+{-| Extracts a `BigInt` at the current location.
187+-}
116188bigint : Deconstructor (BigInt -> a) a
117189bigint =
118190 Deconstructor
@@ -126,6 +198,11 @@ bigint =
126198 )
127199
128200
201+{-| Extracts a 32-bit signed `Int` at the given location.
202+
203+If the `Atom` at the current location is larger than 32 bits the the behaviour is undefined.
204+
205+-}
129206signedInt : Deconstructor (Int -> a) a
130207signedInt =
131208 int
@@ -139,6 +216,8 @@ signedInt =
139216 )
140217
141218
219+{-| Extracts a 32-bit `Float` at the given location.
220+-}
142221float32 : Deconstructor (Float -> a) a
143222float32 =
144223 Deconstructor
@@ -153,6 +232,8 @@ float32 =
153232 )
154233
155234
235+{-| Extracts a 64-bit `Float` at the given location.
236+-}
156237float64 : Deconstructor (Float -> a) a
157238float64 =
158239 Deconstructor
@@ -167,6 +248,8 @@ float64 =
167248 )
168249
169250
251+{-| Extracts the raw `Byte`s of an `Atom` at the current location.
252+-}
170253bytes : Deconstructor (Bytes -> a) a
171254bytes =
172255 Deconstructor
@@ -180,6 +263,8 @@ bytes =
180263 )
181264
182265
266+{-| Asserts the the `Atom` at the current position should be exactly `sig` (`~`).
267+-}
183268sig : Deconstructor a a
184269sig =
185270 Deconstructor
@@ -197,6 +282,11 @@ sig =
197282 )
198283
199284
285+{-| Extracts a sig-terminated list of arbitrary elements at the current position.
286+
287+The first argument is a `Deconstructor` of the elements of the list.
288+
289+-}
200290list : Deconstructor (a -> a) a -> Deconstructor (List a -> b) b
201291list (Deconstructor f) =
202292 Deconstructor
@@ -227,6 +317,11 @@ alt (Deconstructor f) (Deconstructor g) =
227317 )
228318
229319
320+{-| Try to execute all of the `Deconstructor`s in order until one succeeds.
321+
322+This is especially useful for deconstructing head-tagged unions from Hoon.
323+
324+-}
230325oneOf : List (Deconstructor a b) -> Deconstructor a b
231326oneOf l =
232327 case l of
@@ -237,29 +332,31 @@ oneOf l =
237332 alt x (oneOf xs)
238333
239334
335+{-| Extract the raw `Noun` at the current position.
336+
337+Always succeeds.
338+
339+-}
240340tar : Deconstructor (Noun -> a) a
241341tar =
242342 Deconstructor (\noun f -> Just (f noun))
243343
244344
345+{-| Ignore any value at the current position.
346+
347+This is useful when you have a value you don't care about. `ignore` allows you to just skip the value.
348+
349+-}
245350ignore : Deconstructor a a
246351ignore =
247352 Deconstructor (\_ f -> Just f)
248353
249354
250−llec : Deconstructor a b -> Deconstructor b c -> Deconstructor a c
251−llec (Deconstructor r) (Deconstructor l) =
252− Deconstructor
253− (\noun a ->
254− case noun of
255− Cell ( lhs, rhs ) ->
256− r rhs a |> Maybe.andThen (\b -> l lhs b)
257−
258− Atom _ ->
259− Nothing
260− )
355+{-| Extracts a [`Cell`](https://developers.urbit.org/reference/glossary/cell) (pair) of two arbitrary values.
261356
357+Accepts two arbitrary `Deconstructor`s that form a Cell.
262358
359+-}
263360cell : Deconstructor a b -> Deconstructor b c -> Deconstructor a c
264361cell (Deconstructor l) (Deconstructor r) =
265362 Deconstructor
@@ -273,6 +370,11 @@ cell (Deconstructor l) (Deconstructor r) =
273370 )
274371
275372
373+{-| Maps (applies) a function to all of the values deconstructed.
374+
375+This is useful when you want to create a data type with extracted values as fields.
376+
377+-}
276378map : a -> Deconstructor a b -> Deconstructor (b -> c) c
277379map a (Deconstructor f) =
278380 Deconstructor (\noun g -> f noun a |> Maybe.map g)