diff --git "a/text/0000-\330\252\331\210\330\255\331\212\330\257-\331\202\330\247\330\271\330\257\330\251-\330\247\331\204\330\257\330\247\331\204\330\251-\330\247\331\204\330\261\330\246\331\212\330\263\331\212\330\251-\330\271\330\250\330\261-\330\247\331\204\331\205\330\255\330\261\331\221\331\203\331\212\331\206.md" "b/text/0000-\330\252\331\210\330\255\331\212\330\257-\331\202\330\247\330\271\330\257\330\251-\330\247\331\204\330\257\330\247\331\204\330\251-\330\247\331\204\330\261\330\246\331\212\330\263\331\212\330\251-\330\271\330\250\330\261-\330\247\331\204\331\205\330\255\330\261\331\221\331\203\331\212\331\206.md" new file mode 100644 index 0000000..f8ae3d5 --- /dev/null +++ "b/text/0000-\330\252\331\210\330\255\331\212\330\257-\331\202\330\247\330\271\330\257\330\251-\330\247\331\204\330\257\330\247\331\204\330\251-\330\247\331\204\330\261\330\246\331\212\330\263\331\212\330\251-\330\271\330\250\330\261-\330\247\331\204\331\205\330\255\330\261\331\221\331\203\331\212\331\206.md" @@ -0,0 +1,111 @@ +- **عنوان المقترح:** توحيد قاعدة الدالة الرئيسية (SEM018) عبر المحرّكين +- **النطاق:** لغة `text/` +- **تاريخ البدء:** 2026-07-05 +- **رقم الـ RFC:** (يُترك فارغاً حتى الدمج) +- **الحالة:** مقترَح (PR مفتوح) +- **Issue التتبُّع:** (يُترك فارغاً حتى القبول) + +# ملخّص + +قاعدة الدالة الرئيسية **SEM018** («تعارض الدالة الرئيسية مع كود المستوى الأعلى») مُعرَّفة +في مصدر الحقيقة `language-truth/errors/semantic.yaml`، لكنّها **مفروضة في المفسّر وحده** +(`interpreter_core`). المترجم `sad-build` يقبل البرنامج المخالِف بصمت ثمّ **يتجاهل الكود +العلويّ** عند التنفيذ. هذا المقترح ينقل الفحص إلى مكوّن مشترك `sad_program_rules` في `shared/` +يستدعيه **المحرّكان**، فيصير سلوكهما واحدًا (رفض SEM018) — على منوال `sad_null_safety` +و`sad_ownership`. النتيجة المرئية: `sad-build` يرفض ما يرفضه `sad-run` بالرسالة نفسها ورمز +خروج غير صفريّ، بلا تنفيذ الكود. + +# الدافع (Motivation) + +- **تباعد محرّكات مُثبَت تجريبيًّا:** لملفٍّ فيه `دالة رئيسية` + جملة علويّة `اطبع_سطر(٢)`: + - `sad-run` ⇐ خطأ SEM018، رمز خروج 1. + - `sad-build` ⇐ يبني تنفيذيًّا ناجحًا، يطبع مخرجات `رئيسية` فقط **ويُهمل العلويّ صامتًا**. + الإهمال الصامت أسوأ من الرفض: يخفي خطأً منطقيًّا عن المستخدم. +- **مصدر الحقيقة قرّر سلفًا:** SEM018 قاعدة دلاليّة رسميّة في `semantic.yaml` (fix_hint: + «اجعل رئيسية نقطة الدخول الوحيدة»). المترجم هو **غير الممتثل**، لا اللغة ناقصة. +- **حاجة أدوات المنظومة:** طبقة الذكاء (نِبراس) تحتاج **فحصًا دلاليًّا بلا تنفيذ** يمسك مثل + هذه المخالفات كي تتحقّق من الكود المولَّد دون تشغيله (احترامًا لآلة الأذونات). توحيد القاعدة + في المترجم يجعل `sad-build -c` (ترجمة بلا ربط، بلا تنفيذ) قناةَ التحقّق الطبيعيّة. + +# الشرح التوجيهي (Guide-level explanation) + +نموذج نقطة الدخول في ص: **إمّا** أن تُعرّف `دالة رئيسية` فتكون نقطة الدخول الوحيدة، **وإمّا** +أن تكتب كودًا في المستوى الأعلى يُنفَّذ تلقائيًّا عند غياب `رئيسية` — لا الاثنان معًا. + +```sad +# ✅ سليم: رئيسية وحدها نقطة الدخول +دالة رئيسية() + اطبع_سطر("مرحبا") +نهاية + +# ✅ سليم: لا رئيسية ⇒ الكود العلويّ يُنفَّذ تلقائيًّا +اطبع_سطر("مرحبا") + +# ❌ خطأ SEM018: رئيسية + كود علويّ معًا (يلتبس ترتيب الدخول) +دالة رئيسية() + اطبع_سطر("أ") +نهاية +اطبع_سطر("ب") # ← جملة تنفيذية علويّة مع وجود رئيسية +``` + +بعد هذا التغيير يرفض **المترجم والمفسّر** الحالة الأخيرة برسالة SEM018 نفسها. يبقى مسموحًا مع +`رئيسية`: التصريحات (دوال/أصناف/تعدادات/قوالب/فضاءات أسماء)، والمتغيّرات العامّة، +وجُمل الاستيراد/التصدير. + +# الشرح المرجعي (Reference-level explanation) + +- **مصدر الحقيقة (`language-truth/`):** لا تغيير — SEM018 معرّف سلفًا. هذا المقترح **إنفاذ** + لقاعدة قائمة لا توسيعٌ للّغة. +- **المكوّن المشترك الجديد `shared/program_rules/` (مكتبة `sad_program_rules`):** + دالّة نقيّة `Sad::Semantic::checkMainFunctionRule(program) → {hasMain, ok, line, column}` + — قراءة فقط، بلا إبلاغ (كلّ محرّك يُبلّغ عبر مساره من رمز الكتالوج نفسه). تنقل منطق + `interpreter_core` حرفيًّا: كشف `FunctionDecl::isMainFunction`، ثمّ منع أيّ جملة علويّة ليست + تصريحًا/متغيّرًا عامًّا/جملة وحدة. +- **المفسّر:** يستبدل الحلقة المضمّنة باستدعاء `checkMainFunctionRule`؛ يُبلّغ عبر + `ErrorManager::reportFromCatalog(SEM_MAIN_FUNCTION_RULE, loc)` (تحسين: موقع المخالفة الحقيقيّ + بدل 1:1 الثابت). +- **المترجم (sadc):** يستدعي القاعدة بعد التحليل النحويّ وقبل بناء SIR؛ عند المخالفة يُبلّغ عبر + `diagnostics_.report_error(buildBilingualMessage(SEM018, ctx))` ويعيد `false` (⇒ رمز خروج + غير صفريّ). **يُتجاوَز في `--freestanding`/`--no-main`** (لا حقن `main` افتراضيّ، نقطة دخول + مخصّصة عبر `--entry-point`). لا أثر على SIR/LLVM codegen (الرفض يسبق البناء). +- **نظام الأخطاء:** لا رمز جديد — يُعاد استعمال `SEM_MAIN_FUNCTION_RULE` (SEM018). +- **الأدوات:** يفتح البابَ لتوصيل تحقّق نِبراس بـ`sad-build -c`. LSP/المنسّق: بلا أثر مباشر. +- **التوافق الخلفي:** ⚠️ **كسر سلوكيّ مقصود:** برامج تُبنى اليوم بـ`sad-build` وتحوي `رئيسية` + + كودًا علويًّا سيبدأ رفضها (كانت تُبنى وتُهمِل العلويّ صامتًا). هذا تصحيحٌ لسلوكٍ صامتٍ + خاطئ، ومتوائم مع المفسّر الذي يرفضها أصلًا. الهروب الرسميّ: `--freestanding`/`--no-main`. + +# السلبيات (Drawbacks) + +- كسر توافقيّ محدود (أعلاه) قد يُفاجئ من اعتمد الإهمال الصامت في المترجم. +- مكتبة مشتركة جديدة (عبء صيانة ضئيل — ملفّان + CMake، على نمط قائم). + +# المبرّرات والبدائل (Rationale and alternatives) + +- **البديل أ — `--fsyntax-only` على المفسّر:** راية فحص بلا تنفيذ تعيد استعمال فحوص المفسّر. + أقلّ تدخّلًا لكنّها **لا تُنهي التباعد** (المترجم يبقى غير ممتثل) وتُبقي مصدرَي حقيقة. +- **البديل ب (المُختار) — التوحيد في `shared/`:** مصدر حقيقة واحد يستهلكه المحرّكان، يُنهي + التباعد جذريًّا، ويتّسق مع سابقة `sad_null_safety` (NS-01) و`sad_ownership`. +- **عدم فعل شيء:** يُبقي إهمالًا صامتًا في المترجم وتباعدًا بين المحرّكين — غير مقبول. + +# أعمال سابقة (Prior art) + +- **Rust/Go:** كود المستوى الأعلى القابل للتنفيذ ممنوع خارج `main`/الدوال أصلًا (نموذج نقطة + دخول واحدة صريحة). ص تسمح بنموذجَي دخول (رئيسية أو سكربت علويّ) لكن تمنع خلطهما — وهو ما + تفرضه هذه القاعدة على المحرّكين معًا. +- **سابقة داخليّة:** RFC 0003 (نظام أمان null) و`sad_ownership` أرسيا نمط «فحص مشترك يستدعيه + المحرّكان»؛ هذا المقترح يطبّقه على قاعدة الدالة الرئيسية. + +# أسئلة غير محسومة (Unresolved questions) + +- هل يُوسَّع `sad_program_rules` لاحقًا ليضمّ قواعد بنيويّة أخرى مفروضة في محرّك واحد فقط + (مسحٌ لاحق لرصد تباعدات مشابهة)؟ +- هل يُضاف اختبار تكافؤ آليّ (golden) يشغّل عيّنة على المحرّكين ويؤكّد تطابق قبول/رفض SEM018؟ + +# إمكانات مستقبلية (Future possibilities) + +- **توسيع `sad_program_rules`:** استضافة قواعد بنيويّة أخرى مفروضة اليوم في محرّك واحد فقط + (مسحٌ منهجيّ لرصد تباعدات مماثلة ونقلها إلى المكوّن المشترك) — إنهاء التباعد فئةً كاملة. +- **سدّ ثغرة harness السلبيّة:** جعل الاختبارات السلبيّة (`@expect_error`) تفحص **المترجم** أيضًا + لا المفسّر وحده (تتوقّف حاليًّا عند خطأ المفسّر) — كي لا يتكرّر بقاء تباعدٍ خفيًّا كهذا. +- **مدخل فحص دلاليّ صريح:** راية `--fsyntax-only` (فحص بلا تنفيذ) تُبنى فوق القاعدة الموحَّدة، + تُيسّر لأدوات المنظومة (نِبراس) التحقّقَ الدلاليّ دون توليد/ربط/تنفيذ.