Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions text/0000-جودة-تشخيص-أخطاء-المفسّر.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
- **عنوان المقترح:** تحسين جودة تشخيص أخطاء المفسّر (تصنيف صحيح + إخفاء آثار الاسترداد الداخليّة)
- **النطاق:** لغة `text/`
- **تاريخ البدء:** 2026-07-06
- **رقم الـ RFC:** (يُترك فارغاً حتى الدمج)
- **الحالة:** مقترَح (PR مفتوح)
- **Issue التتبُّع:** (يُترك فارغاً حتى القبول)

# ملخّص

يعالج هذا المقترح أربعة عيوب في تشخيص أخطاء **المفسّر** (`sad-run`) تُضعِف تجربة المبتدئ في أوّل تفاعل مع الأخطاء:

1. **وسم خاطئ:** خطأ **نحويّ** (SYN) يُوسَم «🔍 هذا خطأ **دلاليّ**».
2. **تسريب آثار داخليّة:** «=== إحصائيات الاسترداد === ناجح/فاشل» تظهر للمستخدم النهائيّ.
3. **رسالة مُضلِّلة + تناقض:** الخطأ المُستردّ يُعرَض بوصف فعل الاسترداد («إدراج ')' المفقودة») بدل وصف المشكلة، فيبدو أنّ الأداة أصلحت الكود ثمّ تُبلّغ عنه خطأً في آن.
4. **تلميح غير ذي صلة:** «استورد الوحدة المطلوبة» يظهر لكلّ **متغيّر** غير معرّف رغم أنّ جوابه الغالب «عرّفه».

النتيجة المرئيّة: عند حذف قوس إغلاق `)` وتشغيل البرنامج، يرى المستخدم رسالة عربيّة نظيفة تصف المشكلة وتصنّفها **نحويًّا** بلا ضجيج، بدل تقريرٍ متناقض يُوسَم «دلاليًّا» خطأً.

# الدافع (Motivation)

جولة الترحيب في محراب (رحلة P0) تَعِد المبتدئ بأنّ الخطأ «معلّمٌ لطيف» يشرح في ثلاث طبقات (ماذا/أين/كيف)، وتطلب منه تحديدًا **حذف `)` وتشغيل البرنامج**. لكنّ هذا المثال بالذات يُخرج أسوأ ناتج ممكن:

```
🔧 إدراج ')' المفقودة | Inserted missing ')'
=== إحصائيات الاسترداد ===
ناجح: 1
فاشل: 0
❌ error [SYN003]: <source>:2:1
│ إدراج ')' المفقودة
📝 note [SYN003]: ❌ إدراج ')' المفقودة
🔍 هذا خطأ دلالي.
❌ 1 خطأ
```

هذا يقوّض ثقة المبتدئ في أوّل ٩٠ ثانية: تصنيفٌ خاطئ، وضجيجٌ داخليّ، وتناقض «ناجح» ⇄ «❌ خطأ». الأخطاء نظام حَسَّاس للثقة؛ صوابُ تصنيفها ونظافةُ عرضها جزءٌ من العقد اللغويّ لا رفاهية.

# الشرح التوجيهي (Guide-level explanation)

**قبل** (حذف `)` من `اطبع("مرحبا يا عالم")`):

```
🔧 إدراج ')' المفقودة | Inserted missing ')'
=== إحصائيات الاسترداد === ناجح: 1 / فاشل: 0
❌ error [SYN003]: │ إدراج ')' المفقودة
🔍 هذا خطأ دلالي.
```

**بعد**:

```
❌ error [SYN003]: <source>:2:1
│ توقّعت ')' هنا
🔍 هذا خطأ نحوي.
💡 أضف ')' المقابل لإغلاق التعبير.
```

المبدأ للمستخدم: **الاسترداد آليّةٌ داخليّة** يستعملها المحلّل ليتابع البحث عن أخطاء أخرى — لا وعدٌ بإصلاح كوده. لذا لا يرى المستخدم «ماذا أدرجت الأداة»، بل «ما المشكلة وأين وكيف يُصلحها». آثار الاسترداد (الإحصائيّات + أفعال «🔧») تبقى متاحةً للمطوّر عند ضبط متغيّر البيئة `SAD_DIAG_STATS`.

# الشرح المرجعي (Reference-level explanation)

- **مصدر الحقيقة (`language-truth/`):** **لا تغيير.** الرمز `SYN_UNCLOSED_BRACKET` (SYN003) وطبقاته الوديّة موجودة سلفًا في `errors/syntactic.yaml`. المقترح **إنفاذ** لا توسيع (يوافق مبدأ «الأدوات/الإصلاحات لا توسّع SoT»).

- **العيب ١ — التصنيف** (`shared/errors/src/smart_teacher_mode.cpp::generateBasicExplanation`): الشرط `errorCode.substr(0,1)=="S"` لفئة «دلاليّ» يلتقط رموز **SYN** (تبدأ بـ`S`) قبل فرع «نحويّ»، فيصير الأخير ميّتًا. الإصلاح: فحص الرموز الثلاثيّة الصريحة (`TYPE`/`SYN`/`SEM`/`LEX`/`RUN`) أوّلًا، وإبقاء الحرف المفرد (`T`/`P`/`S`) احتياطًا لرموز قديمة أحاديّة الحرف فقط. (مثاليًّا يُستبدَل الحدس لاحقًا بـ`getErrorCategory(ErrorCode)` الموثوق — عملٌ تابع.)

- **العيب ٢ — تسريب الإحصائيّات** (`shared/parser/src/core/parser_main.cpp`): `std::cerr << formatStats(true)` يُبثّ بلا شرط عند حدوث استردادات. الإصلاح: حجبه خلف متغيّر البيئة `SAD_DIAG_STATS` (ثابت `Errors::kDiagStatsEnvVar` في `error_recovery.h`).

- **العيب ٣ — رسالة الاسترداد + طبع «🔧»** (`shared/parser/src/core/parser_helpers.cpp::tryRecoverFromError`): في حالة `INSERT_TOKEN` تُمرَّر `result.action.description` («إدراج ')'») كرسالة الخطأ. الإصلاح: تمرير رسالة تصف المشكلة «توقّعت '<expected>' هنا / Expected '<expected>' here»، مع إبقاء تسجيل الخطأ (لا نبتلعه — يظلّ خطأً حقيقيًّا يعكسه `hasErrors()`). وطبعا «🔧» للإدراج والمزامنة يُحجبان خلف `SAD_DIAG_STATS`.

- **العيب ٤ — تلميح الاستيراد** (`shared/errors/src/smart_suggestions.cpp`): `generateUndefinedSymbolSuggestions` يدفع «استورد الوحدة» (LOW) لكلّ رمز غير معرّف. الإصلاح: قصره على **الدوالّ** غير المعرّفة (`SEM_UNDEFINED_FUNCTION`) عبر مفتاح داخليّ `undef_kind=function` يمرّره `generateFromErrorCode`؛ المتغيّر غير المعرّف يبقى باقتراح «عرّفه» وحده.

- **المفسّر:** هو المستفيد المباشر (مسار `sad-run`). **المترجم (sadc):** المكوّنات في `shared/` مشتركة؛ لا تغيير سلوكيّ في مسار التوليد (الإصلاحات في طبقتَي التشخيص والاسترداد النصّيّتين).

- **نظام الأخطاء:** لا رموز جديدة. تُصحَّح رسالة/تصنيف رمزٍ قائم فقط.

- **التوافق الخلفي:** لا يكسر برامج `.ص` قائمة (رموز الخروج ومنطق `hasErrors()` كما هي؛ التغيير في نصّ الرسائل وحجب آثار المطوّر). قد تحتاج اختبارات ذهبيّة تلتقط النصّ القديم للتحديث.

# السلبيات (Drawbacks)

- تغيير نصّ رسائل قد يكسر اختبارات ذهبيّة/لقطات تعتمد الصياغة القديمة (تُحدَّث ضمن هذا العمل).
- حجب الإحصائيّات خلف متغيّر بيئة يعني أنّ المطوّر يحتاج معرفته لتفعيل الأثر (يُوثَّق).

# المبرّرات والبدائل (Rationale and alternatives)

- **البديل لـ٢/٣ (حذفٌ كامل بدل حجب):** يفقد المطوّر أداة تشخيص مفيدة؛ الحجب خلف متغيّر بيئة يوازن بين نظافة المستخدم وحاجة المطوّر.
- **البديل لـ١ (استعمال `getErrorCategory` فورًا):** أنظف لكنّه يتطلّب تمرير `ErrorCode` عبر توقيعات وضع المعلّم؛ إعادة الترتيب تُصلح العلّة فورًا بأقلّ خطر، وتُترك الاستعاضة الكاملة عملًا تابعًا.
- **عدم فعل شيء:** يُبقي وعد جولة الترحيب مكسورًا وتجربة الخطأ الأولى مربكة.

# أعمال سابقة (Prior art)

- **Rust/Elm:** تفصلان بوضوح بين *ما الخطأ* و*كيف يُصلَح*، ولا تُظهران آليّات الاسترداد الداخليّة للمستخدم.
- **Clang:** يستعمل استرداد الأخطاء داخليًّا («توقّعت ')'») دون بثّ «أدرجتُ ')'» كإنجاز؛ رسالته تصف التوقّع لا الفعل — وهو نموذج العيب ٣ المعتمَد هنا.

# أسئلة غير محسومة (Unresolved questions)

- هل يُوحَّد اسم متغيّر البيئة التشخيصيّ (`SAD_DIAG_STATS`) مع أيّ راية verbose مستقبليّة للمحرّكين؟
- توقيت الاستعاضة الكاملة عن حدس التصنيف بـ`getErrorCategory(ErrorCode)` (عملٌ تابع خارج نطاق هذا الـRFC).
- هل تُحجب أيضًا أفعال «🔧» ذات القيمة الإرشاديّة (did-you-mean / تخطّي رمز زائد)؟ (تُركت ظاهرةً لأنّها إرشادٌ فعليّ للمستخدم لا أثرُ استرداد صامت.)

# الآفاق المستقبلية (Future possibilities)

> ما الامتدادات الطبيعيّة لهذا العمل مستقبلًا؟

- استبدال حدس تصنيف الخطأ في وضع المعلّم بالمصدر الموثوق `getErrorCategory(ErrorCode)` (المُشتقّ من `category` في YAML) بدل فحص بادئة السلسلة — يُلغي جذر العيب ١ نهائيًّا.
- توحيد متغيّر البيئة التشخيصيّ `SAD_DIAG_STATS` ضمن راية verbose عامّة للمحرّكين إن استُحدثت.
- ترقية أفعال الاسترداد الإرشاديّة الباقية (did-you-mean / تخطّي رمز زائد) من طبع `cerr` خام إلى تشخيصات ضمن نظام الأخطاء الموحَّد.
- تمييز نصّ تلميح الرمز غير المعرّف: «عرّف الدالّة» للدوالّ مقابل «عرّف المتغير» للمتغيّرات.
Loading