# `Feel.Analysis.Images.String`
[🔗](https://github.com/FeeJai/BDM/blob/feel-v0.1.0/apps/feel/lib/feel/analysis/images/string.ex#L1)

The rules for the string built-ins (`Feel.Analysis.Images`, D-161, step C): `contains`, `ends with`, `lower case`,
`matches`, `replace`, `split`, `starts with`, `string join`, `string length`, `substring`, `substring after`,
`substring before` and `upper case`.

A rule gives the whole type of the result, `Null` included, from the types of the arguments. Each argument is read for the
strings (or the numbers) it can be, whether it can be `null`, and whether it can be something that the function turns down
with `null`: a value of another kind, or a list, which is its element if it has one and `null` if it has not (section
10.3.2.9.4). Then the result is found in one of three ways, from the exact to the kind:

  * **The function is run on the strings of a finite set.** A set of strings that is a list (`{"a", "b"}`) gives the values
    of an argument, and the function itself (`Feel.Builtin.call/3`, so that nothing of it is written twice) is called on
    every combination of the values of the arguments. `string length(s)` for `{"a", "b", "c"}` is `number = 1`,
    `upper case(s)` for `{"a", "b"}` is `{"A", "B"}`, `matches(s, "a(")` is `Null`, since the pattern is not one. A product
    of more than 64 combinations is not run. The run has a small budget, as an analysis has to stay cheap whatever the
    model has written (a regular expression of 10,000 steps, a result of 100,000 bytes): a call that passes it ends the
    run and has no value, and then the signatures give the type, as they do for a call on constants that the analysis
    cannot evaluate (D-80).
  * **The kind, with what is known.** For every string, or a set with an interval in it (which has as many strings as
    there are), or a product that is too large, the result is the kind of the function: `string length(s)` is a number in
    `[0..max]`, `contains(s, m)` is `boolean`. What the other arguments say is used: every string has the empty string in
    each place, so `contains(s, "")` is `true` and `substring before(s, "")` is `""`; a set of strings that has not the empty
    string has at least one character, so its length is in `[1..max]`; and the patterns, the replacements and the flags that
    are a finite set are read once (`Feel.Runtime.Regex`), so `matches(s, "a+")` is `boolean`, and `replace(s, "a*", "b")`
    is `Null`.
  * **`substring`** runs the function on the string and on the integers that the numbers can be. A start is cut off at its
    fraction, and a start or a length is out of range past either end of the string, so the integers that make a difference
    are those within one of the ends and the first beyond them: a set of numbers as wide as `number` is a few calls.

`string join` is read by the kinds of its list: its elements are strings or `null` (which are left out), and a string is a
list of one string.

## What is `null`

`Null` is in the type only if some arguments make the run give it. That is a `null` argument and an argument of another
kind, but for the arguments that are left out when they are `null` (the flags of `matches` and `replace`, the delimiter of
`string join`, and the length of `substring`), and what the function itself turns down:

| Function | `null` for |
| -------- | ---------- |
| `substring` | a start of 0 or past either end of the string; a length under 1 or past what is left |
| `matches` | a pattern or flags that are not in the dialect of XPath |
| `replace` | the same, a pattern that matches the empty string, a replacement with a `$` or a `\` that means nothing |
| `split` | the same, but the empty string has no parts, whatever the pattern is |
| `string join` | an element of the list that is neither a string nor `null` |
| the others | nothing |

## What is broader than exact

The type is a superset where it cannot be exact, and never smaller. Where the set of strings has an interval or the product
is too large, the strings of the result are `string` (`upper case(s)` is not every string, but no set says which) and the
booleans are `boolean` (`contains(s, "a")` for a `s` that is only the strings from `"a"` to `"a"` is `true`). The shortest
string of a set with an interval that has not the empty string is taken to have one character, which it has but for a set
such as `["ab".."ac"]`; and a pattern, a replacement or flags that are such a set are taken to have a string that the
function turns down, which is so unless the set is all of one class. The lists of `string join` have no length in their
type, so the result of one is `string`. More than 8 different lists as the results of `split` are one list of their parts,
and more than 2,048 calls of `substring` are `string`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
