diff --git "a/text/0000-\330\252\330\263\331\205\331\212\330\251-\331\205\330\257\331\205\330\254\330\247\330\252-\330\247\331\204\330\271\330\252\330\247\330\257-\331\201\330\271\331\204-\330\243\331\210\331\221\331\204\331\213\330\247.md" "b/text/0000-\330\252\330\263\331\205\331\212\330\251-\331\205\330\257\331\205\330\254\330\247\330\252-\330\247\331\204\330\271\330\252\330\247\330\257-\331\201\330\271\331\204-\330\243\331\210\331\221\331\204\331\213\330\247.md" index 5494d70..dc5c365 100644 --- "a/text/0000-\330\252\330\263\331\205\331\212\330\251-\331\205\330\257\331\205\330\254\330\247\330\252-\330\247\331\204\330\271\330\252\330\247\330\257-\331\201\330\271\331\204-\330\243\331\210\331\221\331\204\331\213\330\247.md" +++ "b/text/0000-\330\252\330\263\331\205\331\212\330\251-\331\205\330\257\331\205\330\254\330\247\330\252-\330\247\331\204\330\271\330\252\330\247\330\257-\331\201\330\271\331\204-\330\243\331\210\331\221\331\204\331\213\330\247.md" @@ -87,6 +87,12 @@ كسر قاطع) لأنّه يُبقي النمط الأعجميّ حيًّا ويضاعف مصدر الحقيقة. - **الإبقاء على الحال**: مرفوض — يرسّخ تناقضًا نحويًّا في قلب اللغة. +# السلبيات (Drawbacks) + +- **كسر قاطع لكلّ مستهلك**: أيّ برنامج ص يستعمل الأسماء القديمة يتوقّف عن الترجمة + حتى يُرحَّل (تفصيله في قسم التوافق أدناه). +- **عبء ترحيل تابع**: مستودعات ص الخارجيّة (sad-os مثلًا) يلزمها ترحيل متزامن. + # التأثير على التوافق (Compatibility / Migration) **كسر قاطع**: كلّ برنامج ص يستعمل الأسماء القديمة يتوقّف عن الترجمة حتى يُرحَّل. @@ -97,7 +103,20 @@ - **دَين معلَن**: `sad-os` وأيّ مستودع ص آخر يستعمل هذه المدمجات يلزمه ترحيل تابع (يُتتبَّع بـIssue منفصل عند القبول). -# الأسئلة المفتوحة (Unresolved questions) +# أعمال سابقة (Prior art) + +- **ترتيب فعل-فاعل في العربيّة الفصحى**: الجملة الفعليّة تبدأ بالفعل («اقرأ المنفذ»)، + وهو الأصل النحويّ الذي تبني عليه هذه القاعدة. +- **تسمية دوالّ POSIX/النظم (`read`/`write`/`ioctl`)**: الفعل أوّلًا سابقة راسخة في + واجهات العتاد، تُعرَّب هنا بالحفاظ على البنية الفعليّة لا قلبها. +- **مبدأ «مصدر حقيقة وحيد» في قلب اللغة الموحَّد (RFC #10)**: يمنع ازدواج التسمية. + +# الأسئلة المفتوحة / غير محسومة (Unresolved questions) - هل تُعمَّم قاعدة «فعل-أوّلًا» لاحقًا على مدمجات أخرى مقلوبة إن وُجدت (تدقيق شامل للكتالوج)؟ يُقترح تدقيقٌ تابع بعد إقرار هذا المبدأ. + +# أعمال مستقبلية (Future work) + +- تدقيق شامل لكتالوج المدمجات يكشف أيّ اسم مقلوب متبقٍّ ويوحّده على «فعل-أوّلًا». +- توثيق القاعدة في دليل المطوّر كي تُطبَّق على أيّ مدمج عتاد جديد تلقائيًّا. diff --git "a/text/0000-\330\261\331\205\331\210\330\262-\330\263\330\250\330\250-\330\247\331\204\331\207\331\204\330\271-\330\247\331\204\331\205\330\263\331\205\331\221\330\247\330\251.md" "b/text/0000-\330\261\331\205\331\210\330\262-\330\263\330\250\330\250-\330\247\331\204\331\207\331\204\330\271-\330\247\331\204\331\205\330\263\331\205\331\221\330\247\330\251.md" new file mode 100644 index 0000000..6ce0f3c --- /dev/null +++ "b/text/0000-\330\261\331\205\331\210\330\262-\330\263\330\250\330\250-\330\247\331\204\331\207\331\204\330\271-\330\247\331\204\331\205\330\263\331\205\331\221\330\247\330\251.md" @@ -0,0 +1,127 @@ +- **عنوان المقترح:** رموز سبب الهلع المسمّاة (ABI نداء `__sad_panic` في الوضع الحرّ) + تمييز فشل التأكيد +- **النطاق:** لغة `text/` +- **تاريخ البدء:** 2026-07-22 +- **رقم الـ RFC:** 49 (رقم PR هذا المقترح) +- **الحالة:** مقترَح (PR مفتوح: sadlang/rfcs#49) — نُفِّذ في المترجم sadlang/s-programming-language#248 (مدموج) واستهلكته نواة النحلة (المرحلة ب، مدموجة) +- **Issue التتبُّع:** (يُترك فارغاً حتى القبول) + +# ملخّص + +في الوضع الحرّ، كلّ مواقع نداء `__sad_panic` الخمسة في المولِّد تمرّر الوسيطَ +الثابتَ السحريّ `1`. فيُصنّف البرنامج الحرّ (نواة النحلة) **كلّ** أنواع الفشل رمزًا +واحدًا (خطأ_انتهاك_مترجم). يقترح هذا المقترح: (١) استبدال `1` بثوابت مسمّاة في +`sir_constants.h` (عقد ABI)، و(٢) منح فشل عامل التأكيد `مؤكَّد` (نظير RUN056) +رمزًا مميَّزًا (`kSadPanicNullAssert = 2`) كي تُصنّفه النواة بدقّة لا كـ«تجاوز حدّ»، +و(٣) كبت سطر RUN056 العربيّ السابق للّافتة في الوضع الحرّ (اللافتة التشخيص الوحيد). + +# الدافع (Motivation) + +نواة النحلة تُخرِّط وسيط `__sad_panic` إلى لافتة `[هلع-ص نظام:<نظام> رمز:<رقم>]`. +لأنّ المولِّد يمرّر `1` دائمًا، تظهر كلّ الانتهاكات رمز:4 (خطأ_انتهاك_مترجم) — +بما فيها فشل عامل التأكيد على قيمة عدم، وهو **ليس** تجاوز حدّ ولا وسم تعداد خاطئ +بل تأكيد مستخدم انكسر. رصدت مراجعة سابقة هذا التصنيف الخاطئ. كما أنّ المولِّد يطبع +سطر RUN056 العربيّ قبل اللافتة في الوضع الحرّ (يخالف مبدأ «اللافتة التشخيص +الوحيد» الذي أرساه مقترح كبت التشخيص الإنجليزيّ). + +# الشرح التوجيهيّ (Guide-level explanation) + +للقارئ الذي يكتب برنامجًا حرًّا (نواة/محمَّل إقلاع) يعرّف `__sad_panic` بنفسه: بدل +أن تصل كلّ حالات الفشل القاتلة برمز واحد لا يميّز بينها، صار المولِّد يمرّر **رمز +سبب** يقول لماذا هلع البرنامج. اليوم قيمتان: `1` = فحص بنيويّ زرعه المولِّد +(تجاوز حدّ مصفوفة، وسم تعداد خاطئ، تأكيد وسيط) و`2` = فشل عامل التأكيد اللاحق +`مؤكَّد` (نظير RUN056: طُبِّق على قيمة عدم). يستقبل المستهلك القيمة معاملًا واحدًا +`(i64)` ويُخرِّطها إلى لافتته/كتالوجه كما يشاء — نواة النحلة مثلًا تُخرِّط `2` إلى +رمز خطأ مخصَّص (`خطأ_تأكيد_عدم`) فتظهر لافتة مميَّزة بدل خلطها مع تجاوز الحدّ. من +لا يعنيه التمييز يعامل أيّ قيمة ≠ الحالات المعروفة كفشل بنيويّ عامّ (سلوك آمن +افتراضيًّا: يوقِف دائمًا). لا يتغيّر توقيع ABI ولا نحو اللغة. + +# الشرح المرجعيّ (Reference-level explanation) + +- عقد رموز السبب في `compiler/include/frontend/sir_constants.h`: + - `kSadPanicCheckViolation = 1` — فحص بنيويّ يزرعه المولِّد فشل (حدّ مصفوفة، + وسم تعداد خاطئ، إجهاض `abort`، مدمج أمنيّ). **يبقى 1** للتوافق التاريخيّ. + - `kSadPanicNullAssert = 2` — فشل عامل التأكيد اللاحق `مؤكَّد` على قيمة عدم. + حصريّ له؛ مدمجا `تأكد`/`ذعر` يبقيان 1. + - **مستقرّ:** لا تُعاد ترقمة القيم (المستهلكون يعتمدونها) — يحرسه + `static_assert(kSadPanicCheckViolation != kSadPanicNullAssert)`. + - رسالة RUN056 العربيّة رُفعت إلى ثابت مسمّى `kNullAssertRun056Msg` (لا سلسلة + حرفيّة منطقيّة في الكود). +- المواقع الخمسة (`array_ops`, `enum_ops`, `builtin_funcs_ops` assert, `security_builtins_ops`, + `arith_main` null-assert) صارت تستعمل الثوابت المسمّاة بدل `1`. أربعة تحمل + `kSadPanicCheckViolation`؛ `arith_main` وحده `kSadPanicNullAssert`. +- **توحيد بناء النداء:** دالّة `LLVMCodeGen::emitFreestandingPanicCall(reasonCode)` + (في `llvm_codegen.h`) تبني `call void @__sad_panic(i64 reason)` مرّة واحدة؛ + وُحِّدت عليها المواقع الخمسة كي لا يُمرَّر رمز سبب خاطئ يدويًّا. لا تُصدر + `unreachable` (المنادي يضيفه، وقد يُشارَك مع المسار المستضاف). +- `arith_main` (الوضع الحرّ): كبت `printf("خطأ [RUN056]…")` — اللافتة العربيّة + السياديّة (النواة تُصنّفها «تأكيد على عدم» عبر رمز 2) هي التشخيص الوحيد. المستضاف + يُبقي RUN056 العربيّ + exit للمطوّر. +- `builtin_funcs_ops` (`emitBuiltinAssert` الكامن): نُقل سطر «Assertion failed» + الإنجليزيّ إلى فرع المستضاف حصرًا (إصلاح دفاعيّ؛ الواجهة تُخفِض `تأكد` إلى + `BUILTIN_SECURITY_ASSERT`/مسار الأمن `sec.fail` فهذا المسار غير مُنتَج اليوم). + +# البدائل (Alternatives) + +1. **رمز مميَّز لكلّ موقع** (حدّ/تعداد/إجهاض/أمن منفصلة): أدقّ لكنّه يوسّع كتالوج + المستهلك بلا حاجة الآن؛ المقترح يفصل الصنف الأهمّ (تأكيد) ويُبقي البنيويّة + موحَّدة (1)، قابلة للتوسيع لاحقًا (القيم 3+ متاحة). +2. **الإبقاء على `1` وتصنيف النواة داخليًّا:** مستحيل — النواة لا تملك سياقًا تميّز + به مصدر الهلع؛ الوسيط هو المعلومة الوحيدة. +3. **توسيع ABI بتمرير تفاصيل (فهرس/طول/رسالة):** يكسر تواقيع النواة القائمة + (`(i64)`)؛ خارج النطاق. + +# السلبيات والمخاطر والتخفيف (Drawbacks) + +- **مستهلك يفترض `1` دائمًا:** نواة النحلة حُدِّثت بالتوازي (المرحلة ب) لتُخرِّط 2 → + رمز كتالوج مخصَّص؛ سلوكها القديم (تجاهل الوسيط) يبقى صحيحًا لرمز 1. المستهلكون + الآخرون (إن وُجدوا) يرون 1 كما كان لكلّ ما عدا التأكيد. +- **الاحتياطيّ الضعيف `[SAD PANIC %lld]`:** يعرض الآن 1 أو 2 — تحسّن تشخيصيّ لا كسر. +- **عبء عقد ثنائيّ:** القيمتان تصيران عقدًا مستقرًّا يلزم المستهلك والمولِّد الاتّفاق + عليه؛ خفّفناه بثابت مسمّى واحد في `sir_constants.h` وحارس `static_assert` للتفرّد. + +# الاختبارات + +(‏`tests/system/lowlevel_freestanding/test_bounds_diag_sovereign.py`) +- `test_freestanding_bounds_fail_no_english_diagnostic`: الحدّ يمرّر `@__sad_panic(i64 1)`. +- `test_freestanding_null_assert_distinct_code_no_arabic_line`: التأكيد يمرّر + `@__sad_panic(i64 2)` وبلا `na.fmt`/`RUN056`. +- `test_hosted_null_assert_keeps_arabic_diagnostic`: مستضاف ⇒ `na.fmt` + `exit`. +- `test_panic_reason_codes_are_distinct`: 1 (حدّ) ≠ 2 (تأكيد)، لا خلط. +- `test_freestanding_user_assert_check_violation_no_english`: مسار `تأكد` + (sec.fail) حرًّا ⇒ `@__sad_panic(i64 1)` بلا `exit` (يحرس بقاء مواقع الانتهاك + غير-الحدّ على رمز 1). +- `test_hosted_user_assert_uses_abort`: مستضاف ⇒ `abort` بلا `__sad_panic`. +- المجموع: 65 اختبار وضع حرّ خضراء، `gen --check` أخضر. + +# الأثر على مصدر الحقيقة + +الثوابت تُضاف إلى `sir_constants.h` (مصدر ثوابت المولِّد). لا تغيير في نحو اللغة +ولا كتالوج المفردات ولا LSP — عقد ABI خلفيّ للوضع الحرّ. المستهلك (النواة) يوثّق +الخريطة عنده (رموز.ص). + +# أعمال سابقة (Prior art) + +- **`errno`/رموز خروج POSIX:** سابقة راسخة لتصنيف الفشل برمز عدديّ صغير مستقرّ عبر + حدّ ABI، يُخرِّطه المستهلك إلى رسالة بلغته — النمط نفسه هنا. +- **`__stack_chk_fail`/`abort` في libc:** دوالّ هلع بلا معامل تفرّق الأسباب؛ يتجاوزها + هذا المقترح بمعامل سبب واحد يبقي التوقيع البسيط `(i64)`. +- **مقترح كبت التشخيص الإنجليزيّ للوضع الحرّ (s-programming-language#243):** أرسى مبدأ + «اللافتة السياديّة هي التشخيص الوحيد» الذي يمدّده هذا المقترح لمسار التأكيد. +- **هجرة `__sad_panic`/`__stack_chk_fail`/`__stack_chk_guard` إلى ص (أخ.3/أخ.4، #238/#239):** + الأساس الذي يجعل النواة تملك تعريف مسار الهلع فتستطيع تخريط رمز السبب. + +# أسئلة غير محسومة (Unresolved questions) + +- هل يُفصَل مدمجا `تأكد`/`ذعر` (يشتركان اليوم في `1`) برمزَي سبب مميّزين لاحقًا؟ + يتطلّب توسيع العقد (قيم 3+) ومقترحًا لاحقًا. +- المسار الكامن `emitBuiltinAssert` (لا مُنتِج له في الواجهة اليوم): هل يُغطّى + باختبار على مستوى SIR مباشرةً بدل الاعتماد على مسار أماميّ غائب؟ +- هل تُوحَّد خريطة رمز السبب بين المستهلكين (نواة النحلة + أيّ مستهلك مستقبليّ) + في جدول مشترك، أم يبقى كلّ مستهلك حرًّا في تخريطه؟ + +# أعمال مستقبلية (Future work) + +- توسيع الكتالوج بقيم سبب بنيويّة أدقّ (حدّ مصفوفة/وسم تعداد/إجهاض منفصلة) عند + الحاجة — القيم 3+ متاحة دون كسر المستهلكين الحاليّين. +- تمرير سياق إضافيّ اختياريّ (فهرس/طول) عبر توقيع موسَّع منفصل لا يكسر `(i64)`. +- اختبار تغطية مباشر لمسار `emitBuiltinAssert` الكامن (انظر الأسئلة غير المحسومة).