
# Architektura

shikiphp zamienia kod źródłowy na podświetlony kod HTML przy użyciu gramatyk TextMate
i motywów VS Code, bez rozszerzeń PHP poza `json`/`mbstring`, bez środowiska uruchomieniowego Node
i natywnego powiązania Oniguruma. Ta strona podsumowuje potok; pełna specyfikacja znajduje się w pliku `ARCHITECTURE.md` w repozytorium.

## Potok przetwarzania

```
source code
  └─ Highlighter::codeToTokens()
       ├─ Grammar\Registry        loads the grammar (+ its includes / embedded langs)
       ├─ Grammar\Tokenizer       line by line, driving an OnigScanner per rule state
       │     └─ Oniguruma\OnigScanner.findNextMatch()
       │           └─ Oniguruma\PatternConverter   Oniguruma pattern → JS regex
       │                 └─ Shikiphp\Regex (Parser + Matcher)   JS RegExp runtime
       ├─ Theme\Theme.match(scopeStack) → StyleAttributes   per token
       └─ Render\ThemedToken[]   (text + style) per line
  └─ Render\HtmlRenderer  → <pre class="shiki">…</pre>
```

Wszystkie operacje używają offsetów w jednostkach kodowych **UTF-16** — tak samo jak
silnik regex JS i tokenizator Shiki. Dla ASCII odpowiadają one offsetom bajtów.

## Środowisko uruchomieniowe regex

U podstaw znajduje się `Shikiphp\Regex` — kompletny silnik regex ECMAScript napisany wyłącznie w PHP,
**dołączony do pakietu z [`inline0/phasis`](https://github.com/inline0/phasis)** (silnik JavaScript napisany wyłącznie w PHP). Analizuje źródło RegExp JS wraz z flagami i wykonuje wyszukiwanie w przód z semantyką Oniguruma `onig_search`.

## Konwersja Oniguruma → JS

Gramatyki TextMate są zapisane w Oniguruma. `Shikiphp\Oniguruma\PatternConverter`
to PHP portu
[`oniguruma-to-es`](https://github.com/slevithan/oniguruma-to-es): konwertuje wzorzec
Oniguruma na źródło i ciąg flag zgodne z RegExp JS, akceptowane przez silnik regex. Tę samą ścieżkę Oniguruma → RegExp wykorzystuje silnik regex JavaScriptShiki, co pozwala shikiphp dopasować jego wynik z dokładnością do offsetu. Konwerter obsługuje konstrukcje używane w rzeczywistych gramatykach: klasy POSIX, kwantyfikatory zachłanne i grupy atomowe, flagi inline, nazwane grupy i odwołania wsteczne, właściwości Unicode i inne.

## Skaner i szybka ścieżka PCRE

`Shikiphp\Oniguruma\OnigScanner` działa tak jak skaner `vscode-oniguruma`: jest budowany
raz dla każdej reguły z listy wzorców i znajduje najwcześniejsze dopasowanie na pozycji początkowej lub dalej.

Dopasowywanie przez przechodzenie drzewa jest poprawne, ale wolne, dlatego skaner ma
**szybką ścieżkę PCRE z gwarancją równoważności**, działającą na dwóch poziomach. `PcreTranslator` przekształca
źródło JS konwertera na natywny wzorzec PCRE tylko wtedy, gdy może dowieść poprawności wyniku:

- **Pełne dopasowanie.** Gdy tłumaczenie zachowuje się identycznie jak dopasowywanie,
  łącznie ze wszystkimi przechwyceniami, wzorzec jest wykonywany bezpośrednio przez PCRE. Nazwane grupy,
  odwołania wsteczne, `\p{}`, `\b`, `\G`, emulacja grup atomowych oraz przechwycenia, których
  semantyka JavaScript różni się od PCRE (wewnątrz grupy z kwantyfikatorem lub
  wyrażenia sprawdzającego od tyłu), nie są dopuszczane na tym poziomie.
- **Tylko pozycja.** Gdy mogą różnić się tylko przechwycenia, drugie tłumaczenie
  dopuszcza te konstrukcje (`\b` i `\B` jako dokładne asercje wyprzedzające i wsteczne ASCII, grupy atomowe jako natywne `(?>…)`, `\p{…}`, jeśli PCRE je kompiluje). PCRE znajduje wtedy tylko pozycję następnego dopasowania, a mechanizm dopasowujący ponownie uruchamia się od tego offsetu, aby wygenerować właściwe przechwycenia. Odwołania wsteczne i `\G` również są tu odrzucane.

Pozostałe przypadki obsługuje wyłącznie mechanizm dopasowujący. Dla gramatyk dołączonych w Shiki
3.23.0 około 39% spośród 14,234 różnych wzorców jest w całości wykonywanych przez PCRE, około 57%
korzysta z poziomu pozycjonowania, a około 4% pozostaje przy mechanizmie dopasowującym. Klasyfikację
sprawdza narzędzie deweloperskie w repozytorium
(`bin/.oracle-tools/pcre-equivalence.php`), które porównuje szybką ścieżkę z mechanizmem dopasowującym — indeks, koniec i, dla pierwszego poziomu, każdy zakres przechwycenia — dla zestawu scenariuszy i syntetycznych ciągów; rozbieżności nie są dopuszczalne.

## Gramatyka i motyw

- **Gramatyka** (`Shikiphp\Grammar`) to wierny port `vscode-textmate`: `Registry` rozpoznaje gramatyki według nazwy zakresu (w tym odwołania `include`,
  osadzone języki i wstrzyknięcia), a `Tokenizer` zarządza stosami reguł i zakresów wiersz po wierszu.
- **Motyw** (`Shikiphp\Theme`) przenosi mechanizm dopasowywania motywów z `vscode-textmate`:
  kolor pierwszego planu i styl czcionki są dobierane według szczegółowości selektora zakresu z uwzględnieniem dopasowania zakresu nadrzędnego.

## Renderowanie

`Shikiphp\Render\HtmlRenderer` buduje dokładnie takie samo drzewo HAST `pre.shiki > code > span.line >
span` jak Shiki, a następnie je serializuje. Tryb jednego motywu zapisuje zwykłe kolory; tryb dwóch motywów zapisuje zmienne `--shiki-light` / `--shiki-dark` CSS.

## Walidacja względem Shiki

Samo Shiki jest wzorcem odniesienia, przypiętym do `shiki` 3.23.0 z silnikiem regex JavaScript. Katalog `scenarios/` zawiera **214** zestawów testowych; każdy obejmuje jedno wejście w jednym języku i jednym motywie. Łącznie pokrywają 167 z 253 dołączonych gramatyk, `lang: 'ansi'` oraz wszystkie 65 motywów. `bin/test-regression` podświetla każde wejście za pomocą obu silników i sprawdza, czy wynik HTML jest identyczny po usunięciu białych znaków z początku i końca. Opcje i transformatory są sprawdzane testami zgodności względem wyników zapisanych z tych samych wersji Shiki i `@shikijs/transformers` 4.2.0. Wynik podświetlania nie może być gorszy niż w Shiki.
