@@ -6,24 +6,16 @@ module Ur.Deconstructor exposing
6 , int, signedInt, bigint
6 , int, signedInt, bigint
7 , float32, float64
7 , float32, float64
8 , cord, tape
8 , cord, tape
9− , bytes, sig, ignore, tar
9+ , bytes, sig, ignore, tar, lazy, debug
12{-| This module provides an API to deconstruct `Noun`s into arbitrary Elm data structures.
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`.
14+You would parse a `[%edit @ cord]` like this:
16−You would parse a `[%edit cord @]` like this:
16+ type alias Edit = {id: Int, text : String}
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
18+ (D.cell (D.const D.cord "edit") (D.cell D.bigint D.cord)) |> D.map (\( (), ( id, txt ) ) -> Edit id txt)
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`.
28@docs Deconstructor
20@docs Deconstructor
@@ -63,7 +55,7 @@ that "capture" a value: `D.int` and `D.cord`.
64# Miscellaneous
56# Miscellaneous
66−@docs bytes, sig, ignore, tar
58+@docs bytes, sig, ignore, tar, lazy, debug
@@ -74,139 +66,74 @@ import Bytes exposing (Bytes, Endianness(..))
74import Bytes.Decode as BD
66import Bytes.Decode as BD
75import Bytes.Encode as BE
67import Bytes.Encode as BE
76import Bytes.Extra
68import Bytes.Extra
77−import Ur.Jam exposing (cue)
69+import Ur.Jam exposing (cue, isSig)
78import Ur.Types exposing (..)
70import Ur.Types exposing (..)
81{-| A `Noun` deconstructor.
73{-| A `Noun` deconstructor.
83−type Deconstructor a b
75+type alias Deconstructor a =
84− = Deconstructor (Noun -> a -> Maybe b)
76+ Noun -> Maybe a
87{-| Executes a `Deconstructor` on a `Noun`.
79{-| Executes a `Deconstructor` on a `Noun`.
89−run : Deconstructor (a -> a) a -> Noun -> Maybe a
81+run : Deconstructor a -> Noun -> Maybe a
90−run (Deconstructor f) noun =
82+run f noun =
91− f noun identity
83+ f noun
94{-| Executes a deconstructor on a `jam`med `Noun`.
86{-| Executes a deconstructor on a `jam`med `Noun`.
96−runBytes : Deconstructor (a -> a) a -> Bytes -> Maybe a
88+runBytes : Deconstructor a -> Bytes -> Maybe a
97−runBytes (Deconstructor f) bs =
89+runBytes f bs =
99− |> Maybe.andThen
90+ cue bs |> Maybe.andThen f
100− (\noun -> f noun identity)
103−{-| Asserts that the value at the current position should be exactly equal to the second argument.
93+{-| Asserts that the value should be exactly equal to the second argument.
105−The first argument is a `Deconstructor` for the gven tyoe.
95+The first argument is a `Deconstructor` for the given type.
107The second argument is the value to compare with.
97The second argument is the value to compare with.
109This is useful to match on `term`s when there are multiple possible cases in a head-tagged union.
99This is useful to match on `term`s when there are multiple possible cases in a head-tagged union.
112−const : Deconstructor (a -> a) a -> a -> Deconstructor c c
102+const : Deconstructor a -> a -> Deconstructor ()
113−const (Deconstructor f) value =
103+const f value noun =
114− Deconstructor
104+ case f noun of
115− (\noun c ->
105+ Just a ->
116− case f noun identity of
118− if a == value then
106+ if a == value then
124− Nothing ->
112+ Nothing ->
129−{-| Extracts a `cord` at the current location.
116+{-| Extracts a `BigInt`.
131−cord : Deconstructor (String -> a) a
118+bigint : Deconstructor BigInt
135− case x of
120+ case x of
136− Atom bs ->
121+ Atom bs ->
137− BD.decode (BD.string (Bytes.width bs)) bs
122+ BigInt.Bytes.decode bs |> Just
145−{-| Extracts a `tape` at the current location.
125+ Nothing
147−tape : Deconstructor (String -> a) a
149− list cord |> fmap String.concat
152−{-| Extracts a 32-bit unsigned `Int` at the given location.
128+{-| Extracts a 32-bit signed `Int`.
154−If the `Atom` at the current location is larger than 32 bits the the behaviour is undefined.
130+If the `Atom` is larger than 32 bits the the behaviour is undefined.
157−int : Deconstructor (Int -> a) a
163− (case Bytes.width bs of
165− BD.decode BD.unsignedInt8 bs
168− BD.decode (BD.unsignedInt16 LE) bs
171− BD.decode (BD.unsignedInt32 LE) (BE.encode (BE.sequence [ BE.bytes bs, BE.unsignedInt8 0 ]))
174− BD.decode (BD.unsignedInt32 LE) bs
186−{-| Extracts a `BigInt` at the current location.
188−bigint : Deconstructor (BigInt -> a) a
194− BigInt.Bytes.decode bs |> f |> Just
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.
206−signedInt : Deconstructor (Int -> a) a
133+signedInt : Deconstructor Int
207signedInt =
134signedInt =
211 if Bitwise.and 1 i == 1 then
138 if Bitwise.and 1 i == 1 then
212 -(Bitwise.shiftRightBy 1 (1 + i))
139 -(Bitwise.shiftRightBy 1 (1 + i))
@@ -216,105 +143,85 @@ signedInt =
219−{-| Extracts a 32-bit `Float` at the given location.
146+{-| Extracts a 32-bit `Float`.
221−float32 : Deconstructor (Float -> a) a
148+float32 : Deconstructor Float
222−float32 =
149+float32 x =
225− case x of
150+ case x of
226− Atom bs ->
151+ Atom bs ->
227− BD.decode (BD.float32 LE) bs
152+ BD.decode (BD.float32 LE) bs
230− Cell _ ->
154+ Cell _ ->
235−{-| Extracts a 64-bit `Float` at the given location.
158+{-| Extracts a 64-bit `Float`.
237−float64 : Deconstructor (Float -> a) a
160+float64 : Deconstructor Float
238−float64 =
161+float64 x =
241− case x of
162+ case x of
242− Atom bs ->
163+ Atom bs ->
243− BD.decode (BD.float64 LE) bs
164+ BD.decode (BD.float64 LE) bs
246− Cell _ ->
166+ Cell _ ->
251−{-| Extracts the raw `Byte`s of an `Atom` at the current location.
170+{-| Extracts the raw `Byte`s of an `Atom`.
253−bytes : Deconstructor (Bytes -> a) a
172+bytes : Deconstructor Bytes
257− case n of
174+ case n of
258− Atom bs ->
175+ Atom bs ->
259− f bs |> Just
176+ Just bs
261− Cell _ ->
178+ Cell _ ->
266−{-| Asserts the the `Atom` at the current position should be exactly `sig` (`~`).
182+{-| Asserts the the `Atom` should be exactly `sig` (`~`).
268−sig : Deconstructor a a
184+sig : Deconstructor ()
272− case n of
186+ case n of
273− Atom b ->
187+ Atom b ->
274− if (Bytes.Extra.toByteValues b |> List.filter (\x -> x /= 0)) == [] then
188+ if (Bytes.Extra.toByteValues b |> List.filter (\x -> x /= 0)) == [] then
280− Cell _ ->
194+ Cell _ ->
285−{-| Extracts a sig-terminated list of arbitrary elements at the current position.
198+{-| Extracts a sig-terminated list of arbitrary elements.
287The first argument is a `Deconstructor` of the elements of the list.
200The first argument is a `Deconstructor` of the elements of the list.
290−list : Deconstructor (a -> a) a -> Deconstructor (List a -> b) b
203+list : Deconstructor a -> Deconstructor (List a)
291−list (Deconstructor f) =
204+list f n =
292− Deconstructor
205+ let
293− (\n g ->
206+ go n_ =
296− case n_ of
207+ case n_ of
297− Atom _ ->
208+ Atom _ ->
300− Cell ( el, tail ) ->
211+ Cell ( el, tail ) ->
301− Maybe.map2 (\a b -> a :: b) (f el identity) (go tail)
212+ Maybe.map2 (\a b -> a :: b) (f el) (go tail)
303− go n |> Maybe.map g
214+ go n
307−alt : Deconstructor a b -> Deconstructor a b -> Deconstructor a b
217+alt : Deconstructor a -> Deconstructor a -> Deconstructor a
308−alt (Deconstructor f) (Deconstructor g) =
218+alt f g n =
311− case f n a of
219+ case f n of
312− Just x ->
220+ Just x ->
315− Nothing ->
223+ Nothing ->
320{-| Try to execute all of the `Deconstructor`s in order until one succeeds.
227{-| Try to execute all of the `Deconstructor`s in order until one succeeds.
@@ -322,34 +229,24 @@ alt (Deconstructor f) (Deconstructor g) =
322This is especially useful for deconstructing head-tagged unions from Hoon.
229This is especially useful for deconstructing head-tagged unions from Hoon.
325−oneOf : List (Deconstructor a b) -> Deconstructor a b
232+oneOf : List (Deconstructor a) -> Deconstructor a
327 case l of
234 case l of
329− Deconstructor (\_ _ -> Nothing)
236+ always Nothing
331 x :: xs ->
238 x :: xs ->
332 alt x (oneOf xs)
239 alt x (oneOf xs)
335−{-| Extract the raw `Noun` at the current position.
340−tar : Deconstructor (Noun -> a) a
342− Deconstructor (\noun f -> Just (f noun))
345−{-| Ignore any value at the current position.
242+{-| Ignore any value.
347This is useful when you have a value you don't care about. `ignore` allows you to just skip the value.
244This is useful when you have a value you don't care about. `ignore` allows you to just skip the value.
350−ignore : Deconstructor a a
247+ignore : Deconstructor ()
352− Deconstructor (\_ f -> Just f)
249+ always (Just ())
355{-| Extracts a [`Cell`](https://developers.urbit.org/reference/glossary/cell) (pair) of two arbitrary values.
252{-| Extracts a [`Cell`](https://developers.urbit.org/reference/glossary/cell) (pair) of two arbitrary values.
@@ -357,17 +254,14 @@ ignore =
357Accepts two arbitrary `Deconstructor`s that form a Cell.
254Accepts two arbitrary `Deconstructor`s that form a Cell.
360−cell : Deconstructor a b -> Deconstructor b c -> Deconstructor a c
257+cell : Deconstructor a -> Deconstructor b -> Deconstructor ( a, b )
361−cell (Deconstructor l) (Deconstructor r) =
258+cell l r noun =
364− case noun of
259+ case noun of
365− Cell ( lhs, rhs ) ->
260+ Cell ( lhs, rhs ) ->
366− l lhs a |> Maybe.andThen (\b -> r rhs b)
261+ l lhs |> Maybe.andThen (\a -> r rhs |> Maybe.map (\b -> ( a, b )))
368− Atom _ ->
263+ Atom _ ->
373{-| Maps (applies) a function to all of the values deconstructed.
267{-| Maps (applies) a function to all of the values deconstructed.
@@ -375,11 +269,110 @@ cell (Deconstructor l) (Deconstructor r) =
375This is useful when you want to create a data type with extracted values as fields.
269This is useful when you want to create a data type with extracted values as fields.
378−map : a -> Deconstructor a b -> Deconstructor (b -> c) c
272+lazy : (() -> Deconstructor a) -> Deconstructor a
379−map a (Deconstructor f) =
273+lazy f noun =
380− Deconstructor (\noun g -> f noun a |> Maybe.map g)
274+ f () noun
277+{-| Maps over the result of the deconstructor.
383−fmap : (a -> b) -> Deconstructor (a -> c) c -> Deconstructor (b -> c) c
279+map : (a -> b) -> Deconstructor a -> Deconstructor b
281+ f noun |> Maybe.map g
284+{-| Extracts a `cord`.
286+cord : Deconstructor String
290+ BD.decode (BD.string (Bytes.width bs)) bs
296+{-| Extracts a `tape`.
384−fmap f (Deconstructor g) =
298+tape : Deconstructor String
300+ list cord |> map String.concat
303+{-| Extracts a 32-bit unsigned `Int`.
305+If the `Atom` is larger than 32 bits the the behaviour is undefined.
385− Deconstructor (\noun h -> g noun (f >> h))
308+int : Deconstructor Int
312+ case Bytes.width bs of
314+ BD.decode BD.unsignedInt8 bs
317+ BD.decode (BD.unsignedInt16 LE) bs
320+ BD.decode (BD.unsignedInt32 LE) (BE.encode (BE.sequence [ BE.bytes bs, BE.unsignedInt8 0 ]))
323+ BD.decode (BD.unsignedInt32 LE) bs
332+{-| Extract the raw `Noun`.
337+tar : Deconstructor Noun
342+{-| Debug a deconstructor.
343+If the deconstructor from the second argument fails then the failed nock will be printed to the console.
345+debug : (String -> String) -> Deconstructor a -> Deconstructor a
354+ log (prettyNoun noun)
359+prettyNoun : Noun -> String
371+ Cell ( lhs, rhs ) ->
373+ go False lhs ++ " " ++ go True rhs
376+ "[" ++ go False lhs ++ " " ++ go True rhs ++ "]"