
# المحلل

يتيح Phasis محلل JavaScript المستقل الخاص به ضمن PHP API. يمكنك تحليل النص المصدري إلى شجرة AST مكتوبة الأنواع، والتنقل فيها، وتصديرها كمصفوفات على نمط ESTree أو JSON، دون إنشاء `Engine` أو تنفيذ أي شيء.

## parseSource

```php
public static function parseSource(string $source, string $sourceType = 'script'): Program
```

نقطة الدخول باستدعاء واحد في `Phasis\Parser\Parser`. تحلل `$source` وتعيد العقدة الجذرية لـ `Phasis\Ast\Program`.

```php
use Phasis\Parser\Parser;

$program = Parser::parseSource('const x = [1, 2].map(n => n * 2);');
$module = Parser::parseSource('import { x } from "./x.js"; export default x;', 'module');
```

يحدد `$sourceType` هدف القواعد النحوية، وتُسمّى قيمه على غرار الخيار نفسه في محللات JS:

| القيمة | الهدف |
|---|---|
| `script` | Script تقليدي. تكون `import`/`export` على المستوى الأعلى أخطاء نحوية، بينما `await` معرّف |
| `module` | وحدة ES. تلتزم الصرامة ضمنيًا، ويُقبل تحليل `import`/`export` و`await` على المستوى الأعلى |

تؤدي أي قيمة أخرى إلى طرح `\InvalidArgumentException`.

لمزيد من التحكم (مثل تهيئة الوضع الصارم مسبقًا لسياق direct-eval، أو قراءة توجيه `//# sourceURL`)، أنشئ المحلل مباشرة: `new Parser($source)` بالإضافة إلى `setModuleMode()` و`setStrictMode()` و`parse()`.

## العقد

ترث كل فئة AST من `Phasis\Ast\Node` وتقع ضمن `Phasis\Ast\{Declaration, Expression, Pattern, Statement}`. العقد كائنات قيم عادية للقراءة فقط:

- تعيد `$node->type()` سلسلة نوع العقدة، وهي الاسم الأساسي للفئة (`'BinaryExpression'` و`'ArrowFunction'` وغيرهما).
- تمثل `$node->location` قيمة `Phasis\Lexer\SourceLocation` تضم `line` (بدءًا من 1)، و`column` (بدءًا من 0)، وإزاحة البايت `offset`. تُخزّن مواضع البداية فقط؛ ولا تحمل العقد إزاحة النهاية.
- جميع الحقول العامة الأخرى هي أبناء العقدة وسماتها (`$binary->left` و`$binary->operator` و`$binary->right`).

تطابق معظم أسماء الأنواع [ESTree](https://github.com/estree/estree). أما الاختلافات فهي:

| نوع Phasis | نوع ESTree |
|---|---|
| `ArrowFunction` | `ArrowFunctionExpression` |
| `TaggedTemplate` | `TaggedTemplateExpression` |
| `ClassMethod` | `MethodDefinition` |
| `ClassProperty` | `PropertyDefinition` |
| `AssignmentProperty` | `Property` (داخل `ObjectPattern`) |
| `ExportDeclaration` | `ExportNamedDeclaration` / `ExportDefaultDeclaration` / `ExportAllDeclaration` |
| `ImportSpecifier` | `ImportSpecifier` / `ImportDefaultSpecifier` / `ImportNamespaceSpecifier` |

تختلف بعض البنى أيضًا: أجسام الفئات مصفوفة عناصر عادية في عقدة الفئة (من دون غلاف `ClassBody`)، وتُخزّن أسماء الاستيراد/التصدير وتسميات العبارات وأسماء `FunctionExpression` كسلاسل بدلًا من عقد `Identifier` متداخلة، كما يُحلّل `super` على أنه `Identifier` باسم `super` (ولا توجد فئة عقدة `Super`). يعيد `Phasis\Ast\EstreeSerializer` تشكيل كل ذلك وفق صيغة ESTree.

## الأخطاء النحوية

يؤدي الإدخال غير الصالح إلى طرح `Phasis\Exceptions\SyntaxError` (غالبًا فئته الفرعية `Phasis\Parser\ParseError`). تنتهي رسالة الاستثناء بالموضع، ويكون الموقع المنظّم متاحًا ضمن الاستثناء:

```php
use Phasis\Exceptions\SyntaxError;
use Phasis\Parser\Parser;

try {
    Parser::parseSource("const a = 1;\nconst b = ;");
} catch (SyntaxError $e) {
    echo $e->getMessage();          // Unexpected token (got ; ";") at line 2, column 10
    echo $e->location->line;        // 2
    echo $e->location->column;      // 10
    echo $e->location->offset;      // 23
}
```

## المتجوّل

يتنقل `Phasis\Ast\Walker` في الشجرة بترتيب العمق أولًا، مع استدعاءات رد عند الدخول والمغادرة، على غرار estraverse:

```php
public static function walk(Node $node, callable $enter, ?callable $leave = null): void
```

يتلقى كلا الاستدعاءين `(Node $node, ?Node $parent)`. وتؤدي إعادة `Walker::SKIP` من `$enter` إلى تخطي أبناء العقدة، مع الاستمرار في استدعاء `$leave` الخاص بالعقدة نفسها.

```php
use Phasis\Ast\Expression\Identifier;
use Phasis\Ast\Node;
use Phasis\Ast\Walker;

$names = [];
Walker::walk($program, function (Node $node) use (&$names) {
    if ($node instanceof Identifier) {
        $names[] = $node->name;
    }
    if ($node instanceof \Phasis\Ast\Expression\ArrowFunction) {
        return Walker::SKIP;
    }
});
```

التنقل للقراءة فقط. العقد كائنات قيم للقراءة فقط، لذا لا يتوفر دعم للاستبدال أو التعديل.

## المُسلسِل

يحوّل `Phasis\Ast\Serializer` شجرة AST المكتوبة الأنواع إلى مصفوفات أو JSON باستخدام أسماء الأنواع وتخطيط الحقول في Phasis، مع إزالة حقول الذاكرة المؤقتة الداخلية للمحلل:

```php
public static function toArray(Node $node): array
public static function toJson(Node $node, bool $pretty = false): string
```

هذا هو التنسيق الذي يطبعه `bin/phasis --ast`.

## EstreeSerializer

يحوّل `Phasis\Ast\EstreeSerializer` شجرة AST المكتوبة الأنواع إلى مصفوفات على نمط ESTree بدلًا من ذلك: أسماء أنواع ESTree (وفق جدول الاختلافات أعلاه)، وأسماء حقول ESTree وترتيبها، وعقد `ClassBody` / specifier / source-`Literal` مُنشأة، وإزاحة بايت `start` لكل عقدة محللة من المصدر. لا توجد إزاحات `end` لأن العقد لا تخزّن إلا مواضع البداية، كما أن عقد السلاسل `Literal` لا تحمل نص `raw`.

```php
public static function toArray(Node $node): array
public static function toJson(Node $node, bool $pretty = false): string
public static function summarize(Node $node): string
```

يصدر `summarize()` ملخصًا حتميًا بسطر لكل عقدة (النوع بالإضافة إلى سمات `name=` / `value=` / `op=` / `kind=`، مع مسافتين بادئتين لكل مستوى عمق). التنسيق مطابق بايتًا ببايت لملخص AST الذي ينتجه اختبار acorn في `tests/Popular/acorn`، لذا تتحقق الأداة المرجعية نفسها من مسار محلل JS ومن تصدير PHP هذا:

```php
use Phasis\Ast\EstreeSerializer;
use Phasis\Parser\Parser;

echo EstreeSerializer::summarize(Parser::parseSource('let x = a + 1;'));
// Program
//   VariableDeclaration kind=let
//     VariableDeclarator
//       Identifier name=x
//       BinaryExpression op=+
//         Identifier name=a
//         Literal value=1
```

## CLI

يحلّل `bin/phasis --ast script.js` ملفًا (بهدف Script) ويطبع تفريغ `Serializer` JSON بمسافتين بادئتين. راجع [CLI](https://phasis.inline0.dev/ar/docs/cli) للاطلاع على مرجع الخيارات كاملًا.
