
# 인덱스 AST 검색

인덱스 AST 검색은 [AST 검색](https://greph.inline0.dev/ko/docs/modes/ast)의 캐시 사전 준비 버전입니다. 첫 호출에서 노드 수준 팩트(호출 이름, 인스턴스화, 클래스 선언, 메서드 선언)를 디스크 저장소에 추출합니다. 이후 호출에서는 저장소를 사용해 구조적 일치가 있을 수 없는 파일을 건너뜁니다. 그런 다음 일치 검사기가 후보를 소스와 대조해 다시 검증합니다.

팩트 인덱스는 `greph-index ast-index` CLI 하위 명령과 `Greph::buildAstIndex()` / `Greph::searchAstIndexed()` 파사드 메서드를 통해 제공됩니다. 사전 준비된 다중 인덱스 및 매니페스트 기반 세트 워크플로우에도 사용됩니다.

## 인덱스 빌드

```bash
# Full build at the current directory
./vendor/bin/greph-index ast-index build .

# Full build at an explicit root
./vendor/bin/greph-index ast-index build path/to/repo

# Use a non-default index directory
./vendor/bin/greph-index ast-index build . --index-dir /tmp/greph-ast-index

# Build a mutable overlay that can refresh cheaply on demand
./vendor/bin/greph-index ast-index build . \
  --lifecycle opportunistic-refresh \
  --auto-refresh-max-files 32 \
  --auto-refresh-max-bytes 1048576
```

기본적으로 팩트 인덱스는 `<root>/.greph-ast-index/`에 저장됩니다.

빌드에 성공하면 한 줄 요약이 출력됩니다:

```text
Built AST index for 2547 files in .greph-ast-index (84931 fact rows, +2547 ~0 -0 =0)
```

네 개의 카운터는 마지막 빌드 이후 추가, 업데이트, 삭제, 변경되지 않은 파일 수를 나타냅니다.

## 인덱스 새로 고침

```bash
./vendor/bin/greph-index ast-index refresh .
```

`refresh`는 인덱싱된 루트를 다시 탐색하고 변경된 파일을 다시 파싱한 뒤 바뀐 팩트 행만 다시 씁니다. 출력에는 텍스트 인덱스와 동일한 네 개의 카운터가 사용됩니다.

수명 주기 프로필은 사전 준비된 텍스트 인덱스와 같은 방식으로 작동합니다:

- `static`: 최신 상태인지 확인하거나 자동으로 변경하지 않음
- `manual-refresh`: `stats`에 오래된 상태를 보고하지만 검색 중에는 새로 고치지 않음
- `opportunistic-refresh`: 변경된 항목 집합이 충분히 작을 때만 검색 중 새로 고침
- `strict-stale-check`: 오래된 검색 결과를 새로 고치는 대신 거부

## 인덱스 쿼리

```bash
./vendor/bin/greph-index ast-index search 'new $CLASS()' src
./vendor/bin/greph-index ast-index search '$obj->$method($$$ARGS)' src
./vendor/bin/greph-index ast-index search --json 'array($$$ITEMS)' src
./vendor/bin/greph-index ast-index search -l 'array($$$ITEMS)' src
./vendor/bin/greph-index ast-index search --trace-plan 'new $CLASS()' src
```

메타변수 구문은 네이티브 AST 검색과 동일합니다. 전체 문법은 [모드 / AST 검색](https://greph.inline0.dev/ko/docs/modes/ast)을 참조하세요.

### 옵션

| 플래그 | 의미 |
|---|---|
| `--lang NAME` | AST 언어. 기본값: `php` |
| `-j N`, `--jobs N` | 병렬 작업자 수 |
| `-l`, `--files-with-matches` | 일치하는 파일만 나열 |
| `--glob GLOB` | 경로가 GLOB과 일치하는 파일만 포함 |
| `--type NAME` / `--type-not NAME` | 파일 형식 필터 |
| `--json` | JSON 출력 생성 |
| `--no-ignore` | `.gitignore` 및 `.grephignore` 무시 |
| `--hidden` | 숨김 파일 포함 |
| `--strict-parse` | 파싱 오류를 건너뛰지 않고 실패 처리 |
| `--fallback MODE` | 인덱스가 없을 때의 동작: `fail`(기본값) 또는 `scan` |
| `--index-dir DIR` | 기본값이 아닌 인덱스 디렉터리 사용 |
| `--trace-plan` | 사전 준비된 AST 플래너 진단을 `stderr`로 출력 |
| `--show-index-origin` | 다중 인덱스 또는 세트 모드에서 일치한 인덱스 라벨을 출력 앞에 붙임 |

### 인덱스 누락 시 대체 동작

기본적으로 요청한 위치에 인덱스가 없으면 `ast-index search`는 오류를 발생시킵니다. 대신 네이티브 AST 스캔을 실행하려면 `--fallback scan`를 전달하세요. 인덱스가 있으면 인덱스 검색을 사용하되, 아직 빌드되지 않은 경우에도 결과를 내야 하는 도구에 적합한 설정입니다.

```bash
./vendor/bin/greph-index ast-index search --fallback scan 'new $CLASS()' src
```

### 여러 인덱스 검색

`--index-dir`를 반복하면 한 명령으로 여러 개의 사전 준비 AST 인덱스를 검색할 수 있습니다. WordPress 핵심 코드와 플러그인 또는 테마를 함께 사용하는 구성에 유용합니다.

```bash
./vendor/bin/greph-index ast-index search \
  --index-dir ../wordpress/.greph-ast-index \
  --index-dir ./.greph-ast-index \
  --show-index-origin \
  'new $CLASS()' .
```

`--show-index-origin`를 활성화하면 출력 앞에 일치한 사전 준비 인덱스 항목의 이름이 붙어 어떤 루트에서 결과가 나왔는지 확인할 수 있습니다.

### 매니페스트 기반 인덱스 세트

안정적으로 사전 준비된 구성을 위해 매니페스트를 정의하고 `greph-index set`가 그룹화된 인덱스를 사용하도록 하세요:

```bash
./vendor/bin/greph-index set build
./vendor/bin/greph-index set stats --mode ast-index --dry-refresh
./vendor/bin/greph-index set search --mode ast-index --show-index-origin 'new $CLASS()' .
```

세트 하위 명령은 직접 `ast-index`를 사용할 때와 동일한 수명 주기 처리, 오래된 상태 검사, 플래너 진단을 공유합니다.

### 플래너 진단

`--trace-plan`는 전체 일치 검사를 실행하기 전에 Greph가 쿼리를 어떻게 좁혔는지 보여줍니다. `ast-index`의 경우 일반적으로 다음이 포함됩니다:

- 패턴에서 추출한 대략적인 팩트 시그니처
- 검색한 사전 준비 인덱스 수
- 팩트 필터로 제외된 파일 수
- 정확한 구조 검증을 위해 다시 파싱한 후보 파일 수

## 인덱스 저장 내용

AST 팩트 추출기는 인덱싱된 각 파일에서 각 "주요" 노드의 행을 기록합니다. 팩트 종류는 AST 패턴이 가장 자주 찾는 구문을 포함합니다:

- 함수 및 메서드 호출(호출 이름별)
- 클래스 인스턴스화(클래스 이름별)
- 클래스, 인터페이스, 트레이트 및 enum 선언(이름별)
- 함수 선언(이름별)
- 메서드 선언(이름 및 가시성별)
- use 문

쿼리가 들어오면 `Greph\Ast\AstFactQuery`는 검색 패턴을 대략적인 팩트 시그니처(예: "어떤 클래스든 `new`를 포함해야 함")로 변환해 팩트 저장소와 대조합니다. 교집합에 남은 파일은 다시 파싱한 다음 전체 패턴과 일치하는지 확인합니다.

따라서 팩트 인덱스는 전체 정보를 보존하는 일치 저장소가 아니라 *사전 필터*입니다. 일치 단계에서 소스를 계속 파싱하므로 구조적 정확도는 네이티브 AST 검색과 같고, 후보 집합만 더 작습니다.

## 사용 시점

다음과 같은 경우 인덱스 AST 모드가 적합합니다:

- 같은 코드베이스에서 동일한 구조 쿼리를 반복 실행하는 경우
- 패턴이 팩트 추출기에 저장되는 식별 가능한 형태(호출 이름, 클래스 이름, 선언 종류)를 대상으로 하는 경우
- 모든 파일을 다시 파싱하는 것보다 응답 시간을 줄이고 싶은 경우

구분에 필요한 특징이 팩트 집합에 없는 패턴(예: 식별 가능한 헤드가 없는 복잡한 중첩 식)의 경우, 대략적인 시그니처에 의존하지 않고 파싱 단계를 완전히 건너뛰는 [캐시된 AST 모드](https://greph.inline0.dev/ko/docs/indexed/cache)가 보통 더 적합합니다.

## 프로그래밍 방식 사용

```php
use Greph\Greph;
use Greph\Ast\AstSearchOptions;
use Greph\Index\IndexLifecycleProfile;

Greph::buildAstIndex('.', lifecycle: IndexLifecycleProfile::OpportunisticRefresh);

$matches = Greph::searchAstIndexed(
    'new $CLASS()',
    'src',
    new AstSearchOptions(jobs: 4, tracePlan: true),
);
```

`searchAstIndexed`는 네이티브 AST 검색과 동일한 `AstSearchOptions`를 받고 같은 형태의 `list<AstMatch>`를 반환합니다. 다중 인덱스 또는 매니페스트 기반 흐름에는 `searchAstIndexedMany(...)` 및 `searchAstIndexedSet(...)`를 사용하세요.
