/*---------------------------------------------------------------------------
  Copyright 2012-2024, Microsoft Research, Daan Leijen.

  This is free software; you can redistribute it and/or modify it under the
  terms of the Apache License, Version 2.0. A copy of the License can be
  found in the LICENSE file at the root of this distribution.
---------------------------------------------------------------------------*/

// Efficient views on strings.
module std/core/sslicestd/core/sslice

import std/core/typesstd/core/types
import std/core/undivstd/core/undiv
import std/core/unsafestd/core/unsafe // unsafe-ptr-eq
import std/core/hndstd/core/hnd
import std/core/intstd/core/int
import std/core/stringstd/core/string

extern import
  c  file "inline/sslice"
  js file "inline/sslice.js"



// A `:sslice` represents a sub-slice of string and
// has a specific start position and character count. It is used
// instead of string indices to make the actual internal representation
// of strings abstract (like UTF-8 or UTF-16). String slices are
// returned by functions that find sub strings or patterns in
// in strings. Use `string:(slice : sslice) -> string` to
// create a fresh substring from a slice.
//
// The start and len fields of a slice are in terms of bytes.
// Slices should only be interacted with safe methods defined in core
// that take care to not cut strings in the middle of a utf codepoint.
abstract value struct sslicestd/core/sslice/sslice: V( strstd/core/sslice/sslice/str: (sslice : sslice) -> string : stringstd/core/types/string: V, startstd/core/sslice/sslice/start: (sslice : sslice) -> int : intstd/core/types/int: V, lenstd/core/sslice/sslice/len: (sslice : sslice) -> int : intstd/core/types/int: V )

// Internal export for the regex module
pub fun @new-sslice( strstr: string :stringstd/core/types/string: V, startstart: int: intstd/core/types/int: V, lenlen: int : intstd/core/types/int: V )result: -> total sslice
  Sslicestd/core/sslice/Sslice: (str : string, start : int, len : int) -> sslice(strstr: string,startstart: int,lenlen: int)

// Equality based on contents of the slice
// O(`n`+`m`) where `n` and `m` are the lengths of the two strings
pub fun (==)std/core/sslice/(==): (slice1 : sslice, slice2 : sslice) -> bool(slice1slice1: sslice: sslicestd/core/sslice/sslice: V, slice2slice2: sslice: sslicestd/core/sslice/sslice: V )result: -> total bool: boolstd/core/types/bool: V
  match (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)slice1slice1: sslice, slice2slice2: sslice)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)
    (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)Sslicestd/core/sslice/Sslice: (str : string, start : int, len : int) -> sslice(s1s1: string, start1start1: int, len1len1: int), Sslicestd/core/sslice/Sslice: (str : string, start : int, len : int) -> sslice(s2s2: string, start2start2: int, len2len2: int))std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b) ->
      if unsafe-ptr-eqstd/core/unsafe/unsafe-ptr-eq: (x : string, y : string) -> bool(s1s1: string,s2s2: string) &&std/core/types/(&&): (x : bool, y : bool) -> bool start1start1: int==std/core/int/(==): (x : int, y : int) -> boolstart2start2: int &&std/core/types/(&&): (x : bool, y : bool) -> bool len1len1: int==std/core/int/(==): (x : int, y : int) -> boollen2len2: int
        then Truestd/core/types/True: bool // fast path
        else slice1slice1: sslice.stringstd/core/sslice/string: (slice : sslice) -> string ==std/core/string/(==): (string, string) -> bool slice2slice2: sslice.stringstd/core/sslice/string: (slice : sslice) -> string

// Inequality based on contents of the slice
// O(`n`+`m`) where `n` and `m` are the lengths of the two strings
pub fun (!=)std/core/sslice/(!=): (slice1 : sslice, slice2 : sslice) -> bool(slice1slice1: sslice: sslicestd/core/sslice/sslice: V, slice2slice2: sslice: sslicestd/core/sslice/sslice: V )result: -> total bool: boolstd/core/types/bool: V
  !std/core/types/bool/(!): (b : bool) -> bool(slice1slice1: sslice ==std/core/sslice/(==): (slice1 : sslice, slice2 : sslice) -> bool slice2slice2: sslice)

// Equality of slices at the same offset and length on an equal string
// (The strings do not have to be referentially identical though)
pub fun (===)std/core/sslice/(===): (slice1 : sslice, slice2 : sslice) -> bool(slice1slice1: sslice: sslicestd/core/sslice/sslice: V, slice2slice2: sslice: sslicestd/core/sslice/sslice: V )result: -> total bool: boolstd/core/types/bool: V
  match (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)slice1slice1: sslice, slice2slice2: sslice)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)
    (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)Sslicestd/core/sslice/Sslice: (str : string, start : int, len : int) -> sslice(s1s1: string, start1start1: int, len1len1: int), Sslicestd/core/sslice/Sslice: (str : string, start : int, len : int) -> sslice(s2s2: string, start2start2: int, len2len2: int))std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b) -> (start1start1: int==std/core/int/(==): (x : int, y : int) -> boolstart2start2: int &&std/core/types/(&&): (x : bool, y : bool) -> bool len1len1: int==std/core/int/(==): (x : int, y : int) -> boollen2len2: int &&std/core/types/(&&): (x : bool, y : bool) -> bool s1s1: string==std/core/string/(==): (string, string) -> bools2s2: string)

// Inequality of slices at the same offset and length on the same string.
// (The strings do not have to be referentially identical though)
pub fun (!==)std/core/sslice/(!==): (slice1 : sslice, slice2 : sslice) -> bool(slice1slice1: sslice: sslicestd/core/sslice/sslice: V, slice2slice2: sslice: sslicestd/core/sslice/sslice: V )result: -> total bool: boolstd/core/types/bool: V
  !std/core/types/bool/(!): (b : bool) -> bool(slice1slice1: sslice===std/core/sslice/(===): (slice1 : sslice, slice2 : sslice) -> boolslice2slice2: sslice)

// O(n). Return the number of characters in a string slice
pub extern countstd/core/sslice/count: (slice : sslice) -> int( sliceslice: sslice : sslicestd/core/sslice/sslice: V ) : intstd/core/types/int: V
  c  "kk_slice_count"
  cs "Primitive.SliceCount"
  js "_sslice_count"

extern first1std/core/sslice/first1: (s : string) -> sslice(ss: string : stringstd/core/types/string: V ) : sslicestd/core/sslice/sslice: V
  c  "kk_slice_first"
  cs "Primitive.SliceFirst"
  js "_sslice_first"

extern last1std/core/sslice/last1: (s : string) -> sslice(ss: string : stringstd/core/types/string: V ) : sslicestd/core/sslice/sslice: V
  c  "kk_slice_last"
  cs "Primitive.SliceLast"
  js "_sslice_last"

// O(`n`). The first `n` (default = `1`) characters in a string.
pub fun firststd/core/sslice/first: (s : string, n : ? int) -> sslice(ss: string : stringstd/core/types/string: V, nn: ? int : intstd/core/types/int: V = 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
)result: -> total sslice : sslicestd/core/sslice/sslice: V val sliceslice: sslice = ss: string.first1std/core/sslice/first1: (s : string) -> sslice if nn: int==std/core/int/(==): (x : int, y : int) -> bool1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
then sliceslice: sslice else sliceslice: sslice.extendstd/core/sslice/extend: (slice : sslice, count : int) -> sslice( nn: int -std/core/int/(-): (x : int, y : int) -> int 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
) // O(`n`). The last `n` (default = `1`) characters in a string pub fun laststd/core/sslice/last: (s : string, n : ? int) -> sslice(ss: string : stringstd/core/types/string: V, nn: ? int : intstd/core/types/int: V = 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
)result: -> total sslice : sslicestd/core/sslice/sslice: V val sliceslice: sslice = ss: string.last1std/core/sslice/last1: (s : string) -> sslice if nn: int==std/core/int/(==): (x : int, y : int) -> bool1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
then sliceslice: sslice else sliceslice: sslice.advancestd/core/sslice/advance: (slice : sslice, count : int) -> sslice(1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
-std/core/int/(-): (x : int, y : int) -> int nn: int).extendstd/core/sslice/extend: (slice : sslice, count : int) -> sslice(nn: int -std/core/int/(-): (x : int, y : int) -> int 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
) // Convert the first character of a string to uppercase. pub fun capitalizestd/core/sslice/capitalize: (s : string) -> string( ss: string : stringstd/core/types/string: V )result: -> total string : stringstd/core/types/string: V ss: string.firststd/core/sslice/first: (s : string, n : ? int) -> sslice.stringstd/core/sslice/string: (slice : sslice) -> string.to-upperstd/core/string/to-upper: (s : string) -> string ++std/core/types/(++): (x : string, y : string) -> string ss: string.firststd/core/sslice/first: (s : string, n : ? int) -> sslice.afterstd/core/sslice/after: (slice : sslice) -> sslice.stringstd/core/sslice/string: (slice : sslice) -> string // O(1). The entire string as a slice pub fun slicestd/core/sslice/slice: (s : string) -> sslice( ss: string : stringstd/core/types/string: V )result: -> total sslice : sslicestd/core/sslice/sslice: V Sslicestd/core/sslice/Sslice: (str : string, start : int, len : int) -> sslice(ss: string,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
,ss: string.lengthstd/core/sslice/length: (s : string) -> int
) // An empty slice val emptystd/core/sslice/empty: sslice = Sslicestd/core/sslice/Sslice: (str : string, start : int, len : int) -> sslice(""literal: string
count= 0
,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) // Is a slice empty? pub fun is-emptystd/core/sslice/is-empty: (slice : sslice) -> bool( sliceslice: sslice : sslicestd/core/sslice/sslice: V )result: -> total bool : boolstd/core/types/bool: V !std/core/types/bool/(!): (b : bool) -> boolsliceslice: sslice.lenstd/core/sslice/sslice/len: (sslice : sslice) -> int.is-posstd/core/int/is-pos: (i : int) -> bool // An invalid slice val invalidstd/core/sslice/invalid: sslice = Sslicestd/core/sslice/Sslice: (str : string, start : int, len : int) -> sslice(""literal: string
count= 0
,-1literal: int
dec = -1
hex8 = 0xFF
bit8 = 0b11111111
,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) // Is a slice invalid? pub fun is-validstd/core/sslice/is-valid: (slice : sslice) -> bool( sliceslice: sslice : sslicestd/core/sslice/sslice: V )result: -> total bool : boolstd/core/types/bool: V sliceslice: sslice.startstd/core/sslice/sslice/start: (sslice : sslice) -> int >=std/core/int/(>=): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
// Is a slice not empty? pub fun is-notemptystd/core/sslice/is-notempty: (slice : sslice) -> bool( sliceslice: sslice : sslicestd/core/sslice/sslice: V )result: -> total bool : boolstd/core/types/bool: V sliceslice: sslice.lenstd/core/sslice/sslice/len: (sslice : sslice) -> int.is-posstd/core/int/is-pos: (i : int) -> bool // Return the first character of a string as a string (or the empty string) pub fun headstd/core/sslice/head: (s : string) -> string( ss: string : stringstd/core/types/string: V )result: -> total string : stringstd/core/types/string: V ss: string.firststd/core/sslice/first: (s : string, n : ? int) -> sslice.stringstd/core/sslice/string: (slice : sslice) -> string // Return the tail of a string (or the empty string) pub fun tailstd/core/sslice/tail: (s : string) -> string( ss: string : stringstd/core/types/string: V )result: -> total string : stringstd/core/types/string: V ss: string.firststd/core/sslice/first: (s : string, n : ? int) -> sslice.afterstd/core/sslice/after: (slice : sslice) -> sslice.stringstd/core/sslice/string: (slice : sslice) -> string // Length returns the length in the platform specific encoding (and should not be exported) inline extern lengthstd/core/sslice/length: (s : string) -> int( s : stringstd/core/types/string: V ) : intstd/core/types/int: V c inline "kk_string_len_int(#1,kk_context())" cs inline "#1.Length" js inline "#1.length" // Return the common prefix of two strings (upto `upto` characters (default is minimum length of the two strings)) pub extern common-prefixstd/core/sslice/common-prefix: (s : string, t : string, upto : ? int) -> sslice(ss: string : stringstd/core/types/string: V, tt: string : stringstd/core/types/string: V, ^uptoupto: ? int : intstd/core/types/int: V = -1literal: int
dec = -1
hex8 = 0xFF
bit8 = 0b11111111
) : sslicestd/core/sslice/sslice: V c "kk_slice_common_prefix_borrow" cs "Primitive.SliceCommonPrefix" js "_sslice_common_prefix"
// O(`count`). Advance the start position of a string slice by `count` characters // up to the end of the string. // A negative `count` advances the start position backwards upto the first position // in a string. // Maintains the character count of the original slice upto the end of the string. // For example: // // * `"abc".first.advance(1).string == "b"`, // * `"abc".first.advance(3).string == ""`, // * `"abc".last.advance(-1).string == "b"`. // pub extern advancestd/core/sslice/advance: (slice : sslice, count : int) -> sslice( sliceslice: sslice : sslicestd/core/sslice/sslice: V, ^countcount: int : intstd/core/types/int: V ) : sslicestd/core/sslice/sslice: V c "kk_slice_advance_borrow" cs "Primitive.SliceAdvance" js "_sslice_advance" // O(`count`). Extend a string slice by `count` characters up to the end of the string. // A negative `count` shrinks the slice up to the empty slice. // For example: // // * `"abc".first.extend(1).string == "ab"` // * `"abc".last.extend(-1).string == ""` // pub extern extendstd/core/sslice/extend: (slice : sslice, count : int) -> sslice( sliceslice: sslice : sslicestd/core/sslice/sslice: V, ^countcount: int : intstd/core/types/int: V ) : sslicestd/core/sslice/sslice: V c "kk_slice_extend_borrow" cs "Primitive.SliceExtend" js "_sslice_extend" // O(1). Return the string slice from the start of a string up to the // start of `slice` argument. pub fun beforestd/core/sslice/before: (slice : sslice) -> sslice(sliceslice: sslice : sslicestd/core/sslice/sslice: V)result: -> total sslice : sslicestd/core/sslice/sslice: V val Sslicestd/core/sslice/Sslice: (str : string, start : int, len : int) -> sslice(ss: string,startstart: int,_len) = sliceslice: sslice Sslicestd/core/sslice/Sslice: (str : string, start : int, len : int) -> sslice(ss: string,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
,startstart: int
) // O(1). Return the string slice from the end of `slice` argument // to the end of the string. pub fun afterstd/core/sslice/after: (slice : sslice) -> sslice(sliceslice: sslice : sslicestd/core/sslice/sslice: V)result: -> total sslice : sslicestd/core/sslice/sslice: V val Sslicestd/core/sslice/Sslice: (str : string, start : int, len : int) -> sslice(ss: string,startstart: int,lenlen: int) = sliceslice: sslice Sslicestd/core/sslice/Sslice: (str : string, start : int, len : int) -> sslice(ss: string,startstart: int+std/core/int/(+): (x : int, y : int) -> intlenlen: int,ss: string.lengthstd/core/sslice/length: (s : string) -> int -std/core/int/(-): (x : int, y : int) -> int (startstart: int+std/core/int/(+): (x : int, y : int) -> intlenlen: int)) // O(n). Copy the `slice` argument into a fresh string. // Takes O(1) time if the slice covers the entire string. pub extern stringstd/core/sslice/string: (slice : sslice) -> string( sliceslice: sslice : sslicestd/core/sslice/sslice: V ) : stringstd/core/types/string: V c "kk_slice_to_string" cs "Primitive.SliceToString" js "_slice_to_string" // If the slice is not empty, // return the first character, and a new slice that is advanced by 1. pub extern nextstd/core/sslice/next: (slice : sslice) -> maybe<(char, sslice)>( sliceslice: sslice : sslicestd/core/sslice/sslice: V ) : maybestd/core/types/maybe: V -> V<(std/core/types/tuple2: (V, V) -> Vcharstd/core/types/char: V,sslicestd/core/sslice/sslice: V)> c "kk_slice_next" cs "Primitive.SliceNext" js "_sslice_next" // Truncates a slice to length 0 pub fun truncatestd/core/sslice/truncate: (slice : sslice) -> sslice( sliceslice: sslice: sslicestd/core/sslice/sslice: V )result: -> total sslice: sslicestd/core/sslice/sslice: V Sslicestd/core/sslice/Sslice: (str : string, start : int, len : int) -> sslice(sliceslice: sslice.strstd/core/sslice/sslice/str: (sslice : sslice) -> string, sliceslice: sslice.startstd/core/sslice/sslice/start: (sslice : sslice) -> int, 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) // Gets up to (`end`-`start`) characters from the slice beginning from `start`. // If either start or end is negative, returns the original slice pub fun subslicestd/core/sslice/subslice: (slice : sslice, start : int, end : int) -> sslice( sliceslice: sslice: sslicestd/core/sslice/sslice: V, startstart: int : intstd/core/types/int: V, endend: int : intstd/core/types/int: V )result: -> total sslice: sslicestd/core/sslice/sslice: V if startstart: int <std/core/int/(<): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
||std/core/types/(||): (x : bool, y : bool) -> bool endend: int <std/core/int/(<): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
then sliceslice: sslice else // Advances to start, zeros the length, and then extends (end - start characters) sliceslice: sslice.advancestd/core/sslice/advance: (slice : sslice, count : int) -> sslice(startstart: int).truncatestd/core/sslice/truncate: (slice : sslice) -> sslice.extendstd/core/sslice/extend: (slice : sslice, count : int) -> sslice(endend: int -std/core/int/(-): (x : int, y : int) -> int startstart: int
) // Gets a slice that only includes up to n characters from the start of the slice. pub fun takestd/core/sslice/take: (slice : sslice, n : int) -> sslice( sliceslice: sslice: sslicestd/core/sslice/sslice: V, nn: int : intstd/core/types/int: V)result: -> total sslice: sslicestd/core/sslice/sslice: V if nn: int <=std/core/int/(<=): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
then returnreturn: sslice sliceslice: sslice else sliceslice: sslice.truncatestd/core/sslice/truncate: (slice : sslice) -> sslice.extendstd/core/sslice/extend: (slice : sslice, count : int) -> sslice(nn: int
) // Gets a slice that drops the first n characters, shrinking the length of the slice by n accordingly. // If the slice does not have n characters, then the slice is shrunk to an empty slice. // // If maintaining the length of the slice is important, use `advance` instead. pub fun dropstd/core/sslice/drop: (slice : sslice, n : int) -> sslice( sliceslice: sslice: sslicestd/core/sslice/sslice: V, nn: int : intstd/core/types/int: V)result: -> total sslice: sslicestd/core/sslice/sslice: V if nn: int <=std/core/int/(<=): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
then returnreturn: sslice sliceslice: sslice else sliceslice: sslice.advancestd/core/sslice/advance: (slice : sslice, count : int) -> sslice(nn: int).truncatestd/core/sslice/truncate: (slice : sslice) -> sslice.extendstd/core/sslice/extend: (slice : sslice, count : int) -> sslice(sliceslice: sslice.countstd/core/sslice/count: (slice : sslice) -> int -std/core/int/(-): (x : int, y : int) -> int nn: int
) // Apply a function for each character in a string slice. // If `action` returns `Just`, the function returns immediately with that result. pub fun foreach-whilestd/core/sslice/foreach-while: forall<a,e> (slice : sslice, action : (c : char) -> e maybe<a>) -> e maybe<a>( sliceslice: sslice : sslicestd/core/sslice/sslice: V, actionaction: (c : char) -> $637 maybe<$636> : (c : charstd/core/types/char: V) -> ee: E maybestd/core/types/maybe: V -> V<aa: V> )result: -> 691 maybe<690> : ee: E maybestd/core/types/maybe: V -> V<aa: V> match sliceslice: sslice.nextstd/core/sslice/next: (slice : sslice) -> $637 maybe<(char, sslice)> Nothingstd/core/types/Nothing: forall<a> maybe<a> -> Nothingstd/core/types/Nothing: forall<a> maybe<a> Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>((std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)cc: char,restrest: sslice)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)) -> match actionaction: (c : char) -> $637 maybe<$636>(cc: char) Nothingstd/core/types/Nothing: forall<a> maybe<a> -> foreach-whilestd/core/sslice/foreach-while: (slice : sslice, action : (c : char) -> $637 maybe<$636>) -> $637 maybe<$636>(pretend-decreasingstd/core/undiv/pretend-decreasing: (x : sslice) -> $637 sslice(restrest: sslice),actionaction: (c : char) -> $637 maybe<$636>) resres: maybe<$636> -> resres: maybe<$636> // Apply a function for each character in a string slice. pub fun foreachstd/core/sslice/foreach: forall<e> (slice : sslice, action : (c : char) -> e ()) -> e ()( sliceslice: sslice : sslicestd/core/sslice/sslice: V, actionaction: (c : char) -> $738 () : (c:charstd/core/types/char: V) -> ee: E (std/core/types/unit: V)std/core/types/unit: V)result: -> 766 () : ee: E (std/core/types/unit: V)std/core/types/unit: V foreach-whilestd/core/sslice/foreach-while: (slice : sslice, action : (c : char) -> $738 maybe<_754>) -> $738 maybe<_754>( sliceslice: sslice ) fnfn: (c : char) -> $738 maybe<_754>(cc: char) actionaction: (c : char) -> $738 ()(cc: char) Nothingstd/core/types/Nothing: forall<a> maybe<a> (std/core/types/Unit: ())std/core/types/Unit: () // Invoke a function for each character in a string. // If `action` returns `Just`, the function returns immediately with that result. pub fun string/foreach-whilestd/core/sslice/string/foreach-while: forall<a,e> (s : string, action : (c : char) -> e maybe<a>) -> e maybe<a>( ss: string : stringstd/core/types/string: V, actionaction: (c : char) -> $693 maybe<$692> : (c:charstd/core/types/char: V) -> ee: E maybestd/core/types/maybe: V -> V<aa: V> )result: -> 721 maybe<720> : ee: E maybestd/core/types/maybe: V -> V<aa: V> ss: string.slicestd/core/sslice/slice: (s : string) -> $693 sslice.foreach-whilestd/core/sslice/foreach-while: (slice : sslice, action : (c : char) -> $693 maybe<$692>) -> $693 maybe<$692>(actionaction: (c : char) -> $693 maybe<$692>) // Invoke a function for each character in a string pub fun string/foreachstd/core/sslice/string/foreach: forall<e> (s : string, action : (c : char) -> e ()) -> e ()( ss: string : stringstd/core/types/string: V, actionaction: (c : char) -> $770 () : (c:charstd/core/types/char: V) -> ee: E (std/core/types/unit: V)std/core/types/unit: V )result: -> 788 () : ee: E (std/core/types/unit: V)std/core/types/unit: V ss: string.slicestd/core/sslice/slice: (s : string) -> $770 sslice.foreachstd/core/sslice/foreach: (slice : sslice, action : (c : char) -> $770 ()) -> $770 ()(actionaction: (c : char) -> $770 ()) // Return the first character of a string (or `Nothing` for the empty string). pub fun head-charstd/core/sslice/head-char: (s : string) -> maybe<char>( ss: string : stringstd/core/types/string: V )result: -> total maybe<char> : maybestd/core/types/maybe: V -> V<charstd/core/types/char: V> ss: string.foreach-whilestd/core/sslice/string/foreach-while: (s : string, action : (c : char) -> maybe<char>) -> maybe<char>( Juststd/core/types/Just: forall<a> (value : a) -> maybe<a> ) // Invoke a function for each character in a string //fun foreach( s : string, f : char -> e () ) : e () // s.list.foreach(f) // todo: optimize // // Count the number of times a predicate is true for each character in a string pub fun pred/countstd/core/sslice/pred/count: forall<e> (s : string, pred : (char) -> e bool) -> e int( ss: string : stringstd/core/types/string: V, predpred: (char) -> $792 bool : (charstd/core/types/char: V) -> ee: E boolstd/core/types/bool: V )result: -> 891 int : ee: E intstd/core/types/int: V var cntcnt: local-var<$801,int> := 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
ss: string.foreachstd/core/sslice/string/foreach: (s : string, action : (c : char) -> <local<$801>|$792> ()) -> <local<$801>|$792> () fnfn: (c : char) -> <local<$801>|$792> ()(cc: char) if mask<local_1: H>{predpred: (char) -> $792 bool(cc: char)} then cntcnt: local-var<$801,int> :=std/core/types/local-set: (v : local-var<$801,int>, assigned : int) -> <local<$801>|$792> () cntcnt: int+std/core/int/(+): (x : int, y : int) -> <local<$801>|$792> int1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
cntcnt: int
// Does string `s` contain the string `sub` ? inline extern xindex-ofstd/core/sslice/xindex-of: (s : string, sub : string) -> ssize_t(s : stringstd/core/types/string: V, sub : stringstd/core/types/string: V ) : ssize_tstd/core/types/ssize_t: V c inline "kk_string_index_of1(#1,#2,kk_context())" cs inline "((#1).IndexOf(#2) + 1)" js inline "((#1).indexOf(#2) + 1)" // O(n). If it occurs, return the position of substring `sub` in `s`, tupled with // the position just following the substring `sub`. pub fun findstd/core/sslice/find: (s : string, sub : string) -> maybe<sslice>( ss: string : stringstd/core/types/string: V, subsub: string : stringstd/core/types/string: V )result: -> total maybe<sslice> : maybestd/core/types/maybe: V -> V<sslicestd/core/sslice/sslice: V> val ii: int = ss: string.xindex-ofstd/core/sslice/xindex-of: (s : string, sub : string) -> ssize_t(subsub: string).intstd/core/int/ssize_t/int: (i : ssize_t) -> int if ii: int.is-zerostd/core/int/is-zero: (x : int) -> bool then Nothingstd/core/types/Nothing: forall<a> maybe<a> else Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(Sslicestd/core/sslice/Sslice: (str : string, start : int, len : int) -> sslice(ss: string,ii: int.decstd/core/int/dec: (i : int) -> int,subsub: string.lengthstd/core/sslice/length: (s : string) -> int)) // Does string `s` contain the string `sub` ? inline extern xlast-index-ofstd/core/sslice/xlast-index-of: (s : string, sub : string) -> ssize_t(s : stringstd/core/types/string: V, sub : stringstd/core/types/string: V ) : ssize_tstd/core/types/ssize_t: V c inline "kk_string_last_index_of1(#1,#2,kk_context())" cs inline "(#1.LastIndexOf(#2) + 1)" js inline "((#1).lastIndexOf(#2) + 1)" // Return the last index of substring `sub` in `s` if it occurs. pub fun find-laststd/core/sslice/find-last: (s : string, sub : string) -> maybe<sslice>( ss: string : stringstd/core/types/string: V, subsub: string : stringstd/core/types/string: V )result: -> total maybe<sslice> : maybestd/core/types/maybe: V -> V<sslicestd/core/sslice/sslice: V> val ii: int = ss: string.xlast-index-ofstd/core/sslice/xlast-index-of: (s : string, sub : string) -> ssize_t(subsub: string).intstd/core/int/ssize_t/int: (i : ssize_t) -> int if ii: int.is-zerostd/core/int/is-zero: (x : int) -> bool then Nothingstd/core/types/Nothing: forall<a> maybe<a> else Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(Sslicestd/core/sslice/Sslice: (str : string, start : int, len : int) -> sslice(ss: string,ii: int.decstd/core/int/dec: (i : int) -> int,subsub: string.lengthstd/core/sslice/length: (s : string) -> int)) inline extern xstarts-withstd/core/sslice/xstarts-with: (s : string, pre : string) -> bool: (s : stringstd/core/types/string: V, pre : stringstd/core/types/string: V ) -> boolstd/core/types/bool: V c "kk_string_starts_with" cs inline "#1.StartsWith(#2)" js inline "(#1.substr(0,#2.length) === #2)" // Is `pre` a prefix of `s`? If so, returns a slice // of `s` following `pre` up to the end of `s`. pub fun starts-withstd/core/sslice/starts-with: (s : string, pre : string) -> maybe<sslice>( ss: string : stringstd/core/types/string: V, prepre: string : stringstd/core/types/string: V )result: -> total maybe<sslice> : maybestd/core/types/maybe: V -> V<sslicestd/core/sslice/sslice: V> if xstarts-withstd/core/sslice/xstarts-with: (s : string, pre : string) -> bool(ss: string,prepre: string) then Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(Sslicestd/core/sslice/Sslice: (str : string, start : int, len : int) -> sslice(ss: string,prepre: string.lengthstd/core/sslice/length: (s : string) -> int,ss: string.lengthstd/core/sslice/length: (s : string) -> int -std/core/int/(-): (x : int, y : int) -> int prepre: string.lengthstd/core/sslice/length: (s : string) -> int)) else Nothingstd/core/types/Nothing: forall<a> maybe<a> extern xends-withstd/core/sslice/xends-with: (s : string, post : string) -> bool: (s : stringstd/core/types/string: V, post : stringstd/core/types/string: V ) -> boolstd/core/types/bool: V c "kk_string_ends_with" cs inline "#1.EndsWith(#2)" js inline "((#1).indexOf(#2, (#1).length - (#2).length) !== -1)" // Does string `s` end with `post`? // If so, returns a slice of `s` from the start up to the `post` string at the end. pub fun ends-withstd/core/sslice/ends-with: (s : string, post : string) -> maybe<sslice>( ss: string : stringstd/core/types/string: V, postpost: string : stringstd/core/types/string: V )result: -> total maybe<sslice> : maybestd/core/types/maybe: V -> V<sslicestd/core/sslice/sslice: V> if (xends-withstd/core/sslice/xends-with: (s : string, post : string) -> bool(ss: string,postpost: string)) then Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(Sslicestd/core/sslice/Sslice: (str : string, start : int, len : int) -> sslice(ss: string,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
,ss: string.lengthstd/core/sslice/length: (s : string) -> int -std/core/int/(-): (x : int, y : int) -> int postpost: string.lengthstd/core/sslice/length: (s : string) -> int)) else Nothingstd/core/types/Nothing: forall<a> maybe<a>
// Truncate a string to `count` characters. pub fun string/truncatestd/core/sslice/string/truncate: (s : string, count : int) -> string( ss: string : stringstd/core/types/string: V, countcount: int : intstd/core/types/int: V )result: -> total string : stringstd/core/types/string: V ss: string.firststd/core/sslice/first: (s : string, n : ? int) -> sslice.extendstd/core/sslice/extend: (slice : sslice, count : int) -> sslice(countcount: int -std/core/int/(-): (x : int, y : int) -> int 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
).stringstd/core/sslice/string: (slice : sslice) -> string
// Trim off a substring `sub` while `s` starts with that string. pub fun trim-leftstd/core/sslice/trim-left: (s : string, sub : string) -> string( ss: string : stringstd/core/types/string: V, subsub: string : stringstd/core/types/string: V )result: -> total string : stringstd/core/types/string: V if subsub: string.is-emptystd/core/string/is-empty: (s : string) -> bool returnreturn: string ss: string match ss: string.starts-withstd/core/sslice/starts-with: (s : string, pre : string) -> maybe<sslice>(subsub: string) Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(sliceslice: sslice) -> trim-leftstd/core/sslice/trim-left: (s : string, sub : string) -> string(pretend-decreasingstd/core/undiv/pretend-decreasing: (x : string) -> string(sliceslice: sslice.stringstd/core/sslice/string: (slice : sslice) -> string),subsub: string) Nothingstd/core/types/Nothing: forall<a> maybe<a> -> ss: string // Trim off a substring `sub` while `s` ends with that string. pub fun trim-rightstd/core/sslice/trim-right: (s : string, sub : string) -> string( ss: string : stringstd/core/types/string: V, subsub: string : stringstd/core/types/string: V )result: -> total string : stringstd/core/types/string: V if subsub: string.is-emptystd/core/string/is-empty: (s : string) -> bool returnreturn: string ss: string match ss: string.ends-withstd/core/sslice/ends-with: (s : string, post : string) -> maybe<sslice>(subsub: string) Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(sliceslice: sslice) -> trim-rightstd/core/sslice/trim-right: (s : string, sub : string) -> string(pretend-decreasingstd/core/undiv/pretend-decreasing: (x : string) -> string(sliceslice: sslice.stringstd/core/sslice/string: (slice : sslice) -> string),subsub: string) Nothingstd/core/types/Nothing: forall<a> maybe<a> -> ss: string