# Static Analysis

MoonRule can inspect a compiled expression before any user data is evaluated. This is useful in rule editors, pull-request checks, configuration review, and admission control.

## Program analysis

```moonbit nocheck
let program = compile(
  "user.active && contains(user.roles, \"admin\")",
).unwrap()
let report = analyze(program)
println(report.to_json_string())
```

The report includes:

- source length, AST node count, and maximum depth;
- counts for literals, variables, arrays, paths, calls, and operators;
- unique referenced JSON paths;
- unique built-in function calls;
- a deterministic relative-cost estimate;
- structured notes and warnings with source spans.

## Findings

Analysis codes are stable and intended for editor or CI integration:

| Code | Meaning |
|---|---|
| `A001` | unknown function |
| `A002` | invalid argument count |
| `A003` | invalid literal regular expression |
| `A004` | unusually long literal regular expression |
| `A005` | dynamic regular expression cannot be checked early |
| `A010`-`A013` | constant boolean branch or unreachable expression |
| `A014` | literal division or remainder by zero |
| `A020` | unusually large array literal |
| `A030` | deeply nested expression |
| `A031` | high estimated execution cost |
| `A040` | literal argument is known to fail its validator |
| `A050` | AST node count exceeds admission policy |
| `A051` | AST depth exceeds admission policy |
| `A052` | estimated cost exceeds admission policy |
| `A053` | dynamic regular expression rejected by admission policy |

Findings never change evaluation behavior. Applications decide whether warnings should block a deployment.

## Admission policy

`analyze_with_policy` combines findings and resource estimates into a reproducible pass/fail report:

```moonbit nocheck
let policy = AnalysisPolicy::default()
let report = analyze_with_policy(
  compile("is_email(coalesce(user?.email, \"\"))").unwrap(),
  policy,
).unwrap()
assert_true(report.passed)
```

The default policy allows at most 2,048 AST nodes, depth 64, and estimated cost 10,000. It rejects analyzer warnings and dynamic regular expressions. Applications can construct `AnalysisPolicy` explicitly when their reviewed risk budget differs.

## Rule-set analysis

`RuleSet::analyze()` aggregates nodes, cost, paths, functions, notes, and warnings across all named rules while retaining each rule's individual report.

From the command line:

```text
moon run cmd/main -- analyze "true || missing.value"
moon run cmd/main -- analyze-rules examples/access-rules.json
moon run cmd/main -- lint-rules examples/api-validation-rules.json
```

The `analyze` commands return exit code `1` when warnings are present. The `lint` commands return `1` when the configured admission policy fails. Both produce JSON and reserve exit code `2` for configuration or compilation errors.
