
# Αρχιτεκτονική

Το shikiphp μετατρέπει τον πηγαίο κώδικα σε επισημασμένο με θέμα HTML, χρησιμοποιώντας γραμματικές TextMate και θέματα VS Code, χωρίς επεκτάσεις PHP πέρα από τα `json`/`mbstring`, χωρίς runtime Node και χωρίς εγγενή σύνδεση Oniguruma. Αυτή η σελίδα συνοψίζει τη ροή επεξεργασίας· η πλήρης κανονιστική σύμβαση βρίσκεται στο `ARCHITECTURE.md` του αποθετηρίου.

## Η ροή επεξεργασίας

```
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>
```

Όλες οι λειτουργίες χρησιμοποιούν μετατοπίσεις σε μονάδες κώδικα **UTF-16** — το ίδιο σύστημα με τη μηχανή regex JS και τον tokenizer του Shiki. Για ASCII αυτό αντιστοιχεί σε μετατοπίσεις byte.

## Το runtime regex

Στη βάση βρίσκεται το `Shikiphp\Regex`, μια πλήρης μηχανή regex ECMAScript pure-PHP, **ενσωματωμένη από το [`inline0/phasis`](https://github.com/inline0/phasis)** (μηχανή JavaScript pure-PHP). Αναλύει μια πηγή JS-RegExp μαζί με flags και εκτελεί αναζητήσεις προς τα εμπρός με σημασιολογία Oniguruma `onig_search`.

## Μετατροπή Oniguruma → JS

Οι γραμματικές TextMate είναι γραμμένες σε Oniguruma. Το `Shikiphp\Oniguruma\PatternConverter` είναι μια υλοποίηση PHP του [`oniguruma-to-es`](https://github.com/slevithan/oniguruma-to-es): μετατρέπει ένα μοτίβο Oniguruma σε πηγή και συμβολοσειρά flags συμβατά με JS-RegExp, τα οποία δέχεται η μηχανή regex. Αυτή είναι η ίδια διαδρομή Oniguruma → RegExp που ακολουθεί η μηχανή regex του Shiki JavaScript και επιτρέπει στο shikiphp να αντιστοιχίζει την έξοδο αυτής της μηχανής με ακρίβεια σε κάθε μετατόπιση. Ο μετατροπέας υποστηρίζει τις δομές που χρησιμοποιούνται στην πράξη από τις γραμματικές: κλάσεις POSIX, possessive quantifiers και atomic groups, inline flags, named groups και backreferences, ιδιότητες Unicode και άλλα.

## Ο σαρωτής και η γρήγορη διαδρομή PCRE

Το `Shikiphp\Oniguruma\OnigScanner` αντιστοιχεί στον σαρωτή του `vscode-oniguruma`: δημιουργείται μία φορά ανά κανόνα από μια λίστα μοτίβων και βρίσκει την αριστερότερη αντιστοιχία στη θέση έναρξης ή μετά από αυτήν.

Η αντιστοίχιση με διάσχιση του δέντρου είναι σωστή αλλά αργή, γι' αυτό ο σαρωτής διαθέτει **γρήγορη διαδρομή PCRE με έλεγχο ισοδυναμίας** σε δύο επίπεδα. Ένα `PcreTranslator` ξαναγράφει την πηγή JS του μετατροπέα ως εγγενές μοτίβο PCRE μόνο όταν μπορεί να αποδείξει το αποτέλεσμα:

- **Πλήρης αντιστοιχία.** Όταν η μετάφραση συμπεριφέρεται πανομοιότυπα με τον matcher, συμπεριλαμβανομένων όλων των captures, το μοτίβο εκτελείται απευθείας σε PCRE. Τα named groups, τα backreferences, τα `\p{}`, `\b`, `\G`, η προσομοίωση atomic groups και τα captures των οποίων η σημασιολογία JavaScript διαφέρει από την PCRE (μέσα σε ποσοτικοποιημένο group ή lookbehind) αποκλείονται από αυτό το επίπεδο.
- **Μόνο θέση.** Όταν ενδέχεται να διαφέρουν μόνο τα captures, μια δεύτερη μετάφραση επιτρέπει αυτές τις δομές (τα `\b` και `\B` ως ακριβή ASCII lookarounds, τα atomic groups ως εγγενή `(?>…)`, το `\p{…}` όταν το μεταγλωττίζει η PCRE). Έτσι, η PCRE βρίσκει μόνο τη θέση της επόμενης αντιστοιχίας και ο matcher εκτελεί ξανά την αντιστοίχιση σε αυτή τη μετατόπιση για να παράγει τα πραγματικά captures. Τα backreferences και το `\G` παραμένουν επίσης αποκλεισμένα.

Όλα τα υπόλοιπα εκτελούνται μόνο από τον matcher. Για τις ενσωματωμένες γραμματικές στο Shiki 3.23.0, περίπου το 39% των 14,234 διαφορετικών μοτίβων εκτελείται πλήρως σε PCRE, περίπου το 57% χρησιμοποιεί το επίπεδο θέσης και περίπου το 4% παραμένει στον matcher. Η ταξινόμηση ελέγχεται από ένα εργαλείο ανάπτυξης στο αποθετήριο (`bin/.oracle-tools/pcre-equivalence.php`), το οποίο συγκρίνει τη γρήγορη διαδρομή με τον matcher — δείκτη, τέλος και, για το πρώτο επίπεδο, κάθε εύρος capture — στα σενάρια δοκιμής και σε συνθετικές συμβολοσειρές, χωρίς να επιτρέπονται αποκλίσεις.

## Γραμματική και θέμα

- **Γραμματική** (`Shikiphp\Grammar`) είναι πιστή μεταφορά του `vscode-textmate`: ένα `Registry` επιλύει γραμματικές με βάση το όνομα scope (συμπεριλαμβανομένων των αναφορών `include`, των ενσωματωμένων γλωσσών και των injections) και ένα `Tokenizer` διατηρεί τις στοίβες κανόνων και scope ανά γραμμή.
- **Θέμα** (`Shikiphp\Theme`) μεταφέρει την αντιστοίχιση θεμάτων του `vscode-textmate`: το χρώμα προσκηνίου και το στυλ γραμματοσειράς επιλύονται βάσει της ειδικότητας του scope selector και της αντιστοίχισης γονικών scope.

## Απόδοση

Το `Shikiphp\Render\HtmlRenderer` δημιουργεί ακριβώς το ίδιο δέντρο HAST `pre.shiki > code > span.line >
span` που δημιουργεί το Shiki και, στη συνέχεια, το σειριοποιεί. Η λειτουργία ενός θέματος γράφει απλά χρώματα· η λειτουργία δύο θεμάτων γράφει μεταβλητές `--shiki-light` / `--shiki-dark` CSS.

## Επικυρωμένο σε σύγκριση με το Shiki

Το ίδιο το Shiki αποτελεί το σημείο αναφοράς, με σταθερή έκδοση `shiki` 3.23.0 και τη μηχανή regex JavaScript. Ο κατάλογος `scenarios/` περιλαμβάνει **214** fixtures, καθένα με μία είσοδο, μία γλώσσα και ένα θέμα· συνολικά καλύπτουν 167 από τις 253 ενσωματωμένες γραμματικές, `lang: 'ansi'` και τα 65 θέματα. Το `bin/test-regression` επισημαίνει καθεμία με τις δύο μηχανές και επιβεβαιώνει ότι η συμβολοσειρά HTML είναι πανομοιότυπη αφού αφαιρεθούν τα κενά στην αρχή και στο τέλος. Οι επιλογές και οι transformers ελέγχονται με δοκιμές ισοδυναμίας έναντι εξόδου που καταγράφηκε από τις ίδιες εκδόσεις Shiki και `@shikijs/transformers` 4.2.0. Ο απαράβατος κανόνας είναι να μην υποβαθμίζεται η έξοδος επισήμανσης σε σχέση με το Shiki.
