# MoonRule Language Reference

## Values

The language uses the JSON value model: `null`, boolean, number, string, array and object.

String literals use double quotes and support `\"`, `\\`, `\/`, `\b`, `\f`, `\n`, `\r` and `\t`.

## Paths and indexing

```text
user.name
orders[0].total
metadata["build-id"]
user?.profile?.email
items?[0]
```

Dot access requires an object field. Bracket access accepts an integer for arrays and a string for objects. Missing fields and invalid indexes are evaluation errors.

Optional access uses `?.field` or `?[index]`. A missing root, missing object field, `null` target, or out-of-bounds array index produces `null`. The index expression is not evaluated when the target is null. Optional access remains strict about target and index types, so malformed data is not silently accepted.

## Operators

| Precedence | Operators | Associativity |
|---:|---|---|
| 7 | `!`, unary `-` | right |
| 6 | `*`, `/`, `%` | left |
| 5 | `+`, `-` | left |
| 4 | `<`, `<=`, `>`, `>=`, `in` | left |
| 3 | `==`, `!=` | left |
| 2 | `&&` | left |
| 1 | `||` | left |

`&&` and `||` short-circuit. The skipped expression is not evaluated and does not appear as an individual trace step.

`+` adds two numbers or concatenates two strings. Ordering comparisons accept two numbers or two strings. Equality accepts any two JSON values.

`in` supports:

- value membership in an array;
- string-key membership in an object;
- substring membership in a string.

## Functions

Most functions have fixed arity. `coalesce` accepts between 1 and 32 arguments. An unknown function or wrong argument count is an evaluation error. The complete machine-readable catalog is available through `builtin_functions()` or the `moonrule functions` command.

### `len(value)`

Accepts strings, arrays and objects.

### `contains(container, value)`

For strings, both arguments must be strings. For arrays, JSON equality is used. For objects, the second argument must be a string key.

### `matches(text, pattern)`

Compiles `pattern` with MoonBit's regular-expression engine. Invalid patterns return diagnostic `E023`. Patterns longer than 512 characters and inputs longer than 65,536 characters are rejected before matching.

### Deterministic validators

- `is_date(text)` validates an ISO `YYYY-MM-DD` calendar date, including leap years;
- `is_datetime(text)` validates an RFC 3339 timestamp with an explicit time zone;
- `is_ipv4(text)` validates canonical dotted-decimal IPv4 text;
- `is_email(text)` validates a conservative ASCII mailbox and DNS-style domain;
- `is_uuid(text)` validates the canonical 8-4-4-4-12 hexadecimal layout;
- `is_semver(text)` validates Semantic Versioning core, prerelease, and build syntax.

These functions inspect text only. They do not perform DNS, network, clock, or registry lookups.

### Other functions

`starts_with`, `ends_with`, `lower`, `upper`, `abs` and `exists` provide common validation operations without introducing side effects.

Collection and safe-access helpers:

- `has(object, key)` tests whether a field exists;
- `get(object, key, default)` returns a field or the supplied default;
- `sum(numbers)` totals an array of numbers;
- `all(booleans)` and `any(booleans)` aggregate boolean arrays.

Numeric and conversion helpers:

- `min(left, right)` and `max(left, right)`;
- `clamp(value, minimum, maximum)`;
- `type_of(value)` returns `null`, `boolean`, `number`, `string`, `array`, or `object`;
- `coalesce(first, ...fallbacks)` returns the first non-null value.

## Compilation limits

`compile` applies default limits of 16,384 source characters, 4,096 AST nodes, and an AST
depth of 128. Use `compile_with_limits(source, limits)` when rules come from an untrusted
source or when an embedding application needs a tighter policy. A compiled `Program`
exposes `node_count()` and `ast_depth()` for inspection and telemetry.

## Evaluation limits

`evaluate_with_limits(program, context, limits)` applies an AST step budget. Each visited node consumes one step; short-circuited branches consume no steps. Exhaustion returns `E024`, while a non-positive configuration returns `C011`.

## Static analysis

`analyze(program)` reports expression counts, referenced JSON paths, called functions, an estimated cost, and structured findings. It detects unknown functions, invalid arity, invalid literal regular expressions, invalid literal validator calls, constant short-circuit branches, and literal division by zero without executing user data.

`analyze_with_policy(program, policy)` turns analysis into an admission decision. It can reject warnings, dynamic regular expressions, excessive AST nodes, excessive depth, and estimated cost. `RuleSet::analyze_with_policy` applies the same decision consistently to a complete rule set.

## Diagnostic families

- `Lxxx`: lexical diagnostics
- `Pxxx`: parser diagnostics
- `Exxx`: evaluation diagnostics
- `Cxxx`: rule configuration diagnostics

Diagnostic codes are treated as part of the public contract and will not be reused for different meanings.
