{
:append
:concat
:join
:equal
:length
:fetch
:clip
:compare
}

Where

Define (join glue strings)
    Match strings {
    | 'nil ""
    | 'cons.{s strings}
        Let glue_len (length glue)
        In
        (CHUNK.new_ro
            Iterate {size strings} From {(length s) strings}
                Match strings {
                | 'nil size
                | 'cons.{s strings}
                    (Continue [size + glue_len + (length s)] strings)
                }
            Func d Begin {
                Let s_len (length s)
                (CHUNK.store_bytes d 0 s 0 s_len)
                Iterate {i strings} From {s_len strings}
                    Begin Match strings {
                    | 'nil
                    | 'cons.{s strings}
                        (CHUNK.store_bytes d i glue 0 glue_len)
                        Let i [i + glue_len]
                        Let s_len (length s)
                        (CHUNK.store_bytes d i s 0 s_len)
                        Let i [i + s_len]
                        (Continue i strings)
                    }
            })
    }

Where

Define (concat strings)
    Let size (LIST.reduce strings 0 [Func {size s} [size + (length s)]])
    In
    (CHUNK.new_ro size
        Func d
            Iterate {i strings} From {0 strings}
                Begin Match strings {
                | 'nil
                | 'cons.{s strings}
                    Let s_len (length s)
                    (CHUNK.store_bytes d i s 0 s_len)
                    (Continue [i + s_len] strings)
                })

Where

Define (append s1 s2)
    Let len1 (length s1)
    Let len2 (length s2)
    In
    (CHUNK.new_ro [len1 + len2]
        Func d Begin {
            (CHUNK.store_bytes d 0 s1 0 len1)
            (CHUNK.store_bytes d len1 s2 0 len2)
        })

Where

Define (equal s1 s2)
    Pattern 'equal Matches (compare s1 s2)

Define (clip s begin end)
    (CHUNK.fetch_bytes_ro s begin [end - begin])

Where

Define (compare a b)
    Let m (length a)
    Let n (length b)
    In
    Iterate i From 0
        Cond {
        | (And [i = m] [i = n]) 'equal
        | [i = m] 'less
        | [i = n] 'greater
        | True
            Let x (fetch a i)
            Let y (fetch b i)
            In
            Cond {
            | [x < y] 'less
            | [x > y] 'greater
            | True (Continue [i + 1])
            }
        }

Where

Define (length s)
    (CHUNK.size s)

Define (fetch s i)
    (CHUNK.fetch_uint8 s i)

Where

Open Z
    {
    :Infix <
    :Infix >
    :Infix =
    :Infix +
    :Infix -
    }

Where

Let CHUNK Package "chunk"
Let LIST Package "list"
Let Z Package "z"