diff --git "a/text/0000-\330\254\331\210\330\257\330\251-\330\252\330\264\330\256\331\212\330\265-\330\243\330\256\330\267\330\247\330\241-\330\247\331\204\331\205\331\201\330\263\331\221\330\261.md" "b/text/0000-\330\254\331\210\330\257\330\251-\330\252\330\264\330\256\331\212\330\265-\330\243\330\256\330\267\330\247\330\241-\330\247\331\204\331\205\331\201\330\263\331\221\330\261.md" new file mode 100644 index 0000000..eeeca56 --- /dev/null +++ "b/text/0000-\330\254\331\210\330\257\330\251-\330\252\330\264\330\256\331\212\330\265-\330\243\330\256\330\267\330\247\330\241-\330\247\331\204\331\205\331\201\330\263\331\221\330\261.md" @@ -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]: :2:1 +│ إدراج ')' المفقودة +📝 note [SYN003]: ❌ إدراج ')' المفقودة +🔍 هذا خطأ دلالي. +❌ 1 خطأ +``` + +هذا يقوّض ثقة المبتدئ في أوّل ٩٠ ثانية: تصنيفٌ خاطئ، وضجيجٌ داخليّ، وتناقض «ناجح» ⇄ «❌ خطأ». الأخطاء نظام حَسَّاس للثقة؛ صوابُ تصنيفها ونظافةُ عرضها جزءٌ من العقد اللغويّ لا رفاهية. + +# الشرح التوجيهي (Guide-level explanation) + +**قبل** (حذف `)` من `اطبع("مرحبا يا عالم")`): + +``` +🔧 إدراج ')' المفقودة | Inserted missing ')' +=== إحصائيات الاسترداد === ناجح: 1 / فاشل: 0 +❌ error [SYN003]: │ إدراج ')' المفقودة +🔍 هذا خطأ دلالي. +``` + +**بعد**: + +``` +❌ error [SYN003]: :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 '' 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` خام إلى تشخيصات ضمن نظام الأخطاء الموحَّد. +- تمييز نصّ تلميح الرمز غير المعرّف: «عرّف الدالّة» للدوالّ مقابل «عرّف المتغير» للمتغيّرات.