@@ -1,27 +1,72 @@
1module Ur.Deconstructor exposing
1module Ur.Deconstructor exposing
2 ( Deconstructor
2 ( Deconstructor
3− , alt
3+ , run, runBytes
4− , bigint
4+ , cell, list, oneOf, const
20− , signedInt
6+ , int, signedInt, bigint
21− , tape
8+ , cord, tape
22− , tar
9+ , bytes, sig, ignore, tar
12+{-| This module provides an API to deconstruct `Noun`s into arbitrary Elm data structures.
14+The principal (and types) are very similar to `Url.Parser` from `elm/url`.
16+You would parse a `[%edit cord @]` like this:
18+ type alias Edit = {text : String, id: Int}
20+ (D.cell (D.const D.cord "edit") (D.cell D.int D.cord)) |> D.map Edit
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`.
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`.
31+# Running a `Deconstructor`
36+# Higher-order `Deconstructor`s
38+@docs cell, list, oneOf, const
41+# Mapping a `Deconstructor`
51+@docs int, signedInt, bigint
56+@docs float32, float64
66+@docs bytes, sig, ignore, tar
25import BigInt exposing (BigInt)
70import BigInt exposing (BigInt)
26import BigInt.Bytes
71import BigInt.Bytes
27import Bitwise
72import Bitwise
@@ -29,18 +74,25 @@ import Bytes exposing (Bytes, Endianness(..))
29import Bytes.Decode as BD
74import Bytes.Decode as BD
30import Bytes.Encode as BE
75import Bytes.Encode as BE
31import Bytes.Extra
76import Bytes.Extra
77+import Ur.Jam exposing (cue)
32−import Ur exposing (..)
78+import Ur.Types exposing (..)
81+{-| A `Noun` deconstructor.
35type Deconstructor a b
83type Deconstructor a b
36 = Deconstructor (Noun -> a -> Maybe b)
84 = Deconstructor (Noun -> a -> Maybe b)
87+{-| Executes a `Deconstructor` on a `Noun`.
39run : Deconstructor (a -> a) a -> Noun -> Maybe a
89run : Deconstructor (a -> a) a -> Noun -> Maybe a
40run (Deconstructor f) noun =
90run (Deconstructor f) noun =
41 f noun identity
91 f noun identity
94+{-| Executes a deconstructor on a `jam`med `Noun`.
44runBytes : Deconstructor (a -> a) a -> Bytes -> Maybe a
96runBytes : Deconstructor (a -> a) a -> Bytes -> Maybe a
45runBytes (Deconstructor f) bs =
97runBytes (Deconstructor f) bs =
@@ -48,6 +100,15 @@ runBytes (Deconstructor f) bs =
48 (\noun -> f noun identity)
100 (\noun -> f noun identity)
103+{-| Asserts that the value at the current position should be exactly equal to the second argument.
105+The first argument is a `Deconstructor` for the gven tyoe.
107+The second argument is the value to compare with.
109+This is useful to match on `term`s when there are multiple possible cases in a head-tagged union.
51const : Deconstructor (a -> a) a -> a -> Deconstructor c c
112const : Deconstructor (a -> a) a -> a -> Deconstructor c c
52const (Deconstructor f) value =
113const (Deconstructor f) value =
53 Deconstructor
114 Deconstructor
@@ -65,6 +126,8 @@ const (Deconstructor f) value =
129+{-| Extracts a `cord` at the current location.
68cord : Deconstructor (String -> a) a
131cord : Deconstructor (String -> a) a
70 Deconstructor
133 Deconstructor
@@ -79,11 +142,18 @@ cord =
145+{-| Extracts a `tape` at the current location.
82tape : Deconstructor (String -> a) a
147tape : Deconstructor (String -> a) a
84 list cord |> fmap String.concat
149 list cord |> fmap String.concat
152+{-| Extracts a 32-bit unsigned `Int` at the given location.
154+If the `Atom` at the current location is larger than 32 bits the the behaviour is undefined.
87int : Deconstructor (Int -> a) a
157int : Deconstructor (Int -> a) a
89 Deconstructor
159 Deconstructor
@@ -113,6 +183,8 @@ int =
186+{-| Extracts a `BigInt` at the current location.
116bigint : Deconstructor (BigInt -> a) a
188bigint : Deconstructor (BigInt -> a) a
118 Deconstructor
190 Deconstructor
@@ -126,6 +198,11 @@ bigint =
201+{-| Extracts a 32-bit signed `Int` at the given location.
203+If the `Atom` at the current location is larger than 32 bits the the behaviour is undefined.
129signedInt : Deconstructor (Int -> a) a
206signedInt : Deconstructor (Int -> a) a
130signedInt =
207signedInt =
@@ -139,6 +216,8 @@ signedInt =
219+{-| Extracts a 32-bit `Float` at the given location.
142float32 : Deconstructor (Float -> a) a
221float32 : Deconstructor (Float -> a) a
144 Deconstructor
223 Deconstructor
@@ -153,6 +232,8 @@ float32 =
235+{-| Extracts a 64-bit `Float` at the given location.
156float64 : Deconstructor (Float -> a) a
237float64 : Deconstructor (Float -> a) a
158 Deconstructor
239 Deconstructor
@@ -167,6 +248,8 @@ float64 =
251+{-| Extracts the raw `Byte`s of an `Atom` at the current location.
170bytes : Deconstructor (Bytes -> a) a
253bytes : Deconstructor (Bytes -> a) a
172 Deconstructor
255 Deconstructor
@@ -180,6 +263,8 @@ bytes =
266+{-| Asserts the the `Atom` at the current position should be exactly `sig` (`~`).
183sig : Deconstructor a a
268sig : Deconstructor a a
185 Deconstructor
270 Deconstructor
@@ -197,6 +282,11 @@ sig =
285+{-| Extracts a sig-terminated list of arbitrary elements at the current position.
287+The first argument is a `Deconstructor` of the elements of the list.
200list : Deconstructor (a -> a) a -> Deconstructor (List a -> b) b
290list : Deconstructor (a -> a) a -> Deconstructor (List a -> b) b
201list (Deconstructor f) =
291list (Deconstructor f) =
202 Deconstructor
292 Deconstructor
@@ -227,6 +317,11 @@ alt (Deconstructor f) (Deconstructor g) =
320+{-| Try to execute all of the `Deconstructor`s in order until one succeeds.
322+This is especially useful for deconstructing head-tagged unions from Hoon.
230oneOf : List (Deconstructor a b) -> Deconstructor a b
325oneOf : List (Deconstructor a b) -> Deconstructor a b
232 case l of
327 case l of
@@ -237,29 +332,31 @@ oneOf l =
237 alt x (oneOf xs)
332 alt x (oneOf xs)
335+{-| Extract the raw `Noun` at the current position.
240tar : Deconstructor (Noun -> a) a
340tar : Deconstructor (Noun -> a) a
242 Deconstructor (\noun f -> Just (f noun))
342 Deconstructor (\noun f -> Just (f noun))
345+{-| Ignore any value at the current position.
347+This is useful when you have a value you don't care about. `ignore` allows you to just skip the value.
245ignore : Deconstructor a a
350ignore : Deconstructor a a
247 Deconstructor (\_ f -> Just f)
352 Deconstructor (\_ f -> Just f)
250−llec : Deconstructor a b -> Deconstructor b c -> Deconstructor a c
355+{-| Extracts a [`Cell`](https://developers.urbit.org/reference/glossary/cell) (pair) of two arbitrary values.
251−llec (Deconstructor r) (Deconstructor l) =
255− Cell ( lhs, rhs ) ->
256− r rhs a |> Maybe.andThen (\b -> l lhs b)
357+Accepts two arbitrary `Deconstructor`s that form a Cell.
263cell : Deconstructor a b -> Deconstructor b c -> Deconstructor a c
360cell : Deconstructor a b -> Deconstructor b c -> Deconstructor a c
264cell (Deconstructor l) (Deconstructor r) =
361cell (Deconstructor l) (Deconstructor r) =
265 Deconstructor
362 Deconstructor
@@ -273,6 +370,11 @@ cell (Deconstructor l) (Deconstructor r) =
373+{-| Maps (applies) a function to all of the values deconstructed.
375+This is useful when you want to create a data type with extracted values as fields.
276map : a -> Deconstructor a b -> Deconstructor (b -> c) c
378map : a -> Deconstructor a b -> Deconstructor (b -> c) c
277map a (Deconstructor f) =
379map a (Deconstructor f) =
278 Deconstructor (\noun g -> f noun a |> Maybe.map g)
380 Deconstructor (\noun g -> f noun a |> Maybe.map g)