~/bend-docscommunity

parse.bend source

parse.bend on the hub · documented module

import Baseimport ./books.bend as Booksimport ./normalize.bend as Normimport ./share.bend as Shareimport ./complete.bend as Compimport ./context.bend as Ctximport ./route.bend as Routeimport ./ref_token.bend as Tokdef char1(+c: Char) -> String:  String.from_list(c <> Nil{})def is_book_stop_flags(+has_letter: Bool, is_d: Bool, is_a: Bool, is_s: Bool) -> Bool:  match is_d:    case True{}:      has_letter    case False{}:      match is_a:        case True{}:          False{}        case False{}:          match is_s:            case True{}:              False{}            case False{}:              True{}def is_book_stop(+has_letter: Bool, +c: Char) -> Bool:  is_book_stop_flags(has_letter, Char.is_digit(c), Char.is_alpha(c), Char.is_space(c))def next_has_letter_go(has_letter: Bool, is_a: Bool) -> Bool:  match has_letter:    case True{}:      True{}    case False{}:      is_adef next_has_letter(+has_letter: Bool, +c: Char) -> Bool:  next_has_letter_go(has_letter, Char.is_alpha(c))type BookSt is Data:  BookCheck{}  BookDecide{stop: Bool}  BookTake{}def take_book_go(fuel: Nat, st: BookSt, rest: String, acc: String, +has_letter: Bool) -> String & String:  match fuel:    case 0n:      (acc, rest)    case 1n+p:      match st:        case BookCheck{}:          match rest:            case SNil{}:              (acc, "")            case SCon{+h, +t}:              take_book_go(p, BookDecide{is_book_stop(has_letter, h)}, rest, acc, has_letter)        case BookDecide{stop}:          match stop:            case True{}:              (acc, rest)            case False{}:              take_book_go(p, BookTake{}, rest, acc, has_letter)        case BookTake{}:          match rest:            case SNil{}:              (acc, "")            case SCon{+h, +t}:              take_book_go(p, BookCheck{}, t, String.append(acc, char1(h)), next_has_letter(has_letter, h))def take_book(+s: String) -> String & String:  take_book_go(Nat.add(Nat.mul(3n, String.length(s)), 3n), BookCheck{}, s, "", False{})type DigSt is Data:  DigCheck{}  DigDecide{is_d: Bool}  DigTake{}def take_digits_go(fuel: Nat, st: DigSt, rest: String, acc: String) -> String & String:  match fuel:    case 0n:      (acc, rest)    case 1n+p:      match st:        case DigCheck{}:          match rest:            case SNil{}:              (acc, "")            case SCon{+h, +t}:              take_digits_go(p, DigDecide{Char.is_digit(h)}, rest, acc)        case DigDecide{is_d}:          match is_d:            case False{}:              (acc, rest)            case True{}:              take_digits_go(p, DigTake{}, rest, acc)        case DigTake{}:          match rest:            case SNil{}:              (acc, "")            case SCon{+h, +t}:              take_digits_go(p, DigCheck{}, t, String.append(acc, char1(h)))def take_digits(+s: String) -> String & String:  take_digits_go(Nat.add(Nat.mul(3n, String.length(s)), 3n), DigCheck{}, s, "")def is_colon_or_dot(+c: Char) -> Bool:  Bool.or(Char.is_eq(c, ':'), Char.is_eq(c, '.'))def drop_head(s: String) -> String:  match s:    case SNil{}:      ""    case SCon{h, t}:      tdef drop_cv_sep_go(+s: String, drop: Bool) -> String:  match drop:    case True{}:      drop_head(s)    case False{}:      sdef drop_cv_sep(+s: String) -> String:  match s:    case SNil{}:      ""    case SCon{+h, +t}:      drop_cv_sep_go(s, is_colon_or_dot(h))def drop_dash_go(+s: String, drop: Bool) -> String:  match drop:    case True{}:      drop_head(s)    case False{}:      sdef drop_dash(+s: String) -> String:  match s:    case SNil{}:      ""    case SCon{+h, +t}:      drop_dash_go(s, Char.is_eq(h, '-'))def is_dash_head(s: String) -> Bool:  match s:    case SNil{}:      False{}    case SCon{h, t}:      Char.is_eq(h, '-')type RangeKind is Data:  Single{}  Chapter{}  SameChapter{}  ChapterRange{}  CrossReference{}type ParseErr is Data:  Empty{}  BadBook{}  BadFormat{}  BadNumber{}  CapChapter{book: String, max: U32, got: U32}  CapVerse{book: String, chapter: U32, max: U32, got: U32}  Reversed{}type Parsed is Data:  Parsed{    canonical: String,    display: String,    book: String,    end_book: String,    chapter: U32,    verse: Maybe<&2, U32>,    end_chapter: U32,    end_verse: Maybe<&2, U32>,    kind: RangeKind  }def require_u32_nz(n: U32, z: Bool) -> Result<ParseErr, U32>:  match z:    case True{}:      Fail{BadNumber{}}    case False{}:      Done{n}def require_u32_go(m: Maybe<&2, U32>) -> Result<ParseErr, U32>:  match m:    case None{}:      Fail{BadNumber{}}    case Some{+n}:      require_u32_nz(n, U32.is_zero(n))def require_u32(s: String) -> Result<ParseErr, U32>:  require_u32_go(U32.read(String.trim(s)))def check_ch_le(+book: String, +ch: U32, +max: U32, ok: Bool) -> Result<ParseErr, Unit>:  match ok:    case True{}:      Done{Unit{}}    case False{}:      Fail{CapChapter{book, max, ch}}def check_ch_go(+book: String, +ch: U32, m: Maybe<&2, U32>) -> Result<ParseErr, Unit>:  match m:    case None{}:      Fail{BadBook{}}    case Some{+max}:      check_ch_le(book, ch, max, U32.is_le(ch, max))def check_ch(+book: String, +ch: U32) -> Result<ParseErr, Unit>:  check_ch_go(book, ch, Books.chapter_count(book))def check_vs_le(+book: String, +ch: U32, +v: U32, +max: U32, ok: Bool) -> Result<ParseErr, Unit>:  match ok:    case True{}:      Done{Unit{}}    case False{}:      Fail{CapVerse{book, ch, max, v}}def check_vs_go(+book: String, +ch: U32, +v: U32, m: Maybe<&2, U32>) -> Result<ParseErr, Unit>:  match m:    case None{}:      Fail{BadNumber{}}    case Some{+max}:      check_vs_le(book, ch, v, max, U32.is_le(v, max))def check_vs(+book: String, +ch: U32, +v: U32) -> Result<ParseErr, Unit>:  check_vs_go(book, ch, v, Books.verse_count(book, ch))def fmt_osis_part(+book: String, +ch: U32, v: Maybe<&2, U32>) -> String:  match v:    case None{}:      String.append(String.append(book, "."), U32.show(ch))    case Some{n}:      String.append(        String.append(String.append(String.append(book, "."), U32.show(ch)), "."),        U32.show(n)      )def fmt_same_canonical(+book: String, +ch: U32, a: U32, ev: Maybe<&2, U32>) -> String:  match ev:    case None{}:      fmt_osis_part(book, ch, Some{a})    case Some{b}:      String.append(String.append(fmt_osis_part(book, ch, Some{a}), "-"), U32.show(b))def fmt_canonical_same(+book: String, +ch: U32, v: Maybe<&2, U32>, ev: Maybe<&2, U32>) -> String:  match v:    case None{}:      fmt_osis_part(book, ch, None{})    case Some{a}:      fmt_same_canonical(book, ch, a, ev)def fmt_canonical_cross(+book: String, +end_book: String, +ch: U32, +v: Maybe<&2, U32>, +ech: U32, +ev: Maybe<&2, U32>) -> String:  String.append(String.append(fmt_osis_part(book, ch, v), "-"), fmt_osis_part(end_book, ech, ev))def fmt_canonical(+book: String, +end_book: String, +ch: U32, +v: Maybe<&2, U32>, +ech: U32, +ev: Maybe<&2, U32>, +kind: RangeKind) -> String:  match kind:    case Single{}:      fmt_osis_part(book, ch, v)    case Chapter{}:      fmt_osis_part(book, ch, None{})    case SameChapter{}:      fmt_canonical_same(book, ch, v, ev)    case ChapterRange{}:      String.append(String.append(fmt_osis_part(book, ch, None{}), "-"), U32.show(ech))    case CrossReference{}:      fmt_canonical_cross(book, end_book, ch, v, ech, ev)def fmt_display_verse(+name: String, +ch: U32, v: Maybe<&2, U32>) -> String:  match v:    case None{}:      String.append(String.append(name, " "), U32.show(ch))    case Some{n}:      String.append(        String.append(String.append(String.append(name, " "), U32.show(ch)), ":"),        U32.show(n)      )def fmt_display_same2(+name: String, +ch: U32, a: U32, ev: Maybe<&2, U32>) -> String:  match ev:    case None{}:      fmt_display_verse(name, ch, Some{a})    case Some{b}:      String.append(        String.append(          String.append(String.append(String.append(name, " "), U32.show(ch)), ":"),          U32.show(a)        ),        String.append("-", U32.show(b))      )def fmt_display_same(+name: String, +ch: U32, v: Maybe<&2, U32>, ev: Maybe<&2, U32>) -> String:  match v:    case None{}:      name    case Some{a}:      fmt_display_same2(name, ch, a, ev)def fmt_cv_part(+ch: U32, v: Maybe<&2, U32>) -> String:  match v:    case None{}:      U32.show(ch)    case Some{n}:      String.append(String.append(U32.show(ch), ":"), U32.show(n))def fmt_display_cross_same(+name: String, +ch: U32, +v: Maybe<&2, U32>, +ech: U32, +ev: Maybe<&2, U32>) -> String:  String.append(    String.append(String.append(name, " "), fmt_cv_part(ch, v)),    String.append("-", fmt_cv_part(ech, ev))  )def fmt_display_cross_diff(+nb: String, +neb: String, +ch: U32, +v: Maybe<&2, U32>, +ech: U32, +ev: Maybe<&2, U32>) -> String:  String.append(    String.append(String.append(nb, " "), fmt_cv_part(ch, v)),    String.append(String.append("-", String.append(neb, " ")), fmt_cv_part(ech, ev))  )def fmt_display_cross_go(+same: Bool, +book: String, +end_book: String, +ch: U32, +v: Maybe<&2, U32>, +ech: U32, +ev: Maybe<&2, U32>) -> String:  match same:    case True{}:      fmt_display_cross_same(Books.display_name(book), ch, v, ech, ev)    case False{}:      fmt_display_cross_diff(Books.display_name(book), Books.display_name(end_book), ch, v, ech, ev)def fmt_display_cross(+book: String, +end_book: String, +ch: U32, +v: Maybe<&2, U32>, +ech: U32, +ev: Maybe<&2, U32>) -> String:  fmt_display_cross_go(String.eq(book, end_book), book, end_book, ch, v, ech, ev)def fmt_display_with(+book: String, +end_book: String, +ch: U32, +v: Maybe<&2, U32>, +ech: U32, +ev: Maybe<&2, U32>, +kind: RangeKind) -> String:  match kind:    case Single{}:      fmt_display_verse(Books.display_name(book), ch, v)    case Chapter{}:      String.append(String.append(Books.display_name(book), " "), U32.show(ch))    case SameChapter{}:      fmt_display_same(Books.display_name(book), ch, v, ev)    case ChapterRange{}:      String.append(        String.append(String.append(String.append(Books.display_name(book), " "), U32.show(ch)), "-"),        U32.show(ech)      )    case CrossReference{}:      fmt_display_cross(book, end_book, ch, v, ech, ev)def fmt_display(+book: String, +end_book: String, +ch: U32, +v: Maybe<&2, U32>, +ech: U32, +ev: Maybe<&2, U32>, +kind: RangeKind) -> String:  fmt_display_with(book, end_book, ch, v, ech, ev, kind)def mk_parsed(+book: String, +end_book: String, +ch: U32, +v: Maybe<&2, U32>, +ech: U32, +ev: Maybe<&2, U32>, +kind: RangeKind) -> Parsed:  Parsed{    fmt_canonical(book, end_book, ch, v, ech, ev, kind),    fmt_display(book, end_book, ch, v, ech, ev, kind),    book, end_book, ch, v, ech, ev, kind  }def mk_same(+book: String, +ch: U32, +v: Maybe<&2, U32>, +ech: U32, +ev: Maybe<&2, U32>, +kind: RangeKind) -> Parsed:  mk_parsed(book, book, ch, v, ech, ev, kind)def finish_ch_ok(+book: String, +ch: U32, +ech: U32, +kind: RangeKind, rev: Bool) -> Result<ParseErr, Parsed>:  match rev:    case True{}:      Fail{Reversed{}}    case False{}:      Done{mk_same(book, ch, None{}, ech, None{}, kind)}def finish_ch_after(+book: String, +ch: U32, +ech: U32,  +kind: RangeKind, r: Result<ParseErr, Unit>) -> Result<ParseErr, Parsed>:  match r:    case Fail{e}:      Fail{e}    case Done{_}:      finish_ch_ok(book, ch, ech, kind, U32.is_lt(ech, ch))def finish_ch_match(+book: String, +ch: U32, +ech: U32, +kind: RangeKind, r: Result<ParseErr, Unit>) -> Result<ParseErr, Parsed>:  match r:    case Fail{e}:      Fail{e}    case Done{_}:      finish_ch_after(book, ch, ech, kind, check_ch(book, ech))def finish_ch(+book: String, +ch: U32, +ech: U32, +kind: RangeKind) -> Result<ParseErr, Parsed>:  finish_ch_match(book, ch, ech, kind, check_ch(book, ch))def finish_vs_end_ok(+book: String, +ch: U32, +vn: U32, +en: U32, rev: Bool) -> Result<ParseErr, Parsed>:  match rev:    case True{}:      Fail{Reversed{}}    case False{}:      Done{mk_same(book, ch, Some{vn}, ch, Some{en}, SameChapter{})}def finish_vs_end(+book: String, +ch: U32, +vn: U32, +en: U32, r: Result<ParseErr, Unit>) -> Result<ParseErr, Parsed>:  match r:    case Fail{e}:      Fail{e}    case Done{_}:      finish_vs_end_ok(book, ch, vn, en, U32.is_lt(en, vn))def finish_vs_ev(+book: String, +ch: U32, +vn: U32, ev: Maybe<&2, U32>) -> Result<ParseErr, Parsed>:  match ev:    case None{}:      Done{mk_same(book, ch, Some{vn}, ch, Some{vn}, Single{})}    case Some{+en}:      finish_vs_end(book, ch, vn, en, check_vs(book, ch, en))def finish_vs_after_vn(+book: String, +ch: U32, +vn: U32, ev: Maybe<&2, U32>, r: Result<ParseErr, Unit>) -> Result<ParseErr, Parsed>:  match r:    case Fail{e}:      Fail{e}    case Done{_}:      finish_vs_ev(book, ch, vn, ev)def finish_vs_match(+book: String, +ch: U32, +vn: U32, ev: Maybe<&2, U32>, r: Result<ParseErr, Unit>) -> Result<ParseErr, Parsed>:  match r:    case Fail{e}:      Fail{e}    case Done{_}:      finish_vs_after_vn(book, ch, vn, ev, check_vs(book, ch, vn))def finish_vs(+book: String, +ch: U32, +vn: U32, ev: Maybe<&2, U32>) -> Result<ParseErr, Parsed>:  finish_vs_match(book, ch, vn, ev, check_ch(book, ch))def is_cv_sep_head(s: String) -> Bool:  match s:    case SNil{}:      False{}    case SCon{+h, t}:      is_colon_or_dot(h)def is_book_num_char(+c: Char) -> Bool:  Bool.or(    Char.is_eq(c, '1'),    Bool.or(Char.is_eq(c, '2'), Char.is_eq(c, '3'))  )def alpha_head_s(s: String) -> Bool:  match s:    case SNil{}:      False{}    case SCon{+h, t}:      Char.is_alpha(h)def bookish_head(s: String) -> Bool:  match s:    case SNil{}:      False{}    case SCon{+h, +t}:      Bool.or(Char.is_alpha(h), Bool.and(is_book_num_char(h), alpha_head_s(t)))def verse_ord_start(v: Maybe<&2, U32>) -> U32:  match v:    case None{}:      0    case Some{n}:      ndef verse_ord_end(v: Maybe<&2, U32>) -> U32:  match v:    case None{}:      4294967295    case Some{n}:      ndef rev_same_book(+sc: U32, +sv: Maybe<&2, U32>, +ec: U32, +ev: Maybe<&2, U32>, ch_lt: Bool, ch_eq: Bool) -> Bool:  match ch_lt:    case True{}:      True{}    case False{}:      match ch_eq:        case False{}:          False{}        case True{}:          U32.is_lt(verse_ord_end(ev), verse_ord_start(sv))def rev_orders(+so: U32, +eo: U32, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, +ev: Maybe<&2, U32>, book_lt: Bool, book_eq: Bool) -> Bool:  match book_lt:    case True{}:      True{}    case False{}:      match book_eq:        case False{}:          False{}        case True{}:          rev_same_book(sc, sv, ec, ev, U32.is_lt(ec, sc), U32.is_eq(ec, sc))def rev_orders_m(+so: U32, eo_m: Maybe<&2, U32>, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, +ev: Maybe<&2, U32>) -> Result<ParseErr, Bool>:  match eo_m:    case None{}:      Fail{BadBook{}}    case Some{+eo}:      Done{rev_orders(so, eo, sc, sv, ec, ev, U32.is_lt(eo, so), U32.is_eq(eo, so))}def rev_books_m(so_m: Maybe<&2, U32>, +eb: String, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, +ev: Maybe<&2, U32>) -> Result<ParseErr, Bool>:  match so_m:    case None{}:      Fail{BadBook{}}    case Some{so}:      rev_orders_m(so, Books.book_order(eb), sc, sv, ec, ev)def is_reversed_cross(+sb: String, +sc: U32, +sv: Maybe<&2, U32>, +eb: String, +ec: U32, +ev: Maybe<&2, U32>) -> Result<ParseErr, Bool>:  rev_books_m(Books.book_order(sb), eb, sc, sv, ec, ev)def finish_cross_ok(+sb: String, +eb: String, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, +ev: Maybe<&2, U32>, rev: Bool) -> Result<ParseErr, Parsed>:  match rev:    case True{}:      Fail{Reversed{}}    case False{}:      Done{mk_parsed(sb, eb, sc, sv, ec, ev, CrossReference{})}def finish_cross_after_rev(+sb: String, +eb: String, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, +ev: Maybe<&2, U32>, r: Result<ParseErr, Bool>) -> Result<ParseErr, Parsed>:  match r:    case Fail{e}:      Fail{e}    case Done{rev}:      finish_cross_ok(sb, eb, sc, sv, ec, ev, rev)def finish_cross_ev(+sb: String, +eb: String, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, +ev: Maybe<&2, U32>, r: Result<ParseErr, Unit>) -> Result<ParseErr, Parsed>:  match r:    case Fail{e}:      Fail{e}    case Done{_}:      finish_cross_after_rev(sb, eb, sc, sv, ec, ev, is_reversed_cross(sb, sc, sv, eb, ec, ev))def finish_cross_ec_ev(ev: Maybe<&2, U32>, +sb: String, +eb: String, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32) -> Result<ParseErr, Parsed>:  match ev:    case None{}:      finish_cross_ev(sb, eb, sc, sv, ec, None{}, Done{Unit{}})    case Some{+en}:      finish_cross_ev(sb, eb, sc, sv, ec, Some{en}, check_vs(eb, ec, en))def finish_cross_ec(+sb: String, +eb: String, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, +ev: Maybe<&2, U32>, r: Result<ParseErr, Unit>) -> Result<ParseErr, Parsed>:  match r:    case Fail{e}:      Fail{e}    case Done{_}:      finish_cross_ec_ev(ev, sb, eb, sc, sv, ec)def finish_cross_sc(+sb: String, +eb: String, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, +ev: Maybe<&2, U32>, r: Result<ParseErr, Unit>) -> Result<ParseErr, Parsed>:  match r:    case Fail{e}:      Fail{e}    case Done{_}:      finish_cross_ec(sb, eb, sc, sv, ec, ev, check_ch(eb, ec))def finish_cross_sv_m(sv: Maybe<&2, U32>, +sb: String, +eb: String, +sc: U32, +ec: U32, +ev: Maybe<&2, U32>) -> Result<ParseErr, Parsed>:  match sv:    case None{}:      finish_cross_sc(sb, eb, sc, None{}, ec, ev, check_ch(sb, sc))    case Some{+vn}:      finish_cross_sc(sb, eb, sc, Some{vn}, ec, ev, check_vs(sb, sc, vn))def finish_cross_sv(+sb: String, +eb: String, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, +ev: Maybe<&2, U32>, r: Result<ParseErr, Unit>) -> Result<ParseErr, Parsed>:  match r:    case Fail{e}:      Fail{e}    case Done{_}:      finish_cross_sv_m(sv, sb, eb, sc, ec, ev)def finish_cross(+sb: String, +eb: String, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, +ev: Maybe<&2, U32>) -> Result<ParseErr, Parsed>:  finish_cross_sv(sb, eb, sc, sv, ec, ev, check_ch(sb, sc))def parse_end_verse_num(+sb: String, +eb: String, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, r: Result<ParseErr, U32>) -> Result<ParseErr, Parsed>:  match r:    case Fail{e}:      Fail{e}    case Done{en}:      finish_cross(sb, eb, sc, sv, ec, Some{en})def parse_end_verse_vs(empty_vs: Bool, +sb: String, +eb: String, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, +vs: String) -> Result<ParseErr, Parsed>:  match empty_vs:    case True{}:      Fail{BadFormat{}}    case False{}:      parse_end_verse_num(sb, eb, sc, sv, ec, require_u32(vs))def parse_end_verse_rest(rest_empty: Bool, +sb: String, +eb: String, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, +vs: String) -> Result<ParseErr, Parsed>:  match rest_empty:    case False{}:      Fail{BadFormat{}}    case True{}:      parse_end_verse_vs(String.is_empty(vs), sb, eb, sc, sv, ec, vs)def parse_end_verse_pair(+sb: String, +eb: String, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, pair: String & String) -> Result<ParseErr, Parsed>:  match pair:    case (+vs, rest2):      parse_end_verse_rest(String.is_empty(String.trim(rest2)), sb, eb, sc, sv, ec, vs)def parse_end_after_ch(+sb: String, +eb: String, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, +rest: String, empty: Bool, sep: Bool) -> Result<ParseErr, Parsed>:  match empty:    case True{}:      finish_cross(sb, eb, sc, sv, ec, None{})    case False{}:      match sep:        case True{}:          parse_end_verse_pair(sb, eb, sc, sv, ec, take_digits(drop_cv_sep(rest)))        case False{}:          Fail{BadFormat{}}def parse_end_ch_num(+sb: String, +eb: String, +sc: U32, +sv: Maybe<&2, U32>, +rest0: String, r: Result<ParseErr, U32>) -> Result<ParseErr, Parsed>:  match r:    case Fail{e}:      Fail{e}    case Done{ec}:      parse_end_after_ch(sb, eb, sc, sv, ec, String.trim(rest0), String.is_empty(String.trim(rest0)), is_cv_sep_head(String.trim(rest0)))def parse_end_tail_ch(empty: Bool, +sb: String, +eb: String, +sc: U32, +sv: Maybe<&2, U32>, +ch_s: String, +rest0: String) -> Result<ParseErr, Parsed>:  match empty:    case True{}:      Fail{BadFormat{}}    case False{}:      parse_end_ch_num(sb, eb, sc, sv, rest0, require_u32(ch_s))def parse_end_tail_pair(+sb: String, +eb: String, +sc: U32, +sv: Maybe<&2, U32>, pair: String & String) -> Result<ParseErr, Parsed>:  match pair:    case (+ch_s, rest0):      parse_end_tail_ch(String.is_empty(ch_s), sb, eb, sc, sv, ch_s, rest0)def parse_end_tail(+sb: String, +eb: String, +sc: U32, +sv: Maybe<&2, U32>, +tail: String) -> Result<ParseErr, Parsed>:  parse_end_tail_pair(sb, eb, sc, sv, take_digits(drop_cv_sep(String.trim(tail))))def parse_cross_second_book_code(+sb: String, +sc: U32, +sv: Maybe<&2, U32>, +rest: String, m: Maybe<&2, String>) -> Result<ParseErr, Parsed>:  match m:    case None{}:      Fail{BadFormat{}}    case Some{eb}:      parse_end_tail(sb, eb, sc, sv, rest)def parse_cross_second_book_pair(+sb: String, +sc: U32, +sv: Maybe<&2, U32>, pair: String & String) -> Result<ParseErr, Parsed>:  match pair:    case (book_raw, rest2):      parse_cross_second_book_code(sb, sc, sv, rest2, Books.resolve_alias(String.trim(book_raw)))def parse_cross_second_book(+sb: String, +sc: U32, +sv: Maybe<&2, U32>, +rest: String) -> Result<ParseErr, Parsed>:  parse_cross_second_book_pair(sb, sc, sv, take_book(rest))def parse_cross_cv_verse(+sb: String, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, r: Result<ParseErr, U32>) -> Result<ParseErr, Parsed>:  match r:    case Fail{e}:      Fail{e}    case Done{en}:      finish_cross(sb, sb, sc, sv, ec, Some{en})def parse_cross_cv_vs(empty_vs: Bool, +sb: String, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, +vs: String) -> Result<ParseErr, Parsed>:  match empty_vs:    case True{}:      Fail{BadFormat{}}    case False{}:      parse_cross_cv_verse(sb, sc, sv, ec, require_u32(vs))def parse_cross_cv_rest(rest_empty: Bool, +sb: String, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, +vs: String) -> Result<ParseErr, Parsed>:  match rest_empty:    case False{}:      Fail{BadFormat{}}    case True{}:      parse_cross_cv_vs(String.is_empty(vs), sb, sc, sv, ec, vs)def parse_cross_cv_pair(+sb: String, +sc: U32, +sv: Maybe<&2, U32>, +ec: U32, pair: String & String) -> Result<ParseErr, Parsed>:  match pair:    case (+vs, rest2):      parse_cross_cv_rest(String.is_empty(String.trim(rest2)), sb, sc, sv, ec, vs)def parse_cross_cv_ech(+sb: String, +sc: U32, +sv: Maybe<&2, U32>, +rest_after_sep: String, r: Result<ParseErr, U32>) -> Result<ParseErr, Parsed>:  match r:    case Fail{e}:      Fail{e}    case Done{ec}:      parse_cross_cv_pair(sb, sc, sv, ec, take_digits(rest_after_sep))def parse_after_verse_ev(+book: String, +ch: U32, +vn: U32, r: Result<ParseErr, U32>) -> Result<ParseErr, Parsed>:  match r:    case Fail{e}:      Fail{e}    case Done{ev}:      finish_vs(book, ch, vn, Some{ev})def parse_chapter_range_num(+book: String, +ch: U32, r: Result<ParseErr, U32>) -> Result<ParseErr, Parsed>:  match r:    case Fail{e}:      Fail{e}    case Done{ech}:      finish_ch(book, ch, ech, ChapterRange{})def parse_range_digits_same(+sb: String, +sc: U32, +sv: Maybe<&2, U32>, +digs: String) -> Result<ParseErr, Parsed>:  match sv:    case None{}:      parse_chapter_range_num(sb, sc, require_u32(digs))    case Some{+vn}:      parse_after_verse_ev(sb, sc, vn, require_u32(digs))def parse_range_digits_allow(allow: Bool, +sb: String, +sc: U32, +sv: Maybe<&2, U32>, +digs: String) -> Result<ParseErr, Parsed>:  match allow:    case True{}:      parse_range_digits_same(sb, sc, sv, digs)    case False{}:      Fail{BadFormat{}}def parse_range_digits_sep(sep: Bool, +sb: String, +sc: U32, +sv: Maybe<&2, U32>, +digs: String, +rest2: String) -> Result<ParseErr, Parsed>:  match sep:    case True{}:      parse_cross_cv_ech(sb, sc, sv, drop_cv_sep(rest2), require_u32(digs))    case False{}:      Fail{BadFormat{}}def parse_range_digits_rest(rest_empty: Bool, +allow_same_ch_digits: Bool, +sb: String, +sc: U32, +sv: Maybe<&2, U32>, +digs: String, +rest2: String) -> Result<ParseErr, Parsed>:  match rest_empty:    case True{}:      parse_range_digits_allow(allow_same_ch_digits, sb, sc, sv, digs)    case False{}:      parse_range_digits_sep(is_cv_sep_head(rest2), sb, sc, sv, digs, rest2)def parse_range_after_digs(digs_empty: Bool, +sb: String, +sc: U32, +sv: Maybe<&2, U32>, +allow_same_ch_digits: Bool, +digs: String, +rest2: String) -> Result<ParseErr, Parsed>:  match digs_empty:    case True{}:      parse_cross_second_book(sb, sc, sv, rest2)    case False{}:      parse_range_digits_rest(String.is_empty(String.trim(rest2)), allow_same_ch_digits, sb, sc, sv, digs, rest2)def parse_range_after_dash_pair(+sb: String, +sc: U32, +sv: Maybe<&2, U32>, +allow_same_ch_digits: Bool, pair: String & String) -> Result<ParseErr, Parsed>:  match pair:    case (+digs, rest2):      parse_range_after_digs(String.is_empty(digs), sb, sc, sv, allow_same_ch_digits, digs, rest2)def parse_range_after_dash_go(bookish: Bool, +sb: String, +sc: U32, +sv: Maybe<&2, U32>, +allow_same_ch_digits: Bool, +rest: String) -> Result<ParseErr, Parsed>:  match bookish:    case True{}:      parse_cross_second_book(sb, sc, sv, rest)    case False{}:      parse_range_after_dash_pair(sb, sc, sv, allow_same_ch_digits, take_digits(rest))def parse_range_after_dash(+sb: String, +sc: U32, +sv: Maybe<&2, U32>, +allow_same_ch_digits: Bool, +rest: String) -> Result<ParseErr, Parsed>:  parse_range_after_dash_go(bookish_head(String.trim(rest)), sb, sc, sv, allow_same_ch_digits, String.trim(rest))def parse_after_verse_num_go(+book: String, +ch: U32, +vn: U32, +rest: String, empty: Bool) -> Result<ParseErr, Parsed>:  match empty:    case True{}:      finish_vs(book, ch, vn, None{})    case False{}:      parse_range_after_dash(book, ch, Some{vn}, True{}, String.trim(drop_dash(rest)))def parse_after_verse_num_trim(+book: String, +ch: U32, +vn: U32, +r: String) -> Result<ParseErr, Parsed>:  parse_after_verse_num_go(book, ch, vn, r, String.is_empty(r))def parse_after_verse_num(+book: String, +ch: U32, +vn: U32, +rest: String) -> Result<ParseErr, Parsed>:  parse_after_verse_num_trim(book, ch, vn, String.trim(rest))def parse_verse_branch_num(+book: String, +ch: U32, +rest2: String, r: Result<ParseErr, U32>) -> Result<ParseErr, Parsed>:  match r:    case Fail{e}:      Fail{e}    case Done{vn}:      parse_after_verse_num(book, ch, vn, rest2)def parse_verse_branch_pair(+book: String, +ch: U32, pair: String & String) -> Result<ParseErr, Parsed>:  match pair:    case (vs, rest2):      parse_verse_branch_num(book, ch, rest2, require_u32(vs))def parse_verse_branch(+book: String, +ch: U32, +rest: String) -> Result<ParseErr, Parsed>:  parse_verse_branch_pair(book, ch, take_digits(rest))def parse_chapter_range_branch(+book: String, +ch: U32, +rest: String) -> Result<ParseErr, Parsed>:  parse_range_after_dash(book, ch, None{}, True{}, String.trim(drop_dash(rest)))def parse_after_chapter_sep_go(+book: String, +ch: U32, +rest: String, empty: Bool, dash: Bool) -> Result<ParseErr, Parsed>:  match empty:    case True{}:      finish_ch(book, ch, ch, Chapter{})    case False{}:      match dash:        case True{}:          parse_chapter_range_branch(book, ch, rest)        case False{}:          parse_verse_branch(book, ch, rest)def parse_after_chapter_sep_trim(+book: String, +ch: U32, +r: String) -> Result<ParseErr, Parsed>:  parse_after_chapter_sep_go(book, ch, r, String.is_empty(r), is_dash_head(r))def parse_after_chapter_sep(+book: String, +ch: U32, +rest: String) -> Result<ParseErr, Parsed>:  parse_after_chapter_sep_trim(book, ch, String.trim(rest))def parse_tail_num(+book: String, +rest0: String, r: Result<ParseErr, U32>) -> Result<ParseErr, Parsed>:  match r:    case Fail{e}:      Fail{e}    case Done{ch}:      parse_after_chapter_sep(book, ch, drop_cv_sep(String.trim(rest0)))def parse_tail_pair(+book: String, pair: String & String) -> Result<ParseErr, Parsed>:  match pair:    case (ch_s, rest0):      parse_tail_num(book, rest0, require_u32(ch_s))def parse_tail(+book: String, +tail: String) -> Result<ParseErr, Parsed>:  parse_tail_pair(book, take_digits(drop_cv_sep(String.trim(tail))))def parse_passage_book(+rest: String, m: Maybe<&2, String>) -> Result<ParseErr, Parsed>:  match m:    case None{}:      Fail{BadBook{}}    case Some{code}:      parse_tail(code, rest)def parse_passage_pair(pair: String & String) -> Result<ParseErr, Parsed>:  match pair:    case (book_raw, rest):      parse_passage_book(rest, Books.resolve_alias(String.trim(book_raw)))def parse_passage_go(+s0: String, empty: Bool) -> Result<ParseErr, Parsed>:  match empty:    case True{}:      Fail{Empty{}}    case False{}:      parse_passage_pair(take_book(s0))# --- URL / route.bible helpers (pure Bend) ---def hex_digit_lo(code: U32, ok: Bool) -> Maybe<&2, U32>:  match ok:    case False{}:      None{}    case True{}:      Some{U32.sub(code, 48)}def hex_digit_up(code: U32, ok: Bool) -> Maybe<&2, U32>:  match ok:    case False{}:      None{}    case True{}:      Some{U32.sub(code, 55)}def hex_digit_low(code: U32, ok: Bool) -> Maybe<&2, U32>:  match ok:    case False{}:      None{}    case True{}:      Some{U32.sub(code, 87)}def hex_nibble_af(+code: U32, dig: Maybe<&2, U32>) -> Maybe<&2, U32>:  match dig:    case Some{n}:      Some{n}    case None{}:      hex_digit_low(code, Bool.and(U32.is_le(97, code), U32.is_le(code, 102)))def hex_nibble_az(+code: U32, dig: Maybe<&2, U32>) -> Maybe<&2, U32>:  match dig:    case Some{n}:      Some{n}    case None{}:      hex_nibble_af(        code,        hex_digit_up(code, Bool.and(U32.is_le(65, code), U32.is_le(code, 70)))      )def hex_nibble_from_code(+code: U32) -> Maybe<&2, U32>:  hex_nibble_az(    code,    hex_digit_lo(code, Bool.and(U32.is_le(48, code), U32.is_le(code, 57)))  )def hex_nibble(+c: Char) -> Maybe<&2, U32>:  match c:    case Chr{+code}:      hex_nibble_from_code(code)def hex_byte(hi: U32, lo: U32) -> U32:  (U32.add(U32.mul(hi, 16), lo) : U32)# Single recursive decoder — Maybe results passed as DecSt fields (no computed match)type DecSt is Data:  DecCopy{}  DecClass{c: Char, is_pct: Bool, is_plus: Bool}  DecPct{}  DecNib1{m: Maybe<&2, U32>, spill: Char}  DecHi{hi: U32}  DecNib2{hi: U32, m: Maybe<&2, U32>, spill: Char}  DecApply{hi: U32, lo: U32}def url_decode_go(fuel: Nat, st: DecSt, rest: String, acc: String) -> String:  match fuel:    case 0n:      acc    case 1n+p:      match st:        case DecCopy{}:          match rest:            case SNil{}:              acc            case SCon{+h, +t}:              url_decode_go(p, DecClass{h, Char.is_eq(h, '%'), Char.is_eq(h, '+')}, t, acc)        case DecClass{+c, is_pct, is_plus}:          match is_pct:            case True{}:              url_decode_go(p, DecPct{}, rest, acc)            case False{}:              match is_plus:                case True{}:                  url_decode_go(p, DecCopy{}, rest, String.append(acc, " "))                case False{}:                  url_decode_go(p, DecCopy{}, rest, String.append(acc, char1(c)))        case DecPct{}:          match rest:            case SNil{}:              String.append(acc, "%")            case SCon{+h, +t}:              url_decode_go(p, DecNib1{hex_nibble(h), h}, t, acc)        case DecNib1{m, +spill}:          match m:            case None{}:              url_decode_go(p, DecCopy{}, SCon{spill, rest}, String.append(acc, "%"))            case Some{hi}:              url_decode_go(p, DecHi{hi}, rest, acc)        case DecHi{+hi}:          match rest:            case SNil{}:              String.append(acc, "%")            case SCon{+h, +t}:              url_decode_go(p, DecNib2{hi, hex_nibble(h), h}, t, acc)        case DecNib2{+hi, m, +spill}:          match m:            case None{}:              url_decode_go(p, DecCopy{}, SCon{spill, rest}, String.append(acc, "%"))            case Some{lo}:              url_decode_go(p, DecApply{hi, lo}, rest, acc)        case DecApply{+hi, +lo}:          url_decode_go(            p,            DecCopy{},            rest,            String.append(acc, char1(Char.from_u32(hex_byte(hi, lo))))          )def url_decode(+s: String) -> String:  url_decode_go(Nat.add(Nat.mul(4n, String.length(s)), 4n), DecCopy{}, s, "")type CutSt is Data:  CutCheck{}  CutDecide{stop: Bool}  CutTake{}def is_query_or_hash(+c: Char) -> Bool:  Bool.or(Char.is_eq(c, '?'), Char.is_eq(c, '#'))def take_until_qh_go(fuel: Nat, st: CutSt, rest: String, acc: String) -> String:  match fuel:    case 0n:      acc    case 1n+p:      match st:        case CutCheck{}:          match rest:            case SNil{}:              acc            case SCon{+h, +t}:              take_until_qh_go(p, CutDecide{is_query_or_hash(h)}, rest, acc)        case CutDecide{stop}:          match stop:            case True{}:              acc            case False{}:              take_until_qh_go(p, CutTake{}, rest, acc)        case CutTake{}:          match rest:            case SNil{}:              acc            case SCon{+h, +t}:              take_until_qh_go(p, CutCheck{}, t, String.append(acc, char1(h)))def strip_query(+s: String) -> String:  take_until_qh_go(Nat.add(Nat.mul(3n, String.length(s)), 3n), CutCheck{}, s, "")def take_until_slash_go(fuel: Nat, st: CutSt, rest: String, acc: String) -> String:  match fuel:    case 0n:      acc    case 1n+p:      match st:        case CutCheck{}:          match rest:            case SNil{}:              acc            case SCon{+h, +t}:              take_until_slash_go(p, CutDecide{Char.is_eq(h, '/')}, rest, acc)        case CutDecide{stop}:          match stop:            case True{}:              acc            case False{}:              take_until_slash_go(p, CutTake{}, rest, acc)        case CutTake{}:          match rest:            case SNil{}:              acc            case SCon{+h, +t}:              take_until_slash_go(p, CutCheck{}, t, String.append(acc, char1(h)))def last_path_segment(+s: String) -> String:  String.reverse(    take_until_slash_go(      Nat.add(Nat.mul(3n, String.length(s)), 3n),      CutCheck{},      String.reverse(s),      ""    )  )type TrPh is Data:  TrStart{h: Char, is_a: Bool}  TrAlpha{}  TrClass{h: Char, is_a: Bool, is_dot: Bool}  TrCommit{ok: Bool}def strip_tr_go(fuel: Nat, ph: TrPh, rest: String, +n: Nat, +orig: String) -> String:  match fuel:    case 0n:      orig    case 1n+p:      match ph:        case TrStart{+h, is_a}:          match is_a:            case False{}:              orig            case True{}:              strip_tr_go(p, TrAlpha{}, rest, 1n, orig)        case TrAlpha{}:          match rest:            case SNil{}:              orig            case SCon{+h, +t}:              strip_tr_go(p, TrClass{h, Char.is_alpha(h), Char.is_eq(h, '.')}, t, n, orig)        case TrClass{+h, is_a, is_dot}:          match is_a:            case True{}:              strip_tr_go(p, TrAlpha{}, rest, Nat.add(n, 1n), orig)            case False{}:              match is_dot:                case True{}:                  strip_tr_go(p, TrCommit{Bool.and(Nat.is_ge(n, 2n), Nat.is_le(n, 8n))}, rest, n, orig)                case False{}:                  orig        case TrCommit{ok}:          match ok:            case True{}:              String.reverse(rest)            case False{}:              origdef strip_tr_suffix_rev(+s: String, rev: String) -> String:  match rev:    case SNil{}:      s    case SCon{+h, +t}:      strip_tr_go(        Nat.add(Nat.mul(3n, String.length(s)), 4n),        TrStart{h, Char.is_alpha(h)},        t,        0n,        s      )def strip_tr_suffix(+s: String) -> String:  strip_tr_suffix_rev(s, String.reverse(s))def parse_passage_trim(+s0: String) -> Result<ParseErr, Parsed>:  parse_passage_go(s0, String.is_empty(s0))def parse_passage(+input: String) -> Result<ParseErr, Parsed>:  parse_passage_trim(strip_tr_suffix(Norm.normalize_intake(input)))def looks_like_url(+s: String) -> Bool:  Bool.or(    String.contains(s, "://"),    Bool.or(      String.starts_with(s, "www."),      Bool.or(        String.contains(s, "bibleref="),        Bool.or(          String.contains(s, "bible/"),          Bool.or(            String.contains(s, "bible-commentary/"),            Bool.or(              String.contains(s, "v1/p/"),              String.starts_with(String.to_lower(s), "logosres:")            )          )        )      )    )  )def pick_url_ref_go(+share: String, +fallback: String, empty: Bool) -> String:  match empty:    case False{}:      url_decode(share)    case True{}:      fallbackdef pick_url_ref(+share: String, +fallback: String) -> String:  pick_url_ref_go(share, fallback, String.is_empty(share))def extract_url_ref(+s: String) -> String:  pick_url_ref(Share.extract_share_ref(s), url_decode(last_path_segment(strip_query(s))))def parse_any_go(+s: String, is_url: Bool) -> Result<ParseErr, Parsed>:  match is_url:    case True{}:      parse_passage(strip_tr_suffix(extract_url_ref(s)))    case False{}:      parse_passage(s)def parse_any_trim(+s: String) -> Result<ParseErr, Parsed>:  parse_any_go(s, looks_like_url(s))def parse_any(+input: String) -> Result<ParseErr, Parsed>:  parse_any_trim(Norm.normalize_intake(input))# String-only probe for linkify (avoids Result across modules)def canonical_of_r(r: Result<ParseErr, Parsed>) -> String:  match r:    case Fail{e}:      ""    case Done{p}:      match p:        case Parsed{+canonical, display, book, end_book, chapter, verse, end_chapter, end_verse, kind}:          canonicaldef try_canonical(+input: String) -> String:  canonical_of_r(parse_any(input))# Multi-ref free-text: REFERENCE_TOKEN-shaped scan (grab-bcv spirit), not only ';' splits.# Walks input at word boundaries; tries URL tokens then ref tokens; dedupes by canonical.def rev_parsed(xs: List<&2, Parsed>, acc: List<&2, Parsed>) -> List<&2, Parsed>:  match xs:    case Nil{}:      acc    case h <> t:      rev_parsed(t, h <> acc)def canon_of(+p: Parsed) -> String:  match p:    case Parsed{+canonical, display, book, end_book, chapter, verse, end_chapter, end_verse, kind}:      canonicaltype ShPh is Data:  ShScan{}  ShEq{eq: Bool}def seen_has_go(fuel: Nat, ph: ShPh, +c: String, xs: List<&2, String>) -> Bool:  match fuel:    case 0n:      False{}    case 1n+p:      match ph:        case ShScan{}:          match xs:            case Nil{}:              False{}            case h <> t:              seen_has_go(p, ShEq{String.eq(h, c)}, c, t)        case ShEq{eq}:          match eq:            case True{}:              True{}            case False{}:              seen_has_go(p, ShScan{}, c, xs)def seen_has(+c: String, +xs: List<&2, String>) -> Bool:  seen_has_go(    Nat.add(List.length(&2, String, xs), 2n),    ShScan{},    c,    xs  )def find_push_dedup(  dup: Bool,  +p: Parsed,  acc: List<&2, Parsed>,  seen: List<&2, String>) -> List<&2, Parsed> & List<&2, String>:  match dup:    case True{}:      (acc, seen)    case False{}:      (p <> acc, canon_of(p) <> seen)def find_push_done(+p: Parsed, acc: List<&2, Parsed>, +seen: List<&2, String>) -> List<&2, Parsed> & List<&2, String>:  find_push_dedup(seen_has(canon_of(p), seen), p, acc, seen)def find_push_r(  r: Result<ParseErr, Parsed>,  acc: List<&2, Parsed>,  seen: List<&2, String>) -> List<&2, Parsed> & List<&2, String>:  match r:    case Fail{e}:      (acc, seen)    case Done{+p}:      find_push_done(p, acc, seen)# On parse failure return "" consume-tok so FaGot advances one char (not the false token).def find_push_r_tok_done(  +tok: String,  pair: List<&2, Parsed> & List<&2, String>) -> String & (List<&2, Parsed> & List<&2, String>):  match pair:    case (acc, seen):      (tok, (acc, seen))def find_push_r_tok(  +tok: String,  r: Result<ParseErr, Parsed>,  acc: List<&2, Parsed>,  seen: List<&2, String>) -> String & (List<&2, Parsed> & List<&2, String>):  match r:    case Fail{e}:      ("", (acc, seen))    case Done{+p}:      find_push_r_tok_done(tok, find_push_done(p, acc, seen))def find_try_tok_empty(  empty: Bool,  +tok: String,  acc: List<&2, Parsed>,  seen: List<&2, String>) -> String & (List<&2, Parsed> & List<&2, String>):  match empty:    case True{}:      ("", (acc, seen))    case False{}:      find_push_r_tok(tok, parse_any(tok), acc, seen)def find_try_tok(  +tok: String,  acc: List<&2, Parsed>,  seen: List<&2, String>) -> String & (List<&2, Parsed> & List<&2, String>):  find_try_tok_empty(String.is_empty(tok), tok, acc, seen)def str_drop_n_go(fuel: Nat, n: Nat, s: String) -> String:  match fuel:    case 0n:      s    case 1n+p:      match n:        case 0n:          s        case 1n+m:          match s:            case SNil{}:              ""            case SCon{h, t}:              str_drop_n_go(p, m, t)def str_drop_n(+n: Nat, +s: String) -> String:  str_drop_n_go(Nat.add(n, 2n), n, s)def is_alnum_c(+c: Char) -> Bool:  Bool.or(Char.is_alpha(c), Char.is_digit(c))type FaPh is Data:  FaScan{prev_alnum: Bool}  FaBound{prev_alnum: Bool, ok: Bool}  FaTryUrl{}  FaAfterUrl{+utok: String, empty: Bool}  FaTryRef{}  FaAfterRef{+rtok: String, empty: Bool}  FaGot{    +tok: String,    acc: List<&2, Parsed>,    seen: List<&2, String>,    empty: Bool  }  FaAdvance{}def fa_url_ph_tok(+utok: String) -> FaPh:  FaAfterUrl{utok, String.is_empty(utok)}def fa_url_ph(+rest: String) -> FaPh:  fa_url_ph_tok(Tok.match_url_token(rest))def fa_ref_ph_tok(+rtok: String) -> FaPh:  FaAfterRef{rtok, String.is_empty(rtok)}def fa_ref_ph(+rest: String) -> FaPh:  fa_ref_ph_tok(Tok.match_ref_token(rest))def fa_got_from_pair(  pair: String & (List<&2, Parsed> & List<&2, String>)) -> FaPh:  match pair:    case (+tok, (acc, seen)):      FaGot{tok, acc, seen, String.is_empty(tok)}def find_any_go(  fuel: Nat,  ph: FaPh,  +rest: String,  +acc: List<&2, Parsed>,  +seen: List<&2, String>) -> List<&2, Parsed>:  match fuel:    case 0n:      acc    case 1n+p:      match ph:        case FaScan{+prev_alnum}:          match rest:            case SNil{}:              acc            case SCon{+h, +t}:              find_any_go(                p,                FaBound{prev_alnum, Tok.boundary_ok(prev_alnum)},                rest,                acc,                seen              )        case FaBound{+prev_alnum, ok}:          match ok:            case False{}:              find_any_go(p, FaAdvance{}, rest, acc, seen)            case True{}:              find_any_go(p, FaTryUrl{}, rest, acc, seen)        case FaTryUrl{}:          find_any_go(p, fa_url_ph(rest), rest, acc, seen)        case FaAfterUrl{+utok, empty}:          match empty:            case False{}:              find_any_go(                p,                fa_got_from_pair(find_try_tok(utok, acc, seen)),                rest,                acc,                seen              )            case True{}:              find_any_go(p, FaTryRef{}, rest, acc, seen)        case FaTryRef{}:          find_any_go(p, fa_ref_ph(rest), rest, acc, seen)        case FaAfterRef{+rtok, empty}:          match empty:            case False{}:              find_any_go(                p,                fa_got_from_pair(find_try_tok(rtok, acc, seen)),                rest,                acc,                seen              )            case True{}:              find_any_go(p, FaAdvance{}, rest, acc, seen)        case FaGot{+tok, +acc2, +seen2, empty}:          match empty:            case True{}:              find_any_go(p, FaAdvance{}, rest, acc, seen)            case False{}:              find_any_go(                p,                FaScan{True{}},                str_drop_n(String.length(tok), rest),                acc2,                seen2              )        case FaAdvance{}:          match rest:            case SNil{}:              acc            case SCon{+h, +t}:              find_any_go(p, FaScan{is_alnum_c(h)}, t, acc, seen)def find_any(+input: String) -> List<&2, Parsed>:  rev_parsed(    find_any_go(      Nat.add(Nat.mul(8n, String.length(input)), 16n),      FaScan{False{}},      Norm.normalize_intake(input),      Nil{},      Nil{}    ),    Nil{}  )def err_msg(e: ParseErr) -> String:  match e:    case Empty{}:      "empty input"    case BadBook{}:      "unknown book"    case BadFormat{}:      "bad format"    case BadNumber{}:      "need a positive chapter/verse number"    case CapChapter{+book, +max, +got}:      String.append(        String.append(String.append(Books.display_name(book), " has "), U32.show(max)),        String.append(" chapters (got ", String.append(U32.show(got), ")"))      )    case CapVerse{+book, +chapter, +max, +got}:      String.append(        String.append(          String.append(String.append(Books.display_name(book), " "), U32.show(chapter)),          String.append(" has ", U32.show(max))        ),        String.append(" verses (got ", String.append(U32.show(got), ")"))      )    case Reversed{}:      "reversed range"def show_ok(+canonical: String, +display: String) -> IO(Unit):  do IO<Unit>:    IO.print(canonical)    IO.print("  (")    IO.print(display)    IO.print(")\n")def show_result(r: Result<ParseErr, Parsed>) -> IO(Unit):  match r:    case Fail{e}:      do IO<Unit>:        IO.print("ERR ")        IO.print(err_msg(e))        IO.print("\n")    case Done{p}:      match p:        case Parsed{+canonical, +display, book, end_book, chapter, verse, end_chapter, end_verse, kind}:          show_ok(canonical, display)def join_args(xs: List<&1, String>) -> String:  match xs:    case Nil{}:      ""    case h <> Nil{}:      h    case h <> t:      String.append(h, String.append(" ", join_args(t)))def usage() -> IO(Unit):  IO.print("grab-bcv (Bend) — parse Bible references to OSIS\n\nUsage:\n  bend main.bend -- \"John 3:16\"\n  bend main.bend -- --all \"John 3:16 and Romans 8:28\"\n  bend main.bend -- --complete \"john 3:\"\n  bend main.bend -- --context \"John 3:16\"\n  bend main.bend -- --linkify \"John 3:16\"\n  bend main.bend -- --linkify --src ci \"John 3:16\"\n  bend main.bend -- --linkify --rewrite-existing \"[John 3:16](https://example.com/x)\"\n  bend main.bend --publish\n")def show_parsed_list_rest(xs: List<&2, Parsed>) -> IO(Unit):  match xs:    case Nil{}:      IO.print("")    case h <> t:      do IO<Unit>:        show_result(Done{h})        show_parsed_list_rest(t)def show_parsed_list(xs: List<&2, Parsed>) -> IO(Unit):  match xs:    case Nil{}:      IO.print("(no refs)\n")    case h <> t:      do IO<Unit>:        show_result(Done{h})        show_parsed_list_rest(t)def run_context_v(+book: String, +chapter: U32, verse: Maybe<&2, U32>) -> IO(Unit):  match verse:    case None{}:      IO.print("context needs a verse\n")    case Some{+v}:      IO.print(String.append(Ctx.format_ctx(Ctx.expand_default(book, chapter, v)), "\n"))def run_context_r(r: Result<ParseErr, Parsed>) -> IO(Unit):  match r:    case Fail{e}:      show_result(Fail{e})    case Done{p}:      match p:        case Parsed{canonical, display, +book, end_book, +chapter, verse, end_chapter, end_verse, kind}:          run_context_v(book, chapter, verse)def run_context(+q: String) -> IO(Unit):  run_context_r(parse_any(q))def run_query(+q: String) -> IO(Unit):  show_result(parse_any(q))def run_all(+q: String) -> IO(Unit):  show_parsed_list(find_any(q))def run_complete(+q: String) -> IO(Unit):  Comp.show_suggestions(Comp.autocomplete(q, 8n))def run_linkify_r(r: Result<ParseErr, Parsed>, +src: String) -> IO(Unit):  match r:    case Fail{e}:      show_result(Fail{e})    case Done{p}:      match p:        case Parsed{+canonical, +display, book, end_book, chapter, verse, end_chapter, end_verse, kind}:          IO.print(String.append(Route.markdown_route_link_qvs(display, canonical, "", src), "\n"))def run_linkify(+q: String, +src: String) -> IO(Unit):  run_linkify_r(parse_any(q), src)# After --linkify: optional --src <tag> / --rewrite-existing (rewrite ignored on single-ref path).type PlfPh is Data:  PlfGo{+src: String}  PlfNeedSrc{}  PlfHead{+src: String, is_rw: Bool, is_src: Bool, +h: String}def parse_linkify_cli_go(fuel: Nat, ph: PlfPh, xs: List<&1, String>) -> IO(Unit):  match fuel:    case 0n:      match ph:        case PlfGo{+src}:          run_linkify(join_args(xs), src)        case PlfNeedSrc{}:          run_linkify(join_args(xs), "")        case PlfHead{+src, is_rw, is_src, +h}:          run_linkify(join_args(h <> xs), src)    case 1n+p:      match ph:        case PlfGo{+src}:          match xs:            case Nil{}:              run_linkify("", src)            case +h <> t:              parse_linkify_cli_go(                p,                PlfHead{src, String.eq(h, "--rewrite-existing"), String.eq(h, "--src"), h},                t              )        case PlfNeedSrc{}:          match xs:            case Nil{}:              run_linkify("", "")            case +tag <> t:              parse_linkify_cli_go(p, PlfGo{tag}, t)        case PlfHead{+src, is_rw, is_src, +h}:          match is_rw:            case True{}:              parse_linkify_cli_go(p, PlfGo{src}, xs)            case False{}:              match is_src:                case True{}:                  parse_linkify_cli_go(p, PlfNeedSrc{}, xs)                case False{}:                  run_linkify(join_args(h <> xs), src)def parse_linkify_cli(xs: List<&1, String>) -> IO(Unit):  parse_linkify_cli_go(64n, PlfGo{""}, xs)def run_flag5(+h: String, t: List<&1, String>, is_all: Bool, is_comp: Bool, is_ctx: Bool, is_link: Bool) -> IO(Unit):  match is_all:    case True{}:      run_all(join_args(t))    case False{}:      match is_comp:        case True{}:          run_complete(join_args(t))        case False{}:          match is_ctx:            case True{}:              run_context(join_args(t))            case False{}:              match is_link:                case True{}:                  parse_linkify_cli(t)                case False{}:                  run_query(join_args(h <> t))def run_args(xs: List<&1, String>) -> IO(Unit):  match xs:    case Nil{}:      usage()    case +h <> t:      run_flag5(        h,        t,        String.eq(h, "--all"),        String.eq(h, "--complete"),        String.eq(h, "--context"),        String.eq(h, "--linkify")      )def main() -> IO(Unit):  do IO<Unit>:    args : List<&1, String> <- IO.args()    run_args(args)