~/bend-docscommunity

src/rules/style/wrap.bend source

src/rules/style/wrap.bend on the hub · documented module

# rule wrap: how a def header breaks. A one-line header wider than 120 must# break; the width is the header through its `:`, counted the way `space`# counts a line (a string literal is two characters), a comment counting# none. A header breaks when a newline token of its own sits in it: a line# break inside a string literal is the string's. A one-line header that# fits stays one line however many parameters it has. A header that breaks# puts `(` at the end of the first line and one parameter on each following# line, then `)` and the return type on a line of their own after the last# parameter. Several parameters on a line, a parameter left on the `(`# line, a parameter split across lines, a `)` on the last parameter's line# (`bb: U32) -> U32:`), a `)` with no `->` right after it on its line (the# return type on a line of its own, `)` then `-> U32:`; a def that fills a# law has no return type, and `):` is its end), or a parameter list# with no parameter in it (`def none(` then `) -> U32:`, which fits on one# line), is a finding. A comment after the header's `:` is not part of the# header: `def u(aa: U32) -> U32: # note` is a one-line header.import Baseimport ../../src.bend as Srcimport ../../finding.bend as Fimport ../../syntax/lex.bend as Leximport ../../syntax/outline.bend as Outlineimport ../../lazy/lazy.bend as Lazyimport ./space.bend as Space# where one parameter sits in the header: its first line, its last, its columntype Span is Data:  Span{line: U32, end: U32, col: U32}# seeking the parameter list, inside it, just past its `)`, past a `->`# right after it on its line, or past anything else after ittype Phase is Data:  Seek{}  Args{}  Past{}  Shut{}  Loose{}# what a token does to the bracket depthstype Act is Data:  AOpen{}  AParen{}  AEnd{}  AUnparen{}  ABrack{}  AUnbrack{}  ABrace{}  AUnbrace{}  AAngle{}  AUnangle{}  AComma{}  AArrow{}  AStray{}  ANone{}# the walk: depths, where the list's `)` sat, the `(` line, and the parameter# open so far (spans reversed)type Walk is Data:  Walk{mode: Phase, paren: U32, bracket: U32, brace: U32, angle: U32, shut: Span, open: U32,    on: Bool, pline: U32, pend: U32, pcol: U32, spans: List<&2, Span>}# the header already breaks across lines: some token of it is a newlinedef check.broken(toks: List<&2, Lex.Tok>) -> Bool:  match toks:    case Nil{}:      False{}    case Con{Lex.Tok{kk, _tx, _ln, _cl}, rest}:      Lazy.or_else(Lex.is_nl(kk), _u => check.broken(rest))# one token's share of the header's width: a comment has nonedef check.cost(kd: Lex.TokKind, +tx: String) -> U32:  match kd:    case Lex.TComment{}:      0    case other:      Space.width_of(other, tx)# the width so far, with one token's share addeddef check.add(+acc: U32, kd: Lex.TokKind, +tx: String) -> U32:  (acc + check.cost(kd, tx) : U32)# a `:` token?def check.is_colon(kk: Lex.TokKind) -> Bool:  match kk:    case Lex.TColon{}:      True{}    case other:      False{}# the header's width through its last `:` (upto, once seen says there was# one), else its whole width, a string literal counting as two and a# comment nonedef check.width.go(toks: List<&2, Lex.Tok>, +acc: U32, +upto: U32, +seen: Bool) -> U32:  match toks:    case Nil{}:      Bool.pick(U32, seen, upto, acc)    case Con{Lex.Tok{+kd, tx, _ln, _cl}, rest}:      +next = check.add(acc, kd, tx)      +colon = check.is_colon(kd)      check.width.go(rest, next, Bool.pick(U32, colon, next, upto), Bool.or(colon, seen))# the header's width, through its `:`: a comment after it does not countdef check.width(toks: List<&2, Lex.Tok>) -> U32:  check.width.go(toks, 0, 0, False{})# a fresh walk, before the parameter listdef check.start() -> Walk:  Walk{Seek{}, 0, 0, 0, 0, Span{0, 0, 0}, 0, False{}, 0, 0, 0, []}# `(`def check.is_oparen(kk: Lex.TokKind, +tx: String) -> Bool:  match kk:    case Lex.TOpen{}:      String.eq(tx, "(")    case other:      False{}# `)`def check.is_cparen(kk: Lex.TokKind, +tx: String) -> Bool:  match kk:    case Lex.TClose{}:      String.eq(tx, ")")    case other:      False{}# an opening bracket, as the depth it raises; ANone when it is not onedef check.open_text(+tx: String) -> Act:  Bool.pick(Act, String.eq(tx, "("), AParen{},    Bool.pick(Act, String.eq(tx, "["), ABrack{},      Bool.pick(Act, String.eq(tx, "{"), ABrace{}, ANone{})))# an opening bracket, as the depth it raisesdef check.on_open(kk: Lex.TokKind, +tx: String) -> Act:  match kk:    case Lex.TOpen{}:      check.open_text(tx)    case other:      ANone{}# a closing bracket, as the depth it lowers; ANone when it is not onedef check.close_text(+tx: String) -> Act:  Bool.pick(Act, String.eq(tx, ")"), AUnparen{},    Bool.pick(Act, String.eq(tx, "]"), AUnbrack{},      Bool.pick(Act, String.eq(tx, "}"), AUnbrace{}, ANone{})))# a closing bracket, as the depth it lowersdef check.on_close(kk: Lex.TokKind, +tx: String) -> Act:  match kk:    case Lex.TClose{}:      check.close_text(tx)    case other:      ANone{}# an operator tokendef check.is_op(kk: Lex.TokKind) -> Bool:  match kk:    case Lex.TOp{}:      True{}    case other:      False{}# every char a `>`def check.gt_chars(cs: List<&2, Char>) -> Bool:  match cs:    case Nil{}:      True{}    case Con{+c, t}:      Lazy.and_then(Char.is_eq(c, '>'), _u => check.gt_chars(t))# the text is a non-empty run of `>`def check.all_gt(+tx: String) -> Bool:  Bool.and(Bool.not(String.is_empty(tx)), check.gt_chars(String.to_list(tx)))# how many `>` a run holdsdef check.gt_count(cs: List<&2, Char>) -> Nat:  match cs:    case Nil{}:      0n    case Con{+c, t}:      +more = check.gt_count(t)      Bool.pick(Nat, Char.is_eq(c, '>'), Succ{more}, more)# the angle-closes in the text, else nonedef check.ticks_of(+tx: String) -> Nat:  Lazy.stop(Nat, Bool.not(check.all_gt(tx)), 0n, _u => check.gt_count(String.to_list(tx)))# `<` or `<&` glued to a name opens type argumentsdef check.opens_angle(glued: Bool, +tx: String) -> Bool:  Bool.and(glued, Bool.or(String.eq(tx, "<"), String.eq(tx, "<&")))# an angle close, discarded when an angle open already wondef check.drop_close(_closed: Act) -> Act:  AAngle{}# an angle open wins over a close; otherwise the close standsdef check.prefer_open(opens: Bool, closed: Act) -> Act:  match opens:    case True{}:      check.drop_close(closed)    case False{}:      closed# `>` runs close angles; `<` glued to a name opens onedef check.op_angle(+tx: String, glued: Bool) -> Act:  check.prefer_open(check.opens_angle(glued, tx),    Bool.pick(Act, check.all_gt(tx), AUnangle{}, ANone{}))# not an operator: no angle motiondef check.no_angle(_tx: String, _glued: Bool) -> Act:  ANone{}# an operator's angle motiondef check.angle_op(is_op: Bool, +tx: String, glued: Bool) -> Act:  match is_op:    case True{}:      check.op_angle(tx, glued)    case False{}:      check.no_angle(tx, glued)# angle motion, when the token is an operatordef check.angle_act(kk: Lex.TokKind, +tx: String, glued: Bool) -> Act:  check.angle_op(check.is_op(kk), tx, glued)# a value used only so a branch can name itdef check.keep(act: Act, _kk: Lex.TokKind, _tx: String, _glued: Bool) -> Act:  act# angle motion when the token was not a bracket, else that bracketdef check.or_angle(closed: Act, kk: Lex.TokKind, +tx: String, glued: Bool) -> Act:  match closed:    case ANone{}:      check.angle_act(kk, tx, glued)    case other:      check.keep(other, kk, tx, glued)# a close bracket, else angle motiondef check.or_close(opened: Act, +kk: Lex.TokKind, +tx: String, glued: Bool) -> Act:  match opened:    case ANone{}:      check.or_angle(check.on_close(kk, tx), kk, tx, glued)    case other:      check.keep(other, kk, tx, glued)# the bracket or angle motion of a token, not the parameter list's own breaksdef check.brackets(+kk: Lex.TokKind, +tx: String, glued: Bool) -> Act:  check.or_close(check.on_open(kk, tx), kk, tx, glued)# no depth is opendef check.zero(+paren: U32, +angle: U32, +brace: U32, +bracket: U32) -> Bool:  Bool.and(U32.is_eq(paren, 0),    Bool.and(U32.is_eq(angle, 0),      Bool.and(U32.is_eq(brace, 0), U32.is_eq(bracket, 0))))# the top of the parameter list: one `(`, nothing nesteddef check.top(+paren: U32, +angle: U32, +brace: U32, +bracket: U32) -> Bool:  Bool.and(U32.is_eq(paren, 1),    Bool.and(U32.is_eq(angle, 0),      Bool.and(U32.is_eq(brace, 0), U32.is_eq(bracket, 0))))# `(` at depth zero opens the parameter list; a nested one is just a parendef check.pick_open(zero: Bool, rest: Act) -> Act:  match zero:    case True{}:      AOpen{}    case False{}:      rest# the parameter list's `(`, else the token's ordinary motiondef check.seek_open(is_open: Bool, zero: Bool, rest: Act) -> Act:  match is_open:    case True{}:      check.pick_open(zero, rest)    case False{}:      rest# motion while still seeking the parameter listdef check.act_seek(  +kk: Lex.TokKind,  +tx: String,  glued: Bool,  +paren: U32,  +angle: U32,  +brace: U32,  +bracket: U32) -> Act:  check.seek_open(check.is_oparen(kk, tx), check.zero(paren, angle, brace, bracket),    check.brackets(kk, tx, glued))# `)` at the top of the list ends it; a nested one is just a parendef check.end_or(flat: Bool, rest: Act) -> Act:  match flat:    case True{}:      AEnd{}    case False{}:      rest# the parameter list's `)`, else the token's ordinary motiondef check.args_end(is_close: Bool, flat: Bool, rest: Act) -> Act:  match is_close:    case True{}:      check.end_or(flat, rest)    case False{}:      rest# a comma at the top of the list separates parametersdef check.comma_or(flat: Bool, rest: Act) -> Act:  match flat:    case True{}:      AComma{}    case False{}:      rest# a separating comma, else the token's ordinary motiondef check.args_comma(is_comma: Bool, flat: Bool, rest: Act) -> Act:  match is_comma:    case True{}:      check.comma_or(flat, rest)    case False{}:      rest# motion inside the parameter listdef check.act_args(  +kk: Lex.TokKind,  +tx: String,  glued: Bool,  +paren: U32,  +angle: U32,  +brace: U32,  +bracket: U32) -> Act:  check.args_end(check.is_cparen(kk, tx), check.top(paren, angle, brace, bracket),    check.args_comma(Lex.is_comma(kk), check.top(paren, angle, brace, bracket),      check.brackets(kk, tx, glued)))# past the parameter list nothing movesdef check.act_done(  _kk: Lex.TokKind,  _tx: String,  _glued: Bool,  _paren: U32,  _angle: U32,  _brace: U32,  _bracket: U32) -> Act:  ANone{}# `->`def check.is_arrow(kk: Lex.TokKind) -> Bool:  match kk:    case Lex.TArrow{}:      True{}    case other:      False{}# right after the list's `)`, a `->`, or the `:` of a header with no return# type (a def that fills a law), or anything elsedef check.act_shut(  +kk: Lex.TokKind,  _tx: String,  _glued: Bool,  _paren: U32,  _angle: U32,  _brace: U32,  _bracket: U32) -> Act:  Bool.pick(Act, Bool.or(check.is_arrow(kk), check.is_colon(kk)), AArrow{}, AStray{})# the motion of one tokendef check.act(  ph: Phase,  kk: Lex.TokKind,  +tx: String,  glued: Bool,  +paren: U32,  +angle: U32,  +brace: U32,  +bracket: U32) -> Act:  match ph:    case Past{}:      check.act_done(kk, tx, glued, paren, angle, brace, bracket)    case Shut{}:      check.act_shut(kk, tx, glued, paren, angle, brace, bracket)    case Loose{}:      check.act_done(kk, tx, glued, paren, angle, brace, bracket)    case Seek{}:      check.act_seek(kk, tx, glued, paren, angle, brace, bracket)    case Args{}:      check.act_args(kk, tx, glued, paren, angle, brace, bracket)# the parameter list's own `(`, `)` and commas are not part of a parameterdef check.is_sep(act: Act) -> Bool:  match act:    case AOpen{}:      True{}    case AEnd{}:      True{}    case AComma{}:      True{}    case other:      False{}# one less, and not below zerodef check.dec_u(+nn: U32) -> U32:  Lazy.stop(U32, U32.is_eq(nn, 0), 0, _u => (nn - 1 : U32))# `left` angle-closes applied to the depth, and not below zerodef check.sub(left: Nat, +angle: U32) -> U32:  match left:    case Zero{}:      angle    case Succ{p}:      Lazy.stop(U32, U32.is_eq(angle, 0), angle, _u => check.sub(p, (angle - 1 : U32)))# a parameter that did start, onto the listdef check.no_span(_pline: U32, _pend: U32, _pcol: U32, spans: List<&2, Span>) -> List<&2, Span>:  spans# the open parameter, closed onto the listdef check.cons(on: Bool, +pline: U32, +pend: U32, +pcol: U32, spans: List<&2, Span>) -> List<&2, Span>:  match on:    case True{}:      Span{pline, pend, pcol} <> spans    case False{}:      check.no_span(pline, pend, pcol, spans)# the walk rebuilt; angle-closes are applied by the callerdef check.rebuild(  _ticks: Nat,  mode: Phase,  paren: U32,  bracket: U32,  brace: U32,  angle: U32,  shut: Span,  open: U32,  on: Bool,  pline: U32,  pend: U32,  pcol: U32,  spans: List<&2, Span>) -> Walk:  Walk{mode, paren, bracket, brace, angle, shut, open, on, pline, pend, pcol, spans}# `(` opens the parameter listdef check.opened(  ticks: Nat,  bracket: U32,  brace: U32,  angle: U32,  spans: List<&2, Span>,  +ln: U32,  _mode: Phase,  _paren: U32,  _shut: Span,  _open: U32,  _on: Bool,  _pline: U32,  _pend: U32,  _pcol: U32) -> Walk:  check.rebuild(ticks, Args{}, 1, bracket, brace, angle, Span{0, 0, 0}, ln, False{}, 0, 0, 0, spans)# `)` ends the parameter list, and notes where it sitsdef check.ended(  ticks: Nat,  _mode: Phase,  paren: U32,  bracket: U32,  brace: U32,  angle: U32,  _shut: Span,  open: U32,  on: Bool,  pline: U32,  pend: U32,  pcol: U32,  spans: List<&2, Span>,  +ln: U32,  cl: U32) -> Walk:  check.rebuild(ticks, Shut{}, check.dec_u(paren), bracket, brace, angle, Span{ln, ln, cl}, open, False{},    0, 0, 0, check.cons(on, pline, pend, pcol, spans))# a comma closes the parameter that was opendef check.commaed(  ticks: Nat,  mode: Phase,  paren: U32,  bracket: U32,  brace: U32,  angle: U32,  shut: Span,  open: U32,  on: Bool,  pline: U32,  pend: U32,  pcol: U32,  spans: List<&2, Span>) -> Walk:  check.rebuild(ticks, mode, paren, bracket, brace, angle, shut, open, False{}, 0, 0, 0,    check.cons(on, pline, pend, pcol, spans))# a run of `>` lowers the angle depthdef check.unangled(  ticks: Nat,  mode: Phase,  paren: U32,  bracket: U32,  brace: U32,  angle: U32,  shut: Span,  open: U32,  on: Bool,  pline: U32,  pend: U32,  pcol: U32,  spans: List<&2, Span>) -> Walk:  check.rebuild(0n, mode, paren, bracket, brace, check.sub(ticks, angle), shut, open, on, pline, pend, pcol, spans)# a `->` on the `)` line puts the return type there; on a later line it does notdef check.turn(+ln: U32, shut: Span) -> Phase:  Span{+line, _end, _col} = shut  Bool.pick(Phase, U32.is_eq(ln, line), Past{}, Loose{})# the token's motion applied to fields already taken off the walkdef check.apply_on(  motion: Act,  mode: Phase,  paren: U32,  bracket: U32,  brace: U32,  angle: U32,  +shut: Span,  open: U32,  on: Bool,  pline: U32,  pend: U32,  pcol: U32,  spans: List<&2, Span>,  +ln: U32,  cl: U32,  ticks: Nat) -> Walk:  match motion:    case AOpen{}:      check.opened(ticks, bracket, brace, angle, spans, ln, mode, paren, shut, open, on, pline, pend, pcol)    case AParen{}:      check.rebuild(ticks, mode, (paren + 1 : U32), bracket, brace, angle, shut, open, on, pline, pend, pcol, spans)    case AEnd{}:      check.ended(ticks, mode, paren, bracket, brace, angle, shut, open, on, pline, pend, pcol, spans, ln, cl)    case AUnparen{}:      check.rebuild(ticks, mode, check.dec_u(paren), bracket, brace, angle, shut, open, on, pline, pend, pcol, spans)    case ABrack{}:      check.rebuild(ticks, mode, paren, (bracket + 1 : U32), brace, angle, shut, open, on, pline, pend, pcol, spans)    case AUnbrack{}:      check.rebuild(ticks, mode, paren, check.dec_u(bracket), brace, angle, shut, open, on, pline, pend, pcol, spans)    case ABrace{}:      check.rebuild(ticks, mode, paren, bracket, (brace + 1 : U32), angle, shut, open, on, pline, pend, pcol, spans)    case AUnbrace{}:      check.rebuild(ticks, mode, paren, bracket, check.dec_u(brace), angle, shut, open, on, pline, pend, pcol, spans)    case AAngle{}:      check.rebuild(ticks, mode, paren, bracket, brace, (angle + 1 : U32), shut, open, on, pline, pend, pcol, spans)    case AUnangle{}:      check.unangled(ticks, mode, paren, bracket, brace, angle, shut, open, on, pline, pend, pcol, spans)    case AComma{}:      check.commaed(ticks, mode, paren, bracket, brace, angle, shut, open, on, pline, pend, pcol, spans)    case AArrow{}:      check.rebuild(ticks, check.turn(ln, shut), paren, bracket, brace, angle, shut, open, on, pline, pend, pcol, spans)    case AStray{}:      check.rebuild(ticks, Loose{}, paren, bracket, brace, angle, shut, open, on, pline, pend, pcol, spans)    case ANone{}:      check.rebuild(ticks, mode, paren, bracket, brace, angle, shut, open, on, pline, pend, pcol, spans)# the token's motion applied to the walkdef check.apply(motion: Act, wk: Walk, +ln: U32, cl: U32, ticks: Nat) -> Walk:  Walk{mode, paren, bracket, brace, angle, shut, open, on, pline, pend, pcol, spans} = wk  check.apply_on(motion, mode, paren, bracket, brace, angle, shut, open, on, pline, pend, pcol, spans, ln, cl, ticks)# the same parameter, extended to this linedef check.note_extend(  +pline: U32,  _pend: U32,  +pcol: U32,  +ln: U32,  _cl: U32,  mode: Phase,  paren: U32,  bracket: U32,  brace: U32,  angle: U32,  shut: Span,  open: U32,  spans: List<&2, Span>) -> Walk:  Walk{mode, paren, bracket, brace, angle, shut, open, True{}, pline, ln, pcol, spans}# a parameter starting heredef check.note_begin(  _pline: U32,  _pend: U32,  _pcol: U32,  +ln: U32,  +cl: U32,  mode: Phase,  paren: U32,  bracket: U32,  brace: U32,  angle: U32,  shut: Span,  open: U32,  spans: List<&2, Span>) -> Walk:  Walk{mode, paren, bracket, brace, angle, shut, open, True{}, ln, ln, cl, spans}# the token continues the open parameter, or starts onedef check.note_on(  on: Bool,  mode: Phase,  paren: U32,  bracket: U32,  brace: U32,  angle: U32,  shut: Span,  open: U32,  pline: U32,  pend: U32,  pcol: U32,  spans: List<&2, Span>,  +ln: U32,  +cl: U32) -> Walk:  match on:    case True{}:      check.note_extend(pline, pend, pcol, ln, cl, mode, paren, bracket, brace, angle, shut, open, spans)    case False{}:      check.note_begin(pline, pend, pcol, ln, cl, mode, paren, bracket, brace, angle, shut, open, spans)# outside the parameter list the token starts nothingdef check.note_skip(  on: Bool,  mode: Phase,  paren: U32,  bracket: U32,  brace: U32,  angle: U32,  shut: Span,  open: U32,  pline: U32,  pend: U32,  pcol: U32,  spans: List<&2, Span>,  _tok: Lex.Tok) -> Walk:  Walk{mode, paren, bracket, brace, angle, shut, open, on, pline, pend, pcol, spans}# inside the parameter list, the token's position joins the open parameterdef check.note_here(  on: Bool,  mode: Phase,  paren: U32,  bracket: U32,  brace: U32,  angle: U32,  shut: Span,  open: U32,  pline: U32,  pend: U32,  pcol: U32,  spans: List<&2, Span>,  tok: Lex.Tok) -> Walk:  Lex.Tok{_kk, _tx, +ln, +cl} = tok  check.note_on(on, mode, paren, bracket, brace, angle, shut, open, pline, pend, pcol, spans, ln, cl)# inside the list the token is part of a parameter; outside it is notdef check.note_phase(  mode: Phase,  on: Bool,  paren: U32,  bracket: U32,  brace: U32,  angle: U32,  shut: Span,  open: U32,  pline: U32,  pend: U32,  pcol: U32,  spans: List<&2, Span>,  tok: Lex.Tok) -> Walk:  match mode:    case Args{}:      check.note_here(on, Args{}, paren, bracket, brace, angle, shut, open, pline, pend, pcol, spans, tok)    case other:      check.note_skip(on, other, paren, bracket, brace, angle, shut, open, pline, pend, pcol, spans, tok)# a token that belongs to a parameter notes where that parameter sitsdef check.note_args(wk: Walk, tok: Lex.Tok) -> Walk:  Walk{mode, paren, bracket, brace, angle, shut, open, on, pline, pend, pcol, spans} = wk  check.note_phase(mode, on, paren, bracket, brace, angle, shut, open, pline, pend, pcol, spans, tok)# a token the parameter list itself consumeddef check.drop_tok(_tok: Lex.Tok, wk: Walk) -> Walk:  wk# note the token when it is part of a parameterdef check.maybe_note(sep: Bool, wk: Walk, tok: Lex.Tok) -> Walk:  match sep:    case True{}:      check.drop_tok(tok, wk)    case False{}:      check.note_args(wk, tok)# one significant tokendef check.step_hit(+wk: Walk, +tok: Lex.Tok, glued: Bool) -> Walk:  Walk{+mode, +paren, +bracket, +brace, +angle, _shut, _open, _on, _pline, _pend, _pcol, _spans} = wk  Lex.Tok{+kk, +tx, +ln, cl} = tok  +motion = check.act(mode, kk, tx, glued, paren, angle, brace, bracket)  check.maybe_note(check.is_sep(motion), check.apply(motion, wk, ln, cl, check.ticks_of(tx)), tok)# a space, a newline or a comment changes nothingdef check.step_skip(_tok: Lex.Tok, wk: Walk, _glued: Bool) -> Walk:  wk# a significant token is read; a space, a newline or a comment is notdef check.step_on(sig: Bool, +tok: Lex.Tok, wk: Walk, glued: Bool) -> Walk:  match sig:    case True{}:      check.step_hit(wk, tok, glued)    case False{}:      check.step_skip(tok, wk, glued)# one token of the headerdef check.step(+tok: Lex.Tok, wk: Walk, glued: Bool) -> Walk:  Lex.Tok{+kk, _tx, _ln, _cl} = tok  check.step_on(Lex.significant(kk), tok, wk, glued)# the parameter still open at the end of the headerdef check.seal(wk: Walk) -> Walk:  Walk{mode, paren, bracket, brace, angle, shut, open, on, pline, pend, pcol, spans} = wk  Walk{mode, paren, bracket, brace, angle, shut, open, False{}, 0, 0, 0, check.cons(on, pline, pend, pcol, spans)}# a name glues a following `<`def check.glue_of(tok: Lex.Tok) -> Bool:  Lex.Tok{kk, _tx, _ln, _cl} = tok  Lex.is_name(kk)# every token of the headerdef check.walk(toks: List<&2, Lex.Tok>, wk: Walk, glued: Bool) -> Walk:  match toks:    case Nil{}:      check.seal(wk)    case Con{+tok, rest}:      check.walk(rest, check.step(tok, wk, glued), check.glue_of(tok))# another parameter already sits on this linedef check.shares(spans: List<&2, Span>, +ln: U32) -> Bool:  match spans:    case Nil{}:      False{}    case Con{Span{+line, _end, _col}, rest}:      Lazy.or_else(U32.is_eq(line, ln), _u => check.shares(rest, ln))# split across lines, sitting on the `(` line, or sharing its linedef check.bad(sp: Span, +open: U32, spans: List<&2, Span>) -> Bool:  Span{+line, +end, _col} = sp  Lazy.or_else(Bool.not(U32.is_eq(line, end)),    _u => Lazy.or_else(U32.is_eq(line, open), _u2 => check.shares(spans, line)))# the first parameter that is not alone on its own linedef check.judge(spans: List<&2, Span>, +open: U32) -> Maybe<&2, Span>:  match spans:    case Nil{}:      None{}    case Con{+sp, +rest}:      Lazy.stop(Maybe<&2, Span>, check.bad(sp, open, rest), Some{sp}, _u => check.judge(rest, open))# the first parameter that breaks the shape, in source orderdef check.jam_span(wk: Walk) -> Maybe<&2, Span>:  Walk{_mode, _paren, _bracket, _brace, _angle, _shut, +open, _on, _pline, _pend, _pcol, spans} = wk  check.judge(List.reverse(&2, Span, spans), open)# the last parameter (the head: spans are reversed) runs onto the `)` linedef check.tight(spans: List<&2, Span>, +close: U32) -> Bool:  match spans:    case Nil{}:      False{}    case Con{Span{_line, +end, _col}, _rest}:      Bool.not(U32.is_lt(end, close))# the `)`, when it shares the last parameter's linedef check.shut_at(shut: Span, spans: List<&2, Span>) -> Maybe<&2, Span>:  Span{+line, end, +col} = shut  Bool.pick(Maybe<&2, Span>, check.tight(spans, line), Some{Span{line, end, col}}, None{})# the `)` of a list that did close, when it is not on a line after the last# parameterdef check.shut_span(wk: Walk) -> Maybe<&2, Span>:  Walk{mode, _paren, _bracket, _brace, _angle, shut, _open, _on, _pline, _pend, _pcol, spans} = wk  match mode:    case Seek{}:      None{}    case Args{}:      None{}    case other:      check.shut_at(shut, spans)# the `)` with no `->` right after it on its linedef check.loose_span(wk: Walk) -> Maybe<&2, Span>:  Walk{mode, _paren, _bracket, _brace, _angle, shut, _open, _on, _pline, _pend, _pcol, _spans} = wk  match mode:    case Shut{}:      Some{shut}    case Loose{}:      Some{shut}    case other:      None{}# the `(` line, when the list holds no parameterdef check.none_at(spans: List<&2, Span>, +open: U32) -> Maybe<&2, Span>:  match spans:    case Nil{}:      Some{Span{open, open, 0}}    case Con{_sp, _rest}:      None{}# a parameter list that opened and holds no parameterdef check.empty_span(wk: Walk) -> Maybe<&2, Span>:  Walk{mode, _paren, _bracket, _brace, _angle, _shut, +open, _on, _pline, _pend, _pcol, spans} = wk  match mode:    case Seek{}:      None{}    case other:      check.none_at(spans, open)# the return type off the `)` line, as a findingdef check.place_loose(  mm: Maybe<&2, Span>,  +base: U32,  +path: String,  +more: List<&2, F.Finding>) -> List<&2, F.Finding>:  match mm:    case None{}:      more    case Some{Span{+line, _end, +col}}:      F.Finding{path, (base + line : U32), col, 0, "wrap",        "The return type is not on the `)` line; write `) -> T` on one line."}        <> more# the `)` on the last parameter's line, as a finding, else the return type# off the `)` linedef check.place_shut(  mm: Maybe<&2, Span>,  loose: Maybe<&2, Span>,  +base: U32,  +path: String,  +more: List<&2, F.Finding>) -> List<&2, F.Finding>:  match mm:    case None{}:      check.place_loose(loose, base, path, more)    case Some{Span{+line, _end, +col}}:      F.Finding{path, (base + line : U32), col, 0, "wrap",        "The `)` shares a line with the last parameter; put `)` and the return type on a line of their own."}        <> more# an empty parameter list across lines, as a finding, else a misplaced `)`def check.place_empty(  mm: Maybe<&2, Span>,  shut: Maybe<&2, Span>,  loose: Maybe<&2, Span>,  +base: U32,  +path: String,  +more: List<&2, F.Finding>) -> List<&2, F.Finding>:  match mm:    case None{}:      check.place_shut(shut, loose, base, path, more)    case Some{Span{+line, _end, +col}}:      F.Finding{path, (base + line : U32), col, 0, "wrap",        "This def header has no parameters but spans several lines; put it on one line."}        <> more# the parameter that breaks the shape, else an empty list, a misplaced `)` or# a return type off its line, as a finding on the header's linesdef check.place(  mm: Maybe<&2, Span>,  empty: Maybe<&2, Span>,  shut: Maybe<&2, Span>,  loose: Maybe<&2, Span>,  +base: U32,  +path: String,  +more: List<&2, F.Finding>) -> List<&2, F.Finding>:  match mm:    case None{}:      check.place_empty(empty, shut, loose, base, path, more)    case Some{Span{+line, _end, +col}}:      F.Finding{path, (base + line : U32), col, 0, "wrap",        "This wrapped def header does not have one parameter per line; put each parameter on its own line."}        <> more# a multi-line header that is not one parameter per line, holds no parameter,# or whose `)` shares the last parameter's line or has no `->` after itdef check.jam(+line: U32, toks: List<&2, Lex.Tok>, +path: String, +more: List<&2, F.Finding>) -> List<&2, F.Finding>:  +wk = check.walk(toks, check.start(), False{})  check.place(check.jam_span(wk), check.empty_span(wk), check.shut_span(wk), check.loose_span(wk), line, path, more)# a one-line header past 120def check.wide(+line: U32, toks: List<&2, Lex.Tok>, +path: String, +more: List<&2, F.Finding>) -> List<&2, F.Finding>:  Lazy.stop(List<&2, F.Finding>, U32.is_gt(check.width(toks), 120),    F.Finding{path, line, 120, 0, "wrap",      "This def header is longer than 120 characters; wrap it with one parameter per line."} <> more, _u => more)# a broken header is judged by its shape; a one-line header by its widthdef check.header(  multi: Bool,  +line: U32,  toks: List<&2, Lex.Tok>,  +path: String,  +more: List<&2, F.Finding>) -> List<&2, F.Finding>:  match multi:    case True{}:      check.jam(line, toks, path, more)    case False{}:      check.wide(line, toks, path, more)# a def header's tokens, judgeddef check.lexed(+line: U32, +toks: List<&2, Lex.Tok>, +path: String, +more: List<&2, F.Finding>) -> List<&2, F.Finding>:  check.header(check.broken(toks), line, toks, path, more)# a def header; anything else is not this rule'sdef check.one(  kk: Outline.ItemKind,  +line: U32,  +sig: String,  +path: String,  +more: List<&2, F.Finding>) -> List<&2, F.Finding>:  Lazy.stop(List<&2, F.Finding>, Bool.not(Outline.is_def(kk)), more,    _u => check.lexed(line, Lex.tokens(sig), path, more))# every def header of the filedef check.go(items: List<&2, Outline.Item>, +path: String) -> List<&2, F.Finding>:  match items:    case Nil{}:      Nil{}    case Con{Outline.Item{+kk, _name, +line, +sig, _doc, _pp}, rest}:      +more = check.go(rest, path)      check.one(kk, line, sig, path, more)# the ruledef check(ss: Src.Src) -> List<&2, F.Finding>:  Src.Src{+path, _text, _toks, _tree, _bound, items} = ss  check.go(items, path)