~/bend-docscommunity

main.bend source

main.bend on the hub · documented module

import Baseimport ./types.bend as Timport 0xd684886d10b431b9dce6c3b2d1ef1980/main.bend as V# Buffer and helpers are representation-private by API convention.type Source is Type:  Buffer{file: U32, size: U32, chars: V.Vec<Char>, starts: V.Vec<U32>}def Source.maximum() -> U32:  16777215def scalar(+c: Char) -> Bool:  +u = Char.to_u32(c)  Bool.and(U32.is_le(u, 1114111), Bool.or(U32.is_lt(u, 55296), U32.is_gt(u, 57343)))def finish_push(id: U32, n: U32, chars: V.Vec<Char>, lines: V.Vec<U32>, r: Result<V.Error,Unit>) -> Result<T.Error,Source>:  match r:    case Fail{e}: Fail{T.Limit{}}    case Done{x}: Done{Buffer{id,n,chars,lines}}def finish_line(id: U32, n: U32, chars: V.Vec<Char>, pair: V.Vec<U32> & Result<V.Error,Unit>) -> Result<T.Error,Source>:  (lines,r) = pair  finish_push(id,n,chars,lines,r)def add_line(id: U32, +n: U32, chars: V.Vec<Char>, lines: V.Vec<U32>, newline: Bool) -> Result<T.Error,Source>:  match newline:    case False{}: Done{Buffer{id,n,chars,lines}}    case True{}:      finish_line(id,n,chars,V.Vec.push(U32,lines,n))def add_char_result(id: U32, n: U32, chars: V.Vec<Char>, lines: V.Vec<U32>, newline: Bool, r: Result<V.Error,Unit>) -> Result<T.Error,Source>:  match r:    case Fail{e}: Fail{T.Limit{}}    case Done{x}: add_line(id,n,chars,lines,newline)def finish_char(id: U32, n: U32, lines: V.Vec<U32>, newline: Bool, pair: V.Vec<Char> & Result<V.Error,Unit>) -> Result<T.Error,Source>:  (chars,r) = pair  add_char_result(id,n,chars,lines,newline,r)def add_valid(s: Source, +c: Char, valid: Bool) -> Result<T.Error,Source>:  match s valid:    case Buffer{id,n,chars,lines} False{}: Fail{T.InvalidScalar{}}    case Buffer{id,n,chars,lines} True{}:      finish_char(id,(n + 1 : U32),lines,Char.is_eq(c,'\n'),V.Vec.push(Char,chars,c))def add(s: Result<T.Error,Source>, +c: Char) -> Result<T.Error,Source>:  match s:    case Fail{e}: Fail{e}    case Done{src}: add_valid(src,c,scalar(c))def build(text: String, s: Result<T.Error,Source>) -> Result<T.Error,Source>:  match text:    case SNil{}: s    case SCon{c,tail}: build(tail,add(s,c))def Source.bounded(file: U32, text: String, limit: U32) -> Result<T.Error,Source>:  build(text,finish_line(file,0,V.Vec.bounded(Char,U32.min(limit,Source.maximum())),V.Vec.push(U32,V.Vec.new(U32),0)))def Source.new(file: U32, text: String) -> Result<T.Error,Source>:  Source.bounded(file,text,Source.maximum())def Source.file(s: Source) -> Source & U32:  match s:    case Buffer{+id,n,chars,lines}: (Buffer{id,n,chars,lines},id)def Source.length(s: Source) -> Source & U32:  match s:    case Buffer{id,+n,chars,lines}: (Buffer{id,n,chars,lines},n)def count_result(id: U32, n: U32, chars: V.Vec<Char>, pair: V.Vec<U32> & U32) -> Source & U32:  (lines,count) = pair  (Buffer{id,n,chars,lines},count)def Source.line_count(s: Source) -> Source & U32:  match s:    case Buffer{id,n,chars,lines}:      count_result(id,n,chars,V.Vec.length(U32,lines))def chars_text(xs: List<Char>) -> String:  match xs:    case Nil{}: SNil{}    case Con{h,t}: SCon{h,chars_text(t)}def text_result(id: U32, n: U32, lines: V.Vec<U32>, pair: V.Vec<Char> & List<Char>) -> Source & String:  (chars,xs) = pair  (Buffer{id,n,chars,lines},chars_text(xs))def Source.text(s: Source) -> Source & String:  match s:    case Buffer{id,n,chars,lines}:      text_result(id,n,lines,V.Vec.to_list(Char,chars))def char_result(r: Result<V.Error,Char>) -> Result<T.Error,Char>:  match r:    case Fail{e}: Fail{T.Bounds{}}    case Done{c}: Done{c}def get_result(id: U32, n: U32, lines: V.Vec<U32>, pair: V.Vec<Char> & Result<V.Error,Char>) -> Source & Result<T.Error,Char>:  (chars,r) = pair  (Buffer{id,n,chars,lines},char_result(r))def Source.get(s: Source, i: U32) -> Source & Result<T.Error,Char>:  match s:    case Buffer{id,n,chars,lines}:      get_result(id,n,lines,V.Vec.get(Char,chars,i))def cursor_if(s: Source, c: T.Cursor, valid: Bool) -> Source & Result<T.Error,T.Cursor>:  match valid:    case False{}: (s,Fail{T.Bounds{}})    case True{}: (s,Done{c})def Source.cursor(s: Source, +i: U32) -> Source & Result<T.Error,T.Cursor>:  match s:    case Buffer{+id,+n,chars,lines}:      cursor_if(Buffer{id,n,chars,lines},T.Cursor{id,i},U32.is_le(i,n))def Source.checkpoint(c: T.Cursor) -> T.Cursor:  cdef restore_if(s: Source, i: U32, same: Bool) -> Source & Result<T.Error,T.Cursor>:  match same:    case False{}: (s,Fail{T.ForeignFile{}})    case True{}: Source.cursor(s,i)def Source.restore(s: Source, c: T.Cursor) -> Source & Result<T.Error,T.Cursor>:  match s c:    case Buffer{+own,n,chars,lines} T.Cursor{id,i}:      restore_if(Buffer{own,n,chars,lines},i,U32.is_eq(id,own))def maybe_char(r: Result<T.Error,Char>) -> Result<T.Error,Maybe<Char>>:  match r:    case Fail{e}: Fail{e}    case Done{c}: Done{Some{c}}def peek_read(pair: Source & Result<T.Error,Char>) -> Source & Result<T.Error,Maybe<Char>>:  (s,r) = pair  (s,maybe_char(r))def peek_at(s: Source, i: U32, eof: Bool) -> Source & Result<T.Error,Maybe<Char>>:  match eof:    case True{}: (s,Done{None{}})    case False{}:      peek_read(Source.get(s,i))def peek_checked(s: Source, r: Result<T.Error,T.Cursor>) -> Source & Result<T.Error,Maybe<Char>>:  match s r:    case Buffer{id,n,chars,lines} Fail{e}: (Buffer{id,n,chars,lines},Fail{e})    case Buffer{id,+n,chars,lines} Done{T.Cursor{other,+i}}:      peek_at(Buffer{id,n,chars,lines},i,U32.is_eq(i,n))def peek_restored(pair: Source & Result<T.Error,T.Cursor>) -> Source & Result<T.Error,Maybe<Char>>:  (s,r) = pair  peek_checked(s,r)def Source.peek(s: Source, c: T.Cursor) -> Source & Result<T.Error,Maybe<Char>>:  peek_restored(Source.restore(s,c))def bumped(c: T.Cursor, r: Result<T.Error,Maybe<Char>>) -> Result<T.Error,T.Cursor & Maybe<Char>>:  match c r:    case T.Cursor{id,i} Fail{e}: Fail{e}    case T.Cursor{id,i} Done{None{}}: Done{(T.Cursor{id,i},None{})}    case T.Cursor{id,i} Done{Some{ch}}: Done{(T.Cursor{id,(i + 1 : U32)},Some{ch})}def bump_result(c: T.Cursor, pair: Source & Result<T.Error,Maybe<Char>>) -> Source & Result<T.Error,T.Cursor & Maybe<Char>>:  (s,r) = pair  (s,bumped(c,r))def Source.bump(s: Source, +c: T.Cursor) -> Source & Result<T.Error,T.Cursor & Maybe<Char>>:  bump_result(c,Source.peek(s,c))def span_if(s: Source, span: T.Span, valid: Bool) -> Source & Result<T.Error,T.Span>:  match valid:    case False{}: (s,Fail{T.InvalidRange{}})    case True{}: (s,Done{span})def Source.span(s: Source, +start: U32, +end: U32) -> Source & Result<T.Error,T.Span>:  match s:    case Buffer{+id,+n,chars,lines}:      span_if(Buffer{id,n,chars,lines},T.Span{id,start,end},Bool.and(U32.is_le(start,end),U32.is_le(end,n)))def slice_result(r: Result<V.Error,List<Char>>) -> Result<T.Error,String>:  match r:    case Fail{e}: Fail{T.InvalidRange{}}    case Done{xs}: Done{chars_text(xs)}def extract_result(id: U32, n: U32, lines: V.Vec<U32>, pair: V.Vec<Char> & Result<V.Error,List<Char>>) -> Source & Result<T.Error,String>:  (chars,r) = pair  (Buffer{id,n,chars,lines},slice_result(r))def extract_if(s: Source, a: U32, b: U32, same: Bool) -> Source & Result<T.Error,String>:  match s same:    case Buffer{id,n,chars,lines} False{}: (Buffer{id,n,chars,lines},Fail{T.ForeignFile{}})    case Buffer{id,n,chars,lines} True{}:      extract_result(id,n,lines,V.Vec.slice(Char,chars,a,b))def Source.extract(s: Source, span: T.Span) -> Source & Result<T.Error,String>:  match s span:    case Buffer{+own,n,chars,lines} T.Span{id,a,b}:      extract_if(Buffer{own,n,chars,lines},a,b,U32.is_eq(id,own))# Upper-bound search: greatest start <= offset. 25 fuel covers <= 2^24 lines.type Search is Data:  Searching{lo: U32, hi: U32}  Found{line: U32}  BadIndex{}def split_search(lo: U32, hi: U32, mid: U32, before: Bool) -> Search:  match before:    case True{}: Searching{lo,mid}    case False{}: Searching{mid,hi}def split_read(lo: U32, hi: U32, mid: U32, pos: U32, r: Result<V.Error,U32>) -> Search:  match r:    case Fail{e}: BadIndex{}    case Done{start}: split_search(lo,hi,mid,U32.is_lt(pos,start))def search_read(lo: U32, hi: U32, mid: U32, pos: U32, pair: V.Vec<U32> & Result<V.Error,U32>) -> V.Vec<U32> & Search:  (lines,r) = pair  (lines,split_read(lo,hi,mid,pos,r))def search_step(lines: V.Vec<U32>, +lo: U32, +hi: U32, pos: U32, close: Bool) -> V.Vec<U32> & Search:  match close:    case True{}: (lines,Found{lo})    case False{}:      +mid = (lo + ((hi - lo : U32) / 2 : U32) : U32)      search_read(lo,hi,mid,pos,V.Vec.get(U32,lines,mid))def search(fuel: Nat, +pos: U32, pair: V.Vec<U32> & Search) -> V.Vec<U32> & Search:  match fuel pair:    case 0n Tuple{lines,Searching{lo,hi}}: (lines,BadIndex{})    case 0n Tuple{lines,Found{line}}: (lines,Found{line})    case 0n Tuple{lines,BadIndex{}}: (lines,BadIndex{})    case 1n+f Tuple{lines,Found{line}}: (lines,Found{line})    case 1n+f Tuple{lines,BadIndex{}}: (lines,BadIndex{})    case 1n+f Tuple{lines,Searching{+lo,+hi}}:      search(f,pos,search_step(lines,lo,hi,pos,U32.is_le((hi - lo : U32),1)))def location_read(line: U32, pos: U32, r: Result<V.Error,U32>) -> Result<T.Error,T.Location>:  match r:    case Fail{e}: Fail{T.IndexInvariant{}}    case Done{start}: Done{T.Location{line,(pos - start : U32)}}def locate_read(id: U32, n: U32, chars: V.Vec<Char>, line: U32, pos: U32, pair: V.Vec<U32> & Result<V.Error,U32>) -> Source & Result<T.Error,T.Location>:  (lines,r) = pair  (Buffer{id,n,chars,lines},location_read(line,pos,r))def location_finish(id: U32, n: U32, chars: V.Vec<Char>, lines: V.Vec<U32>, pos: U32, state: Search) -> Source & Result<T.Error,T.Location>:  match state:    case BadIndex{}: (Buffer{id,n,chars,lines},Fail{T.IndexInvariant{}})    case Searching{lo,hi}: (Buffer{id,n,chars,lines},Fail{T.IndexInvariant{}})    case Found{+line}:      locate_read(id,n,chars,line,pos,V.Vec.get(U32,lines,line))def locate_searched(id: U32, n: U32, chars: V.Vec<Char>, pos: U32, pair: V.Vec<U32> & Search) -> Source & Result<T.Error,T.Location>:  (lines,state) = pair  location_finish(id,n,chars,lines,pos,state)def locate_counted(id: U32, n: U32, chars: V.Vec<Char>, +pos: U32, pair: V.Vec<U32> & U32) -> Source & Result<T.Error,T.Location>:  (lines,count) = pair  locate_searched(id,n,chars,pos,search(25n,pos,(lines,Searching{0,count})))def locate_if(s: Source, +pos: U32, valid: Bool) -> Source & Result<T.Error,T.Location>:  match s valid:    case Buffer{id,n,chars,lines} False{}: (Buffer{id,n,chars,lines},Fail{T.Bounds{}})    case Buffer{id,n,chars,lines} True{}:      locate_counted(id,n,chars,pos,V.Vec.length(U32,lines))def Source.locate(s: Source, +pos: U32) -> Source & Result<T.Error,T.Location>:  match s:    case Buffer{id,+n,chars,lines}:      locate_if(Buffer{id,n,chars,lines},pos,U32.is_le(pos,n))def offset_valid(start: U32, col: U32, valid: Bool) -> Result<T.Error,U32>:  match valid:    case False{}: Fail{T.Bounds{}}    case True{}: Done{(start + col : U32)}def offset_bound(+start: U32, +col: U32, next: Result<V.Error,U32>) -> Result<T.Error,U32>:  match next:    case Fail{e}: Fail{T.IndexInvariant{}}    case Done{end}: offset_valid(start,col,U32.is_lt(col,(end - start : U32)))def offset_next(start: U32, col: U32, pair: V.Vec<U32> & Result<V.Error,U32>) -> V.Vec<U32> & Result<T.Error,U32>:  (lines,b) = pair  (lines,offset_bound(start,col,b))def offset_line(lines: V.Vec<U32>, +line: U32, +col: U32, n: U32, start: Result<V.Error,U32>, last: Bool) -> V.Vec<U32> & Result<T.Error,U32>:  match start last:    case Fail{e} False{}: (lines,Fail{T.Bounds{}})    case Fail{e} True{}: (lines,Fail{T.Bounds{}})    case Done{+a} True{}: (lines,offset_valid(a,col,U32.is_le(col,(n - a : U32))))    case Done{a} False{}:      offset_next(a,col,V.Vec.get(U32,lines,(line + 1 : U32)))def offset_finish(id: U32, n: U32, chars: V.Vec<Char>, pair: V.Vec<U32> & Result<T.Error,U32>) -> Source & Result<T.Error,U32>:  (lines,r) = pair  (Buffer{id,n,chars,lines},r)def offset_read(id: U32, +n: U32, chars: V.Vec<Char>, line: U32, col: U32, last: Bool, pair: V.Vec<U32> & Result<V.Error,U32>) -> Source & Result<T.Error,U32>:  (lines,a) = pair  offset_finish(id,n,chars,offset_line(lines,line,col,n,a,last))def offset_counted(id: U32, n: U32, chars: V.Vec<Char>, +line: U32, col: U32, pair: V.Vec<U32> & U32) -> Source & Result<T.Error,U32>:  (lines,count) = pair  offset_read(id,n,chars,line,col,U32.is_eq(line,(count - 1 : U32)),V.Vec.get(U32,lines,line))def Source.offset(s: Source, loc: T.Location) -> Source & Result<T.Error,U32>:  match s loc:    case Buffer{id,n,chars,lines} T.Location{line,col}:      offset_counted(id,n,chars,line,col,V.Vec.length(U32,lines))