From ee24a708605676f85ad74a978af0900087437048 Mon Sep 17 00:00:00 2001 From: Sigilante Date: Tue, 4 Aug 2026 10:53:03 -0600 Subject: [PATCH 1/3] docs: correct Hoon signatures that mislead readers into broken code Four arms whose documented behaviour no longer matches sys/hoon.hoon at urbit@08026c84b2. Every claim below was reproduced on a fake ship (v4.6 pill) rather than inferred from source. !@ "zappat" (rune/zap.md): branches are REVERSED. Upstream 87adc94d16 (2025-07-21, "!@ reverse polarity") changed the compile of %zppt from ?: to ?., so .q is now the does-not-exist branch and .r the exists branch. Verified both directions in dojo: =foo 42 !@(foo 'exists' 'does not exist') -> 'does not exist' !@(baz 'exists' 'does not exist') -> 'exists' The doc's Discussion and both example outputs asserted the opposite, so a reader following them writes inverted logic that still compiles. The examples are rewritten so the branch labels match the new order. No rationale is given upstream (empty commit body), so none is invented here. +trim (stdlib/4b.md): dry tape gate -> wet list gate. Now `|* [a=@ b=(list)]` / `^+ [p=b q=b]` (hoon.hoon:4317), not `|= [a=@ b=tape]` / `^- [p=tape q=tape]`. Both example OUTPUTS also changed, because the product is no longer cast to $tape: (trim 5 "lasok termun") -> [p=[i='l' t="asok"] q=[i=' ' t="termun"]] (trim 5 "zam") -> [p=[i='z' t="am"] q=~] Added a generic-list example and a note that only the inferred type and its printed form changed, not the value. +bif:by (stdlib/2i.md): now takes the key alone and never inserts. Signature went from `|* [b=* c=*]` to `|* b=*` (hoon.hoon:1445). Critically, the old two-argument call does NOT error: with sample b=*, the arguments arrive as the single cell [b c], so the map is split at that cell instead of at the key and the item at .b survives in the product. Verified: (~(bif by a) %b) -> splits at %b, %b excluded (correct) (~(bif by a) b+2) -> splits at [%b 2], returns a pair still containing [p=%b q=2] (silently wrong) The doc's own examples used the b+2 form, so they were demonstrating the broken call. Rewritten to the key-only form with verified output, plus a Discussion note that old callers fail silently rather than loudly. +peg (stdlib/1b.md): undocumented crash on a zero second argument. Source has `?< =(0 b)` alongside `?< =(0 a)` (hoon.hoon:213); the doc showed only the .a guard. Verified both (peg 4 0) and (peg 0 4) crash. Co-Authored-By: Claude Opus 5 --- content/hoon/rune/zap.md | 8 +++++--- content/hoon/stdlib/1b.md | 5 +++-- content/hoon/stdlib/2i.md | 42 ++++++++++++++++++++++----------------- content/hoon/stdlib/4b.md | 30 ++++++++++++++++++++-------- 4 files changed, 54 insertions(+), 31 deletions(-) diff --git a/content/hoon/rune/zap.md b/content/hoon/rune/zap.md index d0a0313c..65be502e 100644 --- a/content/hoon/rune/zap.md +++ b/content/hoon/rune/zap.md @@ -426,17 +426,19 @@ None #### Discussion -`.p` is a wing reference like `foo`, `bar.foo`, etc. If `.p` exists, `.q`. If `.p` does not exist, `.r`. Essentially, this is like `?:` for wing existence. +`.p` is a wing reference like `foo`, `bar.foo`, etc. If `.p` does *not* exist, `.q`. If `.p` does exist, `.r`. Essentially, this is like `?:` for wing existence, with the non-existence case first. + +Note the branch order: `.q` is the "missing" branch and `.r` is the "found" branch. This order was reversed in 2025; code written against the previous ordering will compile but take the wrong branch. #### Examples ``` > =foo 42 -> !@(foo 'exists' 'does not exist') +> !@(foo 'does not exist' 'exists') 'exists' -> !@(baz 'exists' 'does not exist') +> !@(baz 'does not exist' 'exists') 'does not exist' ``` diff --git a/content/hoon/stdlib/1b.md b/content/hoon/stdlib/1b.md index 50316dc8..833b72cf 100644 --- a/content/hoon/stdlib/1b.md +++ b/content/hoon/stdlib/1b.md @@ -228,9 +228,9 @@ Specifically, `+peg` just concatenates the bits of the input, excluding the most #### Accepts -`.a` is an `$atom`. +`.a` is an `$atom`. It must be non-zero; `+peg` crashes on `0`. -`.b` is an `$atom`. +`.b` is an `$atom`. It must also be non-zero; `+peg` crashes on `0`. #### Produces @@ -243,6 +243,7 @@ An `$atom`. ~/ %peg |= [a=@ b=@] ?< =(0 a) + ?< =(0 b) ^- @ ?- b %1 a diff --git a/content/hoon/stdlib/2i.md b/content/hoon/stdlib/2i.md index ab8f61d9..52c4af4f 100644 --- a/content/hoon/stdlib/2i.md +++ b/content/hoon/stdlib/2i.md @@ -207,15 +207,13 @@ See section [`2f`](2f.md) for more information on `$noun` ordering. Bifurcate. -Splits `+map` `.a` into two `+map`s `.l` and `.r`, which contain the items either side of key `.b` with value `.c` but not including the pair of key `.b` and value `.c`. +Splits `+map` `.a` into two `+map`s `.l` and `.r`, which contain the items either side of key `.b`, not including the item at key `.b`. #### Accepts `.a` is a `+map`, and is the sample of `+by`. -`.b` is a `$noun`. - -`.c` is a `$noun`. +`.b` is a `$noun`, the key to split at. #### Produces @@ -226,23 +224,19 @@ A cell of two `+map`s. ```hoon ++ bif ~/ %bif - |* [b=* c=*] - ^+ [l=a r=a] - =< + - |- ^+ a + |* b=* + |- ^+ [l=a r=a] ?~ a - [[b c] ~ ~] + [~ ~] ?: =(b p.n.a) - ?: =(c q.n.a) - a - a(n [b c]) + +.a ?: (gor b p.n.a) =+ d=$(a l.a) ?> ?=(^ d) - d(r a(l r.d)) + [l.d a(l r.d)] =+ d=$(a r.a) ?> ?=(^ d) - d(l a(r l.d)) + [a(r l.d) r.d] ``` #### Examples @@ -250,17 +244,29 @@ A cell of two `+map`s. ``` > =a (malt `(list [@tas @])`~[a+1 b+2 c+3 d+4 e+5]) -> (~(bif by a) b+2) -[l=[n=[p=%e q=5] l=~ r=~] r=[n=[p=%d q=4] l=~ r=[n=[p=%c q=3] l={[p=%a q=1]} r={}]]] +> (~(bif by a) %b) +[ l=[n=[p=%e q=5] l=~ r=~] + r=[n=[p=%d q=4] l=~ r=[n=[p=%c q=3] l=[n=[p=%a q=1] l=~ r=~] r=~]] +] -> `[(map @tas @) (map @tas @)]`(~(bif by a) b+2) -[{[p=%e q=5]} {[p=%d q=4] [p=%a q=1] [p=%c q=3]}] +> `[(map @tas @) (map @tas @)]`(~(bif by a) %b) +[ [n=[p=%e q=5] l=~ r=~] + [n=[p=%d q=4] l=~ r=[n=[p=%c q=3] l={[p=%a q=1]} r={}]] +] ``` #### Discussion Note that `+map`s are horizontally ordered by the [`+mug`](2e.md#mug) hash of their keys and vertically ordered by the double-`+mug` hash of their keys. This means bifurcating the `+map` `(malt ~[10^10 20^20 30^30 40^40 50^50])` at `30^30` will not produce `[{10^10 20^20} {40^40 50^50}]`, but rather `[{20^20} {10^10 40^40 50^50}]` due to the tree structure resulting from their `+mug` hashes. +`+bif:by` formerly took two arguments, a key `.b` and a value `.c`, and inserted +that pair if it was absent. It now takes the key alone and never inserts. Because +the sample is `b=*`, **calling it the old way does not raise an error** — the two +arguments are passed as the single cell `[b c]`, so the map is split at that cell +rather than at the key, and the item at `.b` is left in the result. Callers written +against the old signature therefore fail silently. For example, `(~(bif by a) b+2)` +now splits on the noun `[%b 2]` and returns a pair still containing `[p=%b q=2]`. + --- ### `+del:by` {#delby} diff --git a/content/hoon/stdlib/4b.md b/content/hoon/stdlib/4b.md index d40c27d1..48b7f75d 100644 --- a/content/hoon/stdlib/4b.md +++ b/content/hoon/stdlib/4b.md @@ -930,26 +930,26 @@ An `$atom`. ## `+trim` {#trim} -Tape split. +List split. -Split first `.a` characters off `$tape` `.b`. +Split first `.a` elements off `+list` `.b`. #### Accepts `.a` is an `$atom`. -`.b` is a `$tape`. +`.b` is a `+list` of any type. #### Produces -A cell of `$tape`s, `.p` and `.q`. +A cell of two `+list`s of the same type as `.b`, `.p` and `.q`. #### Source ```hoon ++ trim - |= [a=@ b=tape] - ^- [p=tape q=tape] + |* [a=@ b=(list)] + ^+ [p=b q=b] ?~ b [~ ~] ?: =(0 a) @@ -962,14 +962,28 @@ A cell of `$tape`s, `.p` and `.q`. ``` > (trim 5 "lasok termun") -[p="lasok" q=" termun"] +[p=[i='l' t="asok"] q=[i=' ' t="termun"]] ``` ``` > (trim 5 "zam") -[p="zam" q=""] +[p=[i='z' t="am"] q=~] ``` +``` +> (trim 2 `(list @ud)`~[1 2 3 4]) +[p=[i=1 t=~[2]] q=[i=3 t=~[4]]] +``` + +#### Discussion + +`+trim` was formerly a dry gate over `$tape` (`|= [a=@ b=tape]`) and is now a +wet gate over `+list`, so it works on a list of any type. One consequence is +that the product is no longer cast to `$tape`, so a tape argument produces a +list that pretty-prints structurally (`[i='l' t="asok"]`) rather than as +`"lasok"`. The value is unchanged; only the inferred type and its printed form +differ. + --- ## `+trip` {#trip} From c6fc7f9117f8ebdf6ba15d7fe28f6e7fab05f2a0 Mon Sep 17 00:00:00 2001 From: Sigilante Date: Tue, 4 Aug 2026 11:02:46 -0600 Subject: [PATCH 2/3] docs: correct scry, hash, and container signatures in stdlib reference Second batch for PR-3. Sources checked against urbit@08026c84b2. Items are marked below as ship-verified (reproduced on a fake ship, v4.6 pill) or source-verified (read from sys/hoon.hoon only). +mink / +mock / +mack (4n.md) -- ship-verified. The scry argument is now `$@(~ $-(^ (unit (unit))))`, not a bare gate (hoon.hoon:6021, :6182). Passing `~` means "no scry handler": ordinary formulas still evaluate, but a Nock 12 immediately blocks. Verified: (mink [[1 2] [0 2]] ~) -> [%0 product=1] (mink [0 [12 [1 0] [1 0]]] ~) -> [%2 trace=~] +mack correspondingly calls `(mink [sub fol] ~)` rather than `|~(^ ~)`. Documented the sentinel in +mink's Accepts with both cases. NOTE: +mong (4n.md:534) was checked and is UNCHANGED -- it still takes a bare gate (hoon.hoon:6256). Left alone deliberately. +shas (3d.md) -- ship-verified. Now `=/ len (max 32 (met 3 sal))` / `(shay len ...)`, not `(shax ...)` (hoon.hoon:3314). The audit characterised this as "differs for salts over 32 bytes"; that is wrong. Verified that a 1-byte salt and a 40-byte salt both agree with the old formula. The forms diverge only when the XOR result has fewer significant bytes than max(32, (met 3 sal)) -- i.e. when leading bytes cancel to zero. Constructed such a salt and confirmed divergence (27.383... vs 71.053...). +apt:in (2h.md) -- source-verified. Gained strict-inequality checks at every node: `&((gor n.a u.l) !=(...))` where the doc showed a bare `(gor n.a u.l)` (hoon.hoon:1224). NOTE: +apt:by in 2i.md was checked and is ALREADY CORRECT; the audit reported it as drifted. No change made there. +dif:by (2i.md) -- source-verified, knock-on from the +bif change. Dropped its `=+ b=a |@ ++ $` wrapper for a direct `|* b=_a`, and now calls `(bif p.n.b)` with one argument instead of `(bif p.n.b q.n.b)` (hoon.hoon:1478). Not previously connected to the +bif finding. +del:in / +del:by (2h.md, 2i.md) -- source-verified, source block only. Both gained `=> .(b `_?>(?=(^ a) ...)`b)` (hoon.hoon:1254, :1461). The audit claimed this makes a wrong-typed key a mint error rather than a silent no-op. That was NOT reproducible: `(~(del in s) "abc")` and `(~(del by mm) [1 2])` both return the container unchanged with no error. The source block is corrected; the behavioural claim is deliberately NOT documented, since it could not be demonstrated. DEFERRED: +inde / +iny (4f.md, 4i.md). Source has the new `|* [[ope=rule end=rule] sef=rule]` signature, but the shipping v4.6 pill does not: the documented one-argument example still works on the ship and the two-argument form fails. This change is in develop ([%zuse 408]) but not in the released kernel ([%zuse 409]), so the current docs are correct for anyone running released Vere. Blocked on the same 408-vs-409 decision as the kelvin updates. Co-Authored-By: Claude Opus 5 --- content/hoon/stdlib/2h.md | 9 +++++---- content/hoon/stdlib/2i.md | 32 +++++++++++++++----------------- content/hoon/stdlib/3d.md | 3 ++- content/hoon/stdlib/4n.md | 20 ++++++++++++++++---- 4 files changed, 38 insertions(+), 26 deletions(-) diff --git a/content/hoon/stdlib/2h.md b/content/hoon/stdlib/2h.md index 4074e3e4..d07c2330 100644 --- a/content/hoon/stdlib/2h.md +++ b/content/hoon/stdlib/2h.md @@ -147,10 +147,10 @@ A `$flag`. =| [l=(unit) r=(unit)] |. ^- ? ?~ a & - ?& ?~(l & (gor n.a u.l)) - ?~(r & (gor u.r n.a)) - ?~(l.a & ?&((mor n.a n.l.a) $(a l.a, l `n.a))) - ?~(r.a & ?&((mor n.a n.r.a) $(a r.a, r `n.a))) + ?& ?~(l & &((gor n.a u.l) !=(n.a u.l))) + ?~(r & &((gor u.r n.a) !=(u.r n.a))) + ?~(l.a & ?&((mor n.a n.l.a) !=(n.a n.l.a) $(a l.a, l `n.a))) + ?~(r.a & ?&((mor n.a n.r.a) !=(n.a n.r.a) $(a r.a, r `n.a))) == ``` @@ -267,6 +267,7 @@ A `+set`. ++ del ~/ %del |* b=* + => .(b `_?>(?=(^ a) n.a)`b) |- ^+ a ?~ a ~ diff --git a/content/hoon/stdlib/2i.md b/content/hoon/stdlib/2i.md index 52c4af4f..1584596a 100644 --- a/content/hoon/stdlib/2i.md +++ b/content/hoon/stdlib/2i.md @@ -291,6 +291,7 @@ A `+map`. ++ del ~/ %del |* b=* + => .(b `_?>(?=(^ a) p.n.a)`b) |- ^+ a ?~ a ~ @@ -344,23 +345,20 @@ A `+map`. ```hoon ++ dif ~/ %dif - =+ b=a - |@ - ++ $ - |- ^+ a - ?~ b - a - =+ c=(bif p.n.b q.n.b) - ?> ?=(^ c) - =+ d=$(a l.c, b l.b) - =+ e=$(a r.c, b r.b) - |- ^- [$?(~ _a)] - ?~ d e - ?~ e d - ?: (mor p.n.d p.n.e) - d(r $(d r.d)) - e(l $(e l.e)) - -- + |* b=_a + |- ^+ a + ?~ b + a + =+ c=(bif p.n.b) + ?> ?=(^ c) + =+ d=$(a l.c, b l.b) + =+ e=$(a r.c, b r.b) + |- ^- [$?(~ _a)] + ?~ d e + ?~ e d + ?: (mor p.n.d p.n.e) + d(r $(d r.d)) + e(l $(e l.e)) ``` #### Examples diff --git a/content/hoon/stdlib/3d.md b/content/hoon/stdlib/3d.md index 60b196dc..d2a454b1 100644 --- a/content/hoon/stdlib/3d.md +++ b/content/hoon/stdlib/3d.md @@ -130,7 +130,8 @@ Produces an `$atom` by using SHA-256 plus a salt input. The [bitwise XOR](2d.md) ++ shas ~/ %shas |= [sal=@ ruz=@] - (shax (mix sal (shax ruz))) + =/ len (max 32 (met 3 sal)) + (shay len (mix sal (shax ruz))) ``` #### Examples diff --git a/content/hoon/stdlib/4n.md b/content/hoon/stdlib/4n.md index 9a494ef6..d151000f 100644 --- a/content/hoon/stdlib/4n.md +++ b/content/hoon/stdlib/4n.md @@ -37,7 +37,7 @@ The `+unit` of a `$noun`. ++ mack |= [sub=* fol=*] ^- (unit) - =/ ton (mink [sub fol] |~(^ ~)) + =/ ton (mink [sub fol] ~) ?.(?=(%0 -.ton) ~ `product.ton) ``` @@ -94,7 +94,19 @@ Note that the gate is expected to return a result of type `(unit (unit))`. A nul `.formula` is the formula as a `$noun`. -`+scry` is an `%iron` gate invoked with Nock operator 12. +`+scry` is either `~`, or an `%iron` gate invoked with Nock operator 12. + +Passing `~` means "no scry handler is available". A formula that never performs a +Nock 12 evaluates normally; one that does immediately produces `[%2 trace]`, the +same block result as an unavailable read. For example: + +``` +> (mink [[1 2] [0 2]] ~) +[%0 product=1] + +> (mink [0 [12 [1 0] [1 0]]] ~) +[%2 trace=~] +``` #### Produces @@ -106,7 +118,7 @@ A `$tone`. ++ mink !. ~/ %mink |= $: [subject=* formula=*] - scry=$-(^ (unit (unit))) + scry=$@(~ $-(^ (unit (unit)))) == =| trace=(list [@ta *]) |^ ^- tone @@ -316,7 +328,7 @@ The `+unit` of a `$noun`. ```hoon ++ mock - |= [[sub=* fol=*] gul=$-(^ (unit (unit)))] + |= [[sub=* fol=*] gul=$@(~ $-(^ (unit (unit))))] (mook (mink [sub fol] gul)) ``` From 47ba9afe75bf891d15e672eab9f350709521e1ff Mon Sep 17 00:00:00 2001 From: Sigilante Date: Tue, 4 Aug 2026 11:35:50 -0600 Subject: [PATCH 3/3] docs: update +inde/+iny for the current kernel; regenerate examples on 408 Follow-up to the previous two PR-3 commits. These were deferred because they could not be verified on the pill I had booted; that pill was one kelvin behind. Re-verified on a fake ship booted from urbit-408k-rc1.pill, which reports [%zuse 408] -- the current kernel. (Kelvin counts down, so 408 is newer than the 409 of the v4.6 pill used earlier.) +inde (4f.md): signature changed from `|* sef=rule` to `|* [[ope=rule end=rule] sef=rule]` (hoon.hoon:4910, upstream d5af20fec1, 2025-12-17, shipped to develop in the 408 merge a92492ed4b). The body was rewritten as well. The documented one-argument call now fails to compile: (inde (star ...)) -> mull-grow / -find.sef Signature, body, Accepts and the worked example are all replaced. The new example was verified verbatim on the ship: > `tape`(scan "\"\"\"\0afoo\0abar\0a\"\"\"" (inde [(jest '\"\"\"') (jest '\"\"\"')] (star ;~(pose prn (just `@`10))))) "foo\0abar" The delimiter form is not invented: it mirrors the kernel's own use in +quote-innards (hoon.hoon:11842) for parsing \"\"\" block strings, which is the only call site in the tree. Confirmed `'\"\"\"'` and `(@t 0x22.2222)` are the same cord before writing the literal form. +iny (4i.md): source is now just `++ iny inde` (hoon.hoon:5258); the doc carried a stale 19-line copy of the old +inde body. Replaced with the one-line source, a pointer to +inde, and a verified example. +bif:by (2i.md): examples regenerated on 408. Under the newer kernel the cast product pretty-prints as maps rather than structurally, so the corrected call now yields exactly what the docs had wrongly attributed to the old two-argument form: > `[(map @tas @) (map @tas @)]`(~(bif by a) %b) [{[p=%e q=5]} {[p=%d q=4] [p=%a q=1] [p=%c q=3]}] The silent-failure note now carries its own captured output, which shows [p=%b q=2] still present in the product: > `[(map @tas @) (map @tas @)]`(~(bif by a) b+2) [{[p=%e q=5] [p=%b q=2] [p=%d q=4] [p=%a q=1]} {[p=%c q=3]}] Re-verified unchanged on 408: !@ polarity, +trim product and printing, +peg crash on a zero argument, +mink's ~ scry sentinel yielding [%2 trace=~]. Co-Authored-By: Claude Opus 5 --- content/hoon/stdlib/2i.md | 17 +++++++---- content/hoon/stdlib/4f.md | 61 ++++++++++++++++++++++++++++----------- content/hoon/stdlib/4i.md | 30 +++++-------------- 3 files changed, 63 insertions(+), 45 deletions(-) diff --git a/content/hoon/stdlib/2i.md b/content/hoon/stdlib/2i.md index 1584596a..050f5ad6 100644 --- a/content/hoon/stdlib/2i.md +++ b/content/hoon/stdlib/2i.md @@ -246,13 +246,11 @@ A cell of two `+map`s. > (~(bif by a) %b) [ l=[n=[p=%e q=5] l=~ r=~] - r=[n=[p=%d q=4] l=~ r=[n=[p=%c q=3] l=[n=[p=%a q=1] l=~ r=~] r=~]] + r=[n=[p=%d q=4] l=~ r=[n=[p=%c q=3] l={[p=%a q=1]} r={}]] ] > `[(map @tas @) (map @tas @)]`(~(bif by a) %b) -[ [n=[p=%e q=5] l=~ r=~] - [n=[p=%d q=4] l=~ r=[n=[p=%c q=3] l={[p=%a q=1]} r={}]] -] +[{[p=%e q=5]} {[p=%d q=4] [p=%a q=1] [p=%c q=3]}] ``` #### Discussion @@ -264,8 +262,15 @@ that pair if it was absent. It now takes the key alone and never inserts. Becaus the sample is `b=*`, **calling it the old way does not raise an error** — the two arguments are passed as the single cell `[b c]`, so the map is split at that cell rather than at the key, and the item at `.b` is left in the result. Callers written -against the old signature therefore fail silently. For example, `(~(bif by a) b+2)` -now splits on the noun `[%b 2]` and returns a pair still containing `[p=%b q=2]`. +against the old signature therefore fail silently. For example: + +``` +> `[(map @tas @) (map @tas @)]`(~(bif by a) b+2) +[{[p=%e q=5] [p=%b q=2] [p=%d q=4] [p=%a q=1]} {[p=%c q=3]}] +``` + +The map is split on the noun `[%b 2]`, and `[p=%b q=2]` is still present in the +result rather than having been removed. --- diff --git a/content/hoon/stdlib/4f.md b/content/hoon/stdlib/4f.md index 240e49d4..3d92e978 100644 --- a/content/hoon/stdlib/4f.md +++ b/content/hoon/stdlib/4f.md @@ -432,11 +432,18 @@ A `$rule`. Indentation block. -Apply `$rule` to indented block starting at current column number, omitting the leading whitespace. +Apply `$rule` to a delimited, indented block starting at the current column number, omitting the leading whitespace. #### Accepts -`.sef` is a `$rule`. +`.ope` is a `$rule` matching the block's opening delimiter. + +`.end` is a `$rule` matching the block's closing delimiter. + +`.sef` is a `$rule` applied to the block's contents. + +The first two are passed together as a cell, so the call shape is +`(inde [ope end] sef)`. #### Produces @@ -445,36 +452,56 @@ A `$rule`. #### Source ```hoon -++ inde |* sef=rule - |= nail ^+ (sef) - =+ [har tap]=[p q]:+< +++ inde + |* [[ope=rule end=rule] sef=rule] + |= tub=nail ^+ (sef) + =* har p.tub + =* tap q.tub =+ lev=(fil 3 (dec q.har) ' ') =+ eol=(just `@t`10) - =+ =- roq=((star ;~(pose prn ;~(sfix eol (jest lev)) -)) har tap) - ;~(simu ;~(plug eol eol) eol) + =+ and=;~(plug eol (jest lev) end) + :: get block contents without the indenting spaces + :: + =/ roq + %. tub + =/ led + ;~ pose + ;~(sfix eol (jest lev)) :: eat leading spaces + ;~(simu ;~(plug eol eol) eol) :: allow empty lines + == + ;~ pfix ope led + %- star + ;~(less and ;~(pose prn led)) + == ?~ q.roq roq - =+ vex=(sef har(q 1) p.u.q.roq) + :: parse block contents fully + :: + =+ vex=((full sef) har(q 1) p.u.q.roq) + :: indent hair, produce result, continue after block + :: =+ fur=p.vex(q (add (dec q.har) q.p.vex)) ?~ q.vex vex(p fur) - =- vex(p fur, u.q -) - :+ &3.vex - &4.vex(q.p (add (dec q.har) q.p.&4.vex)) - =+ res=|4.vex - |- ?~ res |4.roq - ?. =(10 -.res) [-.res $(res +.res)] - (welp [`@t`10 (trip lev)] $(res +.res)) + =+ vux=(and p.roq q.q.u.q.roq) + ?~ q.vux vux + [p.vux ~ p.u.q.vex q.u.q.vux] ``` #### Examples ``` -> `tape`(scan " foo\0a bar" ;~(pfix ace ace ace (inde (star ;~(pose prn (just '\0a')))))) +> `tape`(scan "\"\"\"\0afoo\0abar\0a\"\"\"" (inde [(jest '"""') (jest '"""')] (star ;~(pose prn (just `@`10))))) "foo\0abar" ``` #### Discussion -Note the amount of indentation whitespace to be stripped from the beginning of each line is determined by the value of `.q` (the column) in the `$hair` when `+inde` is first called. This means something like the `+pfix` expression in the example above is necessary to set the level of indentation. Additionally, the `$rule` given to `+inde` must consume the whole line including the line ending. +Note the amount of indentation whitespace to be stripped from the beginning of each line is determined by the value of `.q` (the column) in the `$hair` when `+inde` is first called. Additionally, the `$rule` given to `+inde` must consume the whole line including the line ending. + +`+inde` previously took only `.sef` and was called as `(inde sef)`, with the +indentation level established by a preceding `+pfix`. It was rewritten to take +explicit opening and closing delimiters; the one-argument call now fails to +compile with `mull-grow` / `-find.sef`. The kernel uses it this way to parse +`"""` block strings (see `+quote-innards` in `sys/hoon.hoon`). --- diff --git a/content/hoon/stdlib/4i.md b/content/hoon/stdlib/4i.md index e8e6a4f8..2e38016e 100644 --- a/content/hoon/stdlib/4i.md +++ b/content/hoon/stdlib/4i.md @@ -737,11 +737,15 @@ Parse a single hexadecimal digit. Indentation block. -Apply `$rule` to indented block starting at current column number, omitting the leading whitespace. +Apply `$rule` to a delimited, indented block starting at the current column number, omitting the leading whitespace. + +`+iny` is an alias for [`+inde`](4f.md#inde); see there for details. #### Accepts -`sef` is a `$rule` +`.ope` and `.end` are `$rule`s matching the block's opening and closing +delimiters, passed together as a cell; `.sef` is a `$rule` applied to the +contents. The call shape is `(iny [ope end] sef)`. #### Produces @@ -750,31 +754,13 @@ A `$rule`. #### Source ```hoon -++ iny - |* sef=rule - |= nail ^+ (sef) - =+ [har tap]=[p q]:+< - =+ lev=(fil 3 (dec q.har) ' ') - =+ eol=(just `@t`10) - =+ =- roq=((star ;~(pose prn ;~(sfix eol (jest lev)) -)) har tap) - ;~(simu ;~(plug eol eol) eol) - ?~ q.roq roq - =+ vex=(sef har(q 1) p.u.q.roq) - =+ fur=p.vex(q (add (dec q.har) q.p.vex)) - ?~ q.vex vex(p fur) - =- vex(p fur, u.q -) - :+ &3.vex - &4.vex(q.p (add (dec q.har) q.p.&4.vex)) - =+ res=|4.vex - |- ?~ res |4.roq - ?. =(10 -.res) [-.res $(res +.res)] - (welp [`@t`10 (trip lev)] $(res +.res)) +++ iny inde ``` #### Examples ``` -> `tape`(scan " foo\0a bar" ;~(pfix ace ace ace (iny (star ;~(pose prn (just '\0a')))))) +> `tape`(scan "\"\"\"\0afoo\0abar\0a\"\"\"" (iny [(jest '"""') (jest '"""')] (star ;~(pose prn (just `@`10))))) "foo\0abar" ```