# rusty-jq v2.2.0 — Tier 1 Built-in Functions

## Overview

This update adds **49 built-in functions**, **3 syntax extensions**, and **extended operator semantics** to rusty-jq. All 162 tests pass (93 new + 69 existing).

---

## New No-Arg Builtins (36)

| Function | Input | Output |
|---|---|---|
| `length` | array/object/string/number/null | element count, char count, abs value, or 0 |
| `keys` | object or array | sorted key names, or `[0,1,2,...]` |
| `keys_unsorted` | object | key names in insertion order |
| `values` | object or array | array of values |
| `type` | any | `"null"`, `"boolean"`, `"number"`, `"string"`, `"array"`, `"object"` |
| `reverse` | array or string | reversed |
| `sort` | array | sorted (jq total order: null < false < true < numbers < strings < arrays < objects) |
| `flatten` | nested array | recursively flattened |
| `add` | array | fold with `+` (sum numbers, concat strings/arrays, merge objects; null if empty) |
| `min` | array | minimum element |
| `max` | array | maximum element |
| `unique` | array | sorted, deduplicated |
| `first` | array | first element |
| `last` | array | last element |
| `not` | any | negate truthiness (null/false → true, everything else → false) |
| `empty` | any | produce zero outputs |
| `tostring` | any | string representation (strings pass through) |
| `tonumber` | string or number | parse string as number, or pass through |
| `to_entries` | object | `[{"key": k, "value": v}, ...]` |
| `from_entries` | array of `{key, value}` or `{name, value}` | object |
| `ascii_downcase` | string | lowercased |
| `ascii_upcase` | string | uppercased |
| `tojson` | any | JSON-encoded string |
| `fromjson` | string | parsed JSON value |
| `explode` | string | array of Unicode codepoints |
| `implode` | array of codepoints | string |
| `floor` | number | rounded down (integers pass through) |
| `ceil` | number | rounded up (integers pass through) |
| `round` | number | rounded to nearest (integers pass through) |
| `sqrt` | number | square root |
| `fabs` | number | absolute value |
| `nan` | any | NaN constant |
| `infinite` | any | positive infinity constant |
| `isinfinite` | number | true if infinite |
| `isnan` | number | true if NaN |
| `isnormal` | number | true if normal number |
| `recurse` | any | recursively descend (equivalent to `..`) |

## New One-Arg Builtins (13)

| Function | Example | Description |
|---|---|---|
| `has(k)` | `has("name")`, `has(0)` | test key/index existence |
| `startswith(s)` | `startswith("http")` | string prefix test |
| `endswith(s)` | `endswith(".json")` | string suffix test |
| `contains(s)` | `contains("foo")` | substring/recursive containment |
| `inside(s)` | `inside("foobar")` | inverse of contains |
| `split(s)` | `split(",")` | split string by separator |
| `join(s)` | `join("-")` | join array with separator |
| `ltrimstr(s)` | `ltrimstr("http://")` | remove prefix if present |
| `rtrimstr(s)` | `rtrimstr(".json")` | remove suffix if present |
| `flatten(n)` | `flatten(1)` | flatten to depth n |
| `index(s)` | `index("bar")` | first occurrence (null if absent) |
| `rindex(s)` | `rindex("o")` | last occurrence (null if absent) |
| `indices(s)` | `indices("a")` | all occurrence positions |

## New Syntax

| Syntax | Example | Description |
|---|---|---|
| `..` | `.. \| select(type == "number")` | recursive descent — produces all nested values |
| `.[m:n]` | `.[1:3]`, `.[2:]`, `.[:2]`, `.[-2:]` | array/string slicing with negative index support |
| `%` | `.a % .b` | modulo operator (same precedence as `*` and `/`) |

## Extended Operator Semantics

| Operator | New behavior |
|---|---|
| `+` on strings | concatenation: `"hello" + " world"` → `"hello world"` |
| `+` on arrays | concatenation: `[1,2] + [3,4]` → `[1,2,3,4]` |
| `+` on objects | merge (right wins): `{"a":1} + {"b":2}` → `{"a":1,"b":2}` |
| `+` with null | `null + x` = `x`, `x + null` = `x` |
| `-` on arrays | element removal: `[1,2,3] - [2]` → `[1,3]` |
| `.[]` on objects | iterates object values (previously only arrays) |

## Files Changed

| File | Changes |
|---|---|
| `src/parser.rs` | Added `Builtin0`, `Builtin1` enums, `RecurseDescent`, `Slice` filter variants, `parse_keyword` helper, `parse_builtin0`, `parse_builtin1`, `parse_recursive_descent`, `parse_slice` functions, `%` in arithmetic |
| `src/engine.rs` | Added `exec_builtin0`, `exec_builtin1` dispatch functions, `make_array` helper, `clone_value`, `cmp_values`, `value_contains`, `owned_to_borrowed`, `value_to_json_string`, `value_to_string_repr`, `recurse_values`, `recurse_owned`, `flatten_array`, `resolve_slice_index` utilities, extended `apply_arith` for string/array/object ops, extended `Iterator` for objects |
| `test/test_builtins.py` | **New file** — 93 tests covering all new functions and syntax |

## Test Results

```
162 passed in 0.56s
```
