Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -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` (فحص بلا تنفيذ) تُبنى فوق القاعدة الموحَّدة،
تُيسّر لأدوات المنظومة (نِبراس) التحقّقَ الدلاليّ دون توليد/ربط/تنفيذ.
Loading