diff --git "a/text/0000-\330\252\331\203\330\247\331\201\330\244-\330\252\330\271\330\257\331\212\331\204-\330\271\331\206\330\265\330\261-\330\271\330\247\331\205\331\221-\330\250\331\212\331\206-\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\203\330\247\331\201\330\244-\330\252\330\271\330\257\331\212\331\204-\330\271\331\206\330\265\330\261-\330\271\330\247\331\205\331\221-\330\250\331\212\331\206-\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..2978551 --- /dev/null +++ "b/text/0000-\330\252\331\203\330\247\331\201\330\244-\330\252\330\271\330\257\331\212\331\204-\330\271\331\206\330\265\330\261-\330\271\330\247\331\205\331\221-\330\250\331\212\331\206-\330\247\331\204\331\205\330\255\330\261\331\221\331\203\331\212\331\206.md" @@ -0,0 +1,137 @@ +
+ +- **عنوان المقترح:** تكافؤ تعديل عنصر واجهة عامّ (المعدّل الانسيابيّ) بين المفسّر والمترجم +- **النطاق:** لغة `text/` (سلوك استنتاج النوع في المترجم) +- **تاريخ البدء:** 2026-07-02 +- **رقم الـ RFC:** (يُترك فارغاً حتى الدمج — يصبح رقم الـ PR) +- **الحالة:** مقترَح (PR مفتوح) +- **Issue التتبُّع:** (يُترك فارغاً حتى القبول) + +# ملخّص + +يغلق هذا المقترح فجوة تكافؤ ثالثة بين محرّكَي لغة ص في نظام الرسومات: تطبيق +**معدّل انسيابيّ** (مثل `.محتوى` أو `.لون`) على **متغيّر عنصرِ واجهةٍ عامّ** +(global) من داخل دالّة. المفسّر يشغّله بنجاح (نوع وقت التشغيل)، بينما المترجم +(`sad-build`) كان يُنتج `lld-link: error: undefined symbol: .محتوى` لأنّه لا +يتتبّع أنّ المتغيّر العامّ من نوع مقبض عنصر عبر حدود الدوال. النتيجة المرئيّة: +تطبيق تفاعليّ يعدّل عنصر عرضٍ عامًّا من معالِج حدث (آلة حاسبة تحدّث شاشتها) يعمل +الآن **بالكامل في المحرّكين معًا** بمخرَجٍ متطابق بايتيًّا. + +# الدافع (Motivation) + +النمط الأساسيّ للتطبيقات التفاعليّة في SadUI هو: عنصر عرضٍ **عامّ** تعدّله +معالِجات الأحداث في مكانه ثم `تحديث_حالة()`. هذا النمط يعمل في المفسّر لكنّه كان +**محجوبًا في المترجم**: مصانع العناصر (`نص_عنصر`، `زر`، …) تُرجع «كائن» ⇒ مقبض +عنصر (Pointer)، لكن استنتاج النوع الساكن للمتغيّرات العامّة في المترجم +(`TemplateBuilder::inferExprType`) كان يُرجع `Integer` افتراضيًّا لأيّ نداء دالّة +غير مسجَّل في جدول دوال المستخدم — فلا يمرّ المُستقبِل عبر بوّابة المعدّل الانسيابيّ +(`call_method_dispatch.cpp`) التي تشترط أن يكون المُستقبِل من نوع Pointer، فيُعامَل +`عرض.محتوى(...)` نداءً لدالّةٍ اسمها `.محتوى` غير موجودة ⇒ رمز غير معرَّف عند الربط. + +الفرق الدقيق: التسلسل المباشر `نص_عنصر("0").حجم(44)` (inline) كان يعمل في المترجم +لأنّ المُستقبِل طازجٌ معروف؛ بينما `عرض.محتوى(...)` حيث `عرض` **متغيّر عامّ مخزَّن** +يفشل. أي أنّ الفجوة كانت في تتبّع النوع عبر التخزين وحدود الدوال، لا في الرسم. + +هذا يكسر وعد «اكتب مرّة، اعمل في المحرّكين» للتطبيقات التفاعليّة الحقيقيّة، لا +للعروض الساكنة فقط. + +# الشرح التوجيهي (Guide-level explanation) + +يُكتب عنصر العرض متغيّرًا عامًّا، وتعدّله الدوال في مكانه بمعدّل انسيابيّ: + +```sad +استورد رسومات + +متغير الشاشة = "0" +# عنصر عرض عامّ — مرجع نعدّله في مكانه +متغير عرض_الشاشة = نص_عنصر("0").حجم(44).لون("أبيض") + +دالة اعرض() + عرض_الشاشة.محتوى(الشاشة) # كان يفشل في المترجم (رمز غير معرَّف) — يعمل الآن + تحديث_حالة() +نهاية + +دالة أدخل_رقم(ر) + الشاشة = نص(ر) + اعرض() +نهاية +``` + +بعد هذا المقترح، يسلك `عرض_الشاشة.محتوى(الشاشة)` سلوكًا متطابقًا في `sad-run` +و`sad-build`: يعدّل خاصّيّة المحتوى في مكانها ويعيد رسم الشجرة. لا صياغة جديدة ولا +مفاهيم جديدة — فقط إغلاق تباعدٍ صامت كان يجبر مطوّري المترجم على واجهات ساكنة. + +# الشرح المرجعي (Reference-level explanation) + +- **مصدر الحقيقة (`language-truth/`):** لا توسيع. الإصلاح يشتقّ نوع الإرجاع من + الحقل `returns` القائم في `language-truth/builtins/ui_widgets.yaml` (يظهر في + `BuiltinMeta::returnType` = «كائن» لمصانع UIWidgets الـ42)، لا من قائمة أسماء + مثبّتة في الأداة. التزامٌ بمبدأ «الأدوات لا توسّع SoT اللغة». +- **المحلل المعجمي/النحوي:** لا تغيير. +- **الشجرة المجردة (AST):** لا عقد جديدة. +- **المفسّر:** لا تغيير (مصدر سلوك التكافؤ المرجعيّ). +- **المترجم (`sad-build`):** ثلاثة تعديلات في استنتاج النوع الساكن + (`TemplateBuilder::inferExprType`): + 1. **مصانع العناصر ⇒ Pointer:** داخل حالة `CallExpr`، إن كانت الدالّة مُدمَجة + (`Sad::Builtins::findBuiltinMeta`) ونوع إرجاعها من السجلّ = «كائن» ⇒ يُرجع + `Pointer`. هذا يجعل المتغيّر العامّ المخزَّن نتيجةَ مصنعِ عنصرٍ متتبَّعًا + كمقبض عنصر عبر حدود الدوال. + 2. **المعدّل الانسيابيّ ⇒ Pointer:** حالة `MethodCallExpr` جديدة: إن كان نوع + الكائن المُستقبِل `Pointer` ⇒ يُرجع `Pointer` (لأنّ المعدّل يُرجع العنصر نفسه + للتسلسل، فيبقى `نص_عنصر(..).حجم(..)` مقبضًا). + 3. **مساعد مركزيّ:** `builtinReturnsToSIRKind(returnType)` رُقّي إلى دالّة عضو + في `TemplateBuilder`، فيعتمد عليه مساراً الاستنتاج (نوع إرجاع الجسم + نوع + التعبير) على **الحقل نفسه** `returnType` بدل حقلين مختلفين. +- **نظام الأخطاء:** لا رموز جديدة. على العكس، يزيل رسالة ربطٍ مضلِّلة + (`undefined symbol`) كانت تظهر لبرنامج `.ص` سليم. +- **الأدوات (LSP/المنسّق):** لا أثر. +- **التوافق الخلفي:** لا يكسر شيئًا. يوسّع مجموعة البرامج التي تُترجَم بنجاح فقط + (برامج كانت تفشل صارت تعمل). لا برنامج كان يعتمد على الفشل. + +## التحقّق + +- بناء `sad-build` (Release) ناجح. +- آلة حاسبة تفاعليّة كاملة (`آلة_حاسبة.ص`): منطق `7+3=10.0` وشجرة العرض متطابقان + بايتيًّا بين المحرّكين. +- انحدار: 20/20 من اختبارات تغطية الواجهة (`ui_cov_*.ص`) تكافؤ مترجم↔مفسّر تامّ. +- `x.py gen --check`: المصدر المولَّد متزامن مع مصدر الحقيقة (لا انجراف). + +# السلبيات (Drawbacks) + +- يوسّع مسؤوليّة استنتاج النوع الساكن في المترجم قليلًا (حالة `MethodCallExpr` + جديدة). الكلفة هامشيّة والمنطق محصور. +- المطابقة تبقى نصّيّة على «كائن» لأنّ مصدر الحقيقة نصّيّ (YAML)، لكنّها الآن + ممركزة وموثَّقة في مساعد واحد بدل نثرها. + +# المبرّرات والبدائل (Rationale and alternatives) + +- **لماذا هذا التصميم:** يشتقّ النوع من مصدر الحقيقة (سجلّ المدمجات) لا من قائمة + أسماء مثبّتة، فيبقى متّسقًا تلقائيًّا مع أيّ توسّع مستقبليّ لكتالوج العناصر. +- **بديل مرفوض:** دعم بانِي الجذر في `تشغيل_تطبيق` للمترجم (إعادة بناء الشجرة كلّ + إطار) نظير [نموذج البانِي في التنقّل]. أثقل، ويغيّر نموذج البرمجة، ولا يلزم لحلّ + نمط «التعديل في المكان» الشائع. +- **بديل مرفوض:** تثبيت قائمة أسماء المصانع في المترجم. يكرّر مصدر الحقيقة ويخالف + مبدأ عدم توسيع/تكرار SoT في الأدوات. +- **أثر عدم الفعل:** يبقى التطبيق التفاعليّ الحقيقيّ محجوبًا في المترجم، والوعد + الأساسيّ منقوصًا. + +# أعمال سابقة (Prior art) + +استنتاج النوع الساكن لمقابض الكائنات المعتمة (opaque handles) عبر جدول رموز مطبوع +ممارسةٌ قياسيّة في مترجمات اللغات ذات مصدر حقيقة للأنواع (مثل اشتقاق أنواع الإرجاع +في Rust/Dart من توقيعات الدوال بدل تخمينها). الجديد هنا خصوصيّة لغة ص: مصدر الحقيقة +عربيّ الأسماء (`returns: كائن`) والمترجم يشتقّ منه لا من قائمة يدويّة. + +# أسئلة غير محسومة (Unresolved questions) + +- خارج النطاق: تتبّع النوع للوسائط (parameters) التي تستقبل عناصر — هذا المقترح + يعالج المتغيّرات العامّة والمعدّلات المتسلسلة؛ تتبّع نوع الوسيط شريحة لاحقة. +- خارج النطاق: بانِي الجذر في `تشغيل_تطبيق` للمترجم (بديل نموذجيّ مؤجَّل). + +# إمكانات مستقبلية (Future possibilities) + +- تعميم اشتقاق `returns` من مصدر الحقيقة لكلّ أنواع الإرجاع (عدد/نص/…) لا «كائن» + فقط، بحيث يستنتج المترجم أنواع كلّ المدمجات ساكنًا من SoT. +- مخطَّط SoT يفرض أسماء الأنواع رسميًّا، فتزول المطابقة النصّيّة كلّيًّا. + +