import Base import ./books_data.bend as D type Phase is Data: Scan{} Hit{eq: Bool} # fuel shrinks every step; Init fuel = 2 * length + 1 covers Scan+Hit per row def find_alias(fuel: Nat, ph: Phase, xs: List, +key: String, held: String) -> Maybe<&2, String>: match fuel: case 0n: None{} case 1n+p: match ph: case Scan{}: match xs: case Nil{}: None{} case D.Alias{+k, c} <> t: find_alias(p, Hit{String.eq(k, key)}, t, key, c) case Hit{eq}: match eq: case True{}: Some{held} case False{}: find_alias(p, Scan{}, xs, key, held) type SpSt is Data: SpCheck{} SpDecide{keep: Bool} SpTake{} def char1(+c: Char) -> String: String.from_list(c <> Nil{}) def strip_spaces_go(fuel: Nat, st: SpSt, rest: String, acc: String) -> String: match fuel: case 0n: acc case 1n+p: match st: case SpCheck{}: match rest: case SNil{}: acc case SCon{+h, +t}: strip_spaces_go(p, SpDecide{Bool.not(Char.is_space(h))}, rest, acc) case SpDecide{keep}: match keep: case True{}: strip_spaces_go(p, SpTake{}, rest, acc) case False{}: match rest: case SNil{}: acc case SCon{h, t}: strip_spaces_go(p, SpCheck{}, t, acc) case SpTake{}: match rest: case SNil{}: acc case SCon{+h, +t}: strip_spaces_go(p, SpCheck{}, t, String.append(acc, char1(h))) def strip_spaces(+s: String) -> String: strip_spaces_go( Nat.add(Nat.mul(3n, String.length(s)), 3n), SpCheck{}, s, "" ) def resolve_alias(+raw: String) -> Maybe<&2, String>: find_alias(500n, Scan{}, D.alias_table(), strip_spaces(String.to_lower(raw)), "") def find_cap(fuel: Nat, ph: Phase, xs: List, +key: String, held: U32) -> Maybe<&2, U32>: match fuel: case 0n: None{} case 1n+p: match ph: case Scan{}: match xs: case Nil{}: None{} case D.Cap{+k, n} <> t: find_cap(p, Hit{String.eq(k, key)}, t, key, n) case Hit{eq}: match eq: case True{}: Some{held} case False{}: find_cap(p, Scan{}, xs, key, held) def chapter_count(+book: String) -> Maybe<&2, U32>: find_cap(200n, Scan{}, D.chapter_caps(), book, 0) def verse_count(+book: String, +ch: U32) -> Maybe<&2, U32>: find_cap(3000n, Scan{}, D.verse_caps(), String.append(String.append(book, "."), U32.show(ch)), 0) def find_name(fuel: Nat, ph: Phase, xs: List, +code: String, held: String) -> String: match fuel: case 0n: held case 1n+p: match ph: case Scan{}: match xs: case Nil{}: held case D.BookName{+c, name} <> t: find_name(p, Hit{String.eq(c, code)}, t, code, name) case Hit{eq}: match eq: case True{}: held case False{}: find_name(p, Scan{}, xs, code, held) def display_name(+code: String) -> String: find_name(200n, Scan{}, D.book_names(), code, code)