From 7527ae24bf6685826c34b3c284067742850dc901 Mon Sep 17 00:00:00 2001 From: Sad Lang Dev Date: Fri, 3 Jul 2026 07:10:28 +0300 Subject: [PATCH 1/4] =?UTF-8?q?docs(frontend):=20=D8=AF=D8=B1=D8=A7=D8=B3?= =?UTF-8?q?=D8=A9=20=D8=AD=D8=A7=D9=84=D8=A9=20=D8=AA=D9=86=D9=81=D9=8A?= =?UTF-8?q?=D8=B0=20=D8=A7=D9=84=D8=A7=D8=B3=D8=AA=D9=8A=D8=B9=D8=A7=D8=A8?= =?UTF-8?q?=D8=A7=D8=AA=20(=D8=A3=D9=86=D8=AA=D8=AC=20=E2=86=92=20SIR)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit صفحة frontend/comprehensions.md تتتبّع تنفيذ استيعابات القوائم/المجموعات/ القواميس عبر خطّ الأنابيب: الكشف المبكّر عبر «لكل» وتمييز قاموس/مجموعة بـ«:» في parseArrayLiteral/parseMapLiteral، عقد AST الثابتة، وتوليد SIR (أوكواد ARRAY_* للقائمة، __sad_map_* للقاموس، ومسح إزالة تكرار على قيمة الناتج للمجموعة مع تخصيص في كتلة الدخول). توثّق الحدّ العدديّ وفخّ buildExprGenerator وطبقتَي الاختبار. مُراجَعة Amelia (دقّة كلّ ادّعاء مقابل المصدر) مطبَّقة. يُدمَج بتنسيق مع دمج م1 إلى dev (روابط blob/dev تكتمل بعد الدمج). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/SUMMARY.md | 1 + src/frontend/comprehensions.md | 114 +++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 src/frontend/comprehensions.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index bf66aa0..4f764f2 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -29,6 +29,7 @@ - [المحلل المعجمي (Lexer)](frontend/lexer.md) - [المحلل النحوي (Parser)](frontend/parser.md) - [شجرة AST](frontend/ast.md) +- [دراسة حالة: الاستيعابات (أنتج → SIR)](frontend/comprehensions.md) # الجزء الخامس · الواجهة الخلفيّة (Backend) diff --git a/src/frontend/comprehensions.md b/src/frontend/comprehensions.md new file mode 100644 index 0000000..690f955 --- /dev/null +++ b/src/frontend/comprehensions.md @@ -0,0 +1,114 @@ +# دراسة حالة: الاستيعابات (من `أنتج` إلى SIR) + +مثالٌ متكامل على تمرير ميزة لغويّة عبر خطّ الأنابيب: كيف تُحلَّل الاستيعابات (قوائم/ +مجموعات/قواميس) بترتيب `أنتج` العربيّ، وتُبنى في AST، وتُنفَّذ في المحرّكين. المرجع +اللغويّ للمستخدم في [sadlang-docs](https://github.com/sadlang/sadlang-docs)؛ هذه +الصفحة للمساهم في **التنفيذ**. + +الصيغة: `[لكل <متغيّر> في <مصدر> [إذا <شرط>] أنتج <ناتج>]` (والمعقوفة `{}` للمجموعة/ +القاموس). أُقرّت في RFC 25 (م1ب). + +> **المبدأ الأهمّ:** التغيير في **المحلّل فقط**. عقد AST لم تتغيّر (نفس الحقول)، فلم +> يُمَسّ المفسّر ولا المترجم في *بناء العقدة* — فقط **ترتيب القراءة** انقلب. هذا يقلّل +> سطح التغيير جذريًّا ويحافظ على تكافؤ المحرّكين. + +--- + +## 1) المحلّل: كشف مبكّر + تمييز + +الاستيعاب يُكتشَف **مبكّرًا** عبر `لكل` (KEYWORD_FOR) في أوّل المحتوى، قبل تحليل أيّ +تعبير — فلا لبس مع مصفوفة/خريطة عاديّة: + +- القائمة: + [`ParserCore::parseArrayLiteral`](https://github.com/sadlang/s-programming-language/blob/dev/shared/parser/src/statements/parser_advanced.cpp) + — إن كان أوّل رمز `لكل`: `في` → مصدر → `[إذا شرط]` → `أنتج` → ناتج → `]`. +- المجموعة/القاموس: + [`ParserCore::parseMapLiteral`](https://github.com/sadlang/s-programming-language/blob/dev/shared/parser/src/statements/parser_advanced.cpp) + — بعد `أنتج` يُحلَّل الناتج الأوّل بـ`parseTernary` (لتجنّب التهام `:`)، ثمّ: + **وجود `:` (أو `=`) ⇒ قاموس** (نُحلّل القيمة)، **غيابها ⇒ مجموعة**. + +`أنتج` = `KEYWORD_YIELD` **السياقيّة الموجودة أصلًا** (تُستعمَل أيضًا للتوليد)، فلا +تعديل على [`keywords.yaml`](https://github.com/sadlang/s-programming-language/blob/dev/language-truth/keywords.yaml). +شرط القبول: `match(KEYWORD_YIELD) || matchContextual(KEYWORD_YIELD)` (في الكود حارسٌ +منفيّ: `if (!match(...) && !matchContextual(...)) error`). + +> **فخّ:** الترتيب البايثونيّ القديم (`[تعبير لكل …]`) لم يعد يُبنى كاستيعاب — يُحلَّل +> كمصفوفة عاديّة ثمّ يتعثّر عند `لكل`. حُذفت دالّتا `parseListComprehension`/ +> `parseDictComprehension` القديمتان من **مسار المحلّل الحيّ** (`parser_helpers.cpp`). +> (تبقى نسخة بالترتيب القديم في `shared/parser/src/specs/flow/parser_comprehension.cpp` +> لكنّها نموذج ميت **غير مُترجَم** — لا إحالة إليه في CMake؛ يُنظَّف في طور لاحق.) + +--- + +## 2) عقد AST (لم تتغيّر) + +في [`shared/ast/include/expressions.h`](https://github.com/sadlang/s-programming-language/blob/dev/shared/ast/include/expressions.h) +(لا `comprehension_nodes.h` الميت): + +| العقدة | الحقول | +|---|---| +| `ListComprehensionExpr` | `element`، `variable`، `iterable`، `condition` | +| `SetComprehensionExpr` | `expression`، `variable`، `iterable`، `condition` | +| `DictComprehensionExpr` | `key`، `value`، `variable`، `iterable`، `condition` | + +القاموس بمتغيّر حلقة **مفرد** (أُسقطت الصيغة الثنائيّة `م، ق` القديمة — كانت في دالّة +ميتة بلا مستهلك). + +--- + +## 3) الواجهة الخلفيّة: التوليد في SIR + +بانيات الاستيعاب في `compiler/src/frontend/builders/`: + +- **القائمة والقاموس** — + [`expression_comprehensions.cpp`](https://github.com/sadlang/s-programming-language/blob/dev/compiler/src/frontend/builders/expression_comprehensions.cpp): + `buildExprListComp` يستعمل أوكواد المصفوفة المُلوَّنة في الخلفيّة + (`ARRAY_NEW`/`ARRAY_LEN`/`ARRAY_GET`/`ARRAY_APPEND`)، و`buildExprDictComp` يستعمل + `__sad_map_create` + `__sad_map_set_typed` (نفس مسار الخريطة الحرفيّة). هذا هو + الإصلاح التاريخيّ لـISSUE-016/017 (بدل نداءات رموز وقت تشغيل غير معرَّفة). +- **المجموعة** — + [`expression_comp2.cpp`](https://github.com/sadlang/s-programming-language/blob/dev/compiler/src/frontend/builders/expression_comp2.cpp): + `buildExprSetComp`. المجموعة = **مصفوفة بعناصر فريدة** (كالمفسّر). يستعمل نفس أوكواد + المصفوفة **زائد حلقة مسح داخليّة لإزالة التكرار**: يبني قيمة الناتج، يمسح مصفوفة + النتيجة، ويضيف عبر `ARRAY_APPEND` **فقط إن غابت القيمة**. إزالة التكرار على **قيمة + الناتج** (لا متغيّر الحلقة) — مطابقةً للمفسّر. + +> **لماذا بانٍ منفصل للمجموعة؟** إزالة التكرار تُدخِل حلقة مسح داخليّة متداخلة +> (كتل `scan_cond`/`scan_body`/`scan_found`/`scan_next`/`scan_done`/`append`) تضاعف +> حجم البانِي، فلا تتقاسم بنية List/Dict المستقيمة؛ ويشارك الملفّ `buildExprGenerator`. + +نقاط تنفيذ دقيقة في بانِي المجموعة: + +- علَم «موجود» وعدّاد المسح الداخليّ يُخصَّصان بـ`ALLOC` **مرّة في كتلة الدخول** (قبل + الحلقة الخارجيّة) — لا داخل الجسم — تفاديًا لتسريب مكدس (alloca متكرّر لكلّ عنصر). +- هيمنة SSA محفوظة: `elemExprResult` يُعرَّف في كتلة القيمة التي تُهيمِن على عنقود + المسح والإضافة؛ `curIdxReg` يُعرَّف في كتلة الشرط التي تُهيمِن على الجسم والزيادة. + +> **حدّ معروف:** مقارنة إزالة التكرار (`EQ`) **عدديّة** (كبقيّة بنية الاستيعابات +> عدديّة النوع)، فالمجموعات الصحيحة الإزالة للأعداد؛ مجموعات النصوص/العشريّ تتباعد +> صامتًا حتى يُعمَّم النوع في الاستيعابات الثلاثة. + +> **فخّ متبقٍّ:** `buildExprGenerator` في نفس الملفّ ما زال بالنهج المكسور (`CALL +> __sad_len`/`__sad_array_push` غير المعرَّفة) — سينهار الربط متى استُخدم مولِّد؛ خارج +> نطاق م1ب، يُتابَع بنفس نمط الإصلاح. + +--- + +## 4) الاختبار (طبقتان) + +- **سلوك (تكافؤ مزدوج)** — `tests/behavior/rules_matrix/60_advanced/gr.adv.{list,set, + dict}_comprehension/`، مولَّدة بـ`_generators/gen_comprehension_tests.py` (يحاكي + الدلالة في بايثون ⇒ `@expected` حتميّ). **حسّاس:** اختبارات المجموعة تستعمل خرائط + **غير حقنيّة** (`س % 3`) + probe قيمة بالفهرسة — وإلّا فخريطة حقنيّة تجعل الطول + مستقلًّا عن التحويل، فيمرّ محرّك يتجاهل `أنتج` أو يزيل التكرار على المصدر **زائفًا**. +- **وحدة (C++)** — [`tests/unit/parser/test_comprehensions_antaj.cpp`](https://github.com/sadlang/s-programming-language/blob/dev/tests/unit/parser/test_comprehensions_antaj.cpp) + (إطار `sad_test.h`): يتحقّق من عقد AST + تمييز قاموس/مجموعة + رفض الترتيب القديم + + بنية `BinaryExpr` للناتج. مُسجَّل في CTest كـ`ComprehensionAntajTests` (وسم `Unit`) + عبر [`cmake/tests.cmake`](https://github.com/sadlang/s-programming-language/blob/dev/cmake/tests.cmake). + +--- + +## انظر أيضًا + +- [المحلل النحوي (Parser)](parser.md) · [شجرة AST](ast.md) · [التمثيل الوسيط SIR](../backend/sir.md) +- [قواعد المحلل كمصدر موحّد](../sot/grammar-sot.md) — قواعد `gr.adv.*_comprehension` في `language-truth/grammar/`. From f3b4f55b9bcc13d019806710d19074ab65679f19 Mon Sep 17 00:00:00 2001 From: Sad Lang Dev Date: Fri, 3 Jul 2026 07:26:02 +0300 Subject: [PATCH 2/4] =?UTF-8?q?docs(frontend):=20=D8=B1=D8=B3=D9=88=D9=85?= =?UTF-8?q?=20mermaid=20=D8=BA=D9=86=D9=8A=D9=91=D8=A9=20=D9=84=D9=85?= =?UTF-8?q?=D8=B3=D8=A7=D8=B1=20=D9=83=D9=88=D8=AF=20=D8=A7=D9=84=D8=A7?= =?UTF-8?q?=D8=B3=D8=AA=D9=8A=D8=B9=D8=A7=D8=A8=D8=A7=D8=AA=20+=20=D8=B4?= =?UTF-8?q?=D8=B1=D8=AD=20=D9=85=D9=88=D8=B3=D9=8E=D9=91=D8=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - خطّ الأنابيب (flowchart): عقدة AST كمحور التكافؤ بين المفسّر والمترجم. - شجرة قرار المحلّل (flowchart TD): الكشف المبكّر بـ«لكل» بلا تراجُع، وتمييز قائمة/مجموعة/قاموس بنوع القوس ووجود «:». - CFG بانِي المجموعة في SIR: الحلقة الخارجيّة + مسح إزالة التكرار الداخليّ (sc_cond/body/val/scan_*/append/inc/exit)، تعقيد O(ن²)، تخصيص في كتلة الدخول. شرح موسَّع حول كلّ رسم. الرسوم الثلاثة مُتحقَّق من صياغتها بـmermaid-cli (رندرة SVG). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/frontend/comprehensions.md | 63 ++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/frontend/comprehensions.md b/src/frontend/comprehensions.md index 690f955..c3ca1ec 100644 --- a/src/frontend/comprehensions.md +++ b/src/frontend/comprehensions.md @@ -12,6 +12,23 @@ > يُمَسّ المفسّر ولا المترجم في *بناء العقدة* — فقط **ترتيب القراءة** انقلب. هذا يقلّل > سطح التغيير جذريًّا ويحافظ على تكافؤ المحرّكين. +## خطّ الأنابيب: عقدة AST هي المحور + +عقدة الاستيعاب هي **نقطة الالتقاء** بين المحرّكين: المحلّل يبنيها مرّة، ثمّ يستهلكها +المفسّر (تقييم مباشر) والمترجم (توليد SIR) كلٌّ على حدة. ولأنّ التغيير لم يمسّ العقدة، +بقي الطرفان متكافئين تلقائيًّا — وهذا ما تفرضه اختبارات التكافؤ المزدوج. + +```mermaid +flowchart LR + SRC["شيفرة ص
لكل س في مصدر أنتج ناتج"] --> LEX["المحلّل المعجميّ
رموز: KEYWORD_FOR، KEYWORD_YIELD…"] + LEX --> PAR["المحلّل النحويّ
parseArrayLiteral / parseMapLiteral"] + PAR --> AST["عقدة AST المحوريّة
List / Set / DictComprehensionExpr"] + AST --> INT["المفسّر الشجريّ
تقييم مباشر"] + AST --> SIR["المترجم → SIR
أوكواد ARRAY_* + مسح إزالة تكرار"] + SIR --> LLVM["LLVM → ملفّ تنفيذيّ"] + INT -.->|"تكافؤ مزدوج مضمون"| LLVM +``` + --- ## 1) المحلّل: كشف مبكّر + تمييز @@ -32,6 +49,23 @@ شرط القبول: `match(KEYWORD_YIELD) || matchContextual(KEYWORD_YIELD)` (في الكود حارسٌ منفيّ: `if (!match(...) && !matchContextual(...)) error`). +الفائدة من الكشف المبكّر: **نظرة أمام برمز واحد** (`لكل` أوّلًا) تحسم أنّ ما بين +الأقواس استيعابٌ لا مصفوفة/خريطة — **بلا تراجُع** (backtracking) ولا تحليل تخمينيّ. +والتمييز بين قائمة ومجموعة وقاموس يتأخّر إلى نقطتين حاسمتين فقط: نوع القوس، ووجود +`:` بعد الناتج. + +```mermaid +flowchart TD + START["بعد فتح قوس مربّع أو معقوف"] --> Q1{"أوّل رمز = لكل؟"} + Q1 -.->|"لا"| PLAIN["مصفوفة / خريطة عاديّة
(المسار الافتراضيّ)"] + Q1 -->|"نعم"| HEAD["رأس الحلقة:
متغيّر → في → مصدر
→ (إذا شرط: اختياريّ)
→ أنتج → ناتج"] + HEAD --> Q2{"نوع القوس؟"} + Q2 -->|"قوس مربّع (قائمة)"| LIST["ListComprehensionExpr"] + Q2 -->|"قوس معقوف"| Q3{"بعد الناتج ':' أو '='؟"} + Q3 -->|"نعم"| DICT["DictComprehensionExpr
مفتاح : قيمة"] + Q3 -.->|"لا"| SET["SetComprehensionExpr
ناتج مفرد"] +``` + > **فخّ:** الترتيب البايثونيّ القديم (`[تعبير لكل …]`) لم يعد يُبنى كاستيعاب — يُحلَّل > كمصفوفة عاديّة ثمّ يتعثّر عند `لكل`. حُذفت دالّتا `parseListComprehension`/ > `parseDictComprehension` القديمتان من **مسار المحلّل الحيّ** (`parser_helpers.cpp`). @@ -84,6 +118,35 @@ - هيمنة SSA محفوظة: `elemExprResult` يُعرَّف في كتلة القيمة التي تُهيمِن على عنقود المسح والإضافة؛ `curIdxReg` يُعرَّف في كتلة الشرط التي تُهيمِن على الجسم والزيادة. +### الرسم البيانيّ للتحكّم (CFG) لبانِي المجموعة + +حلقتان متداخلتان: **خارجيّة** تمرّ على المصدر (`sc_cond` → `sc_body` → … → `sc_inc`)، +و**داخليّة** تمسح مصفوفة النتيجة لكلّ عنصر (`sc_scan_*`) وتضيف عبر `ARRAY_APPEND` +فقط إن غابت القيمة. التعقيد O(ن²) في أسوأ حالة (مقبول لأحجام الاستيعاب المعتادة، ومطابق +لدلالة «أضِف-إن-غاب» في المفسّر). العلَم `found` والعدّاد `jdx` يُخصَّصان في `entry` +(لا في الحلقة) فلا تسريب مكدس: + +```mermaid +flowchart TD + ENTRY["entry
ARRAY_NEW النتيجة
ALLOC idx، found، jdx"] --> COND{"sc_cond
idx أصغر من طول المصدر؟"} + COND -.->|"لا"| EXIT["sc_exit
return النتيجة (Array)"] + COND -->|"نعم"| BODY["sc_body
elem = ARRAY_GET المصدر عند idx
ربط متغيّر الحلقة"] + BODY --> CIF{"شرط إذا؟"} + CIF -.->|"خطأ"| INC + CIF -->|"صحيح / لا شرط"| VAL["sc_val
elemExpr = بناء الناتج
found = 0، jdx = 0"] + VAL --> SCOND{"sc_scan_cond
jdx أصغر من طول النتيجة؟"} + SCOND -->|"نعم"| SBODY{"sc_scan_body
عنصر النتيجة عند jdx == elemExpr؟"} + SCOND -.->|"لا"| SDONE{"sc_scan_done
found == 0؟"} + SBODY -->|"تساوٍ"| FOUND["sc_scan_found
found = 1"] + SBODY -.->|"اختلاف"| SNEXT["sc_scan_next
jdx = jdx + 1"] + FOUND --> SDONE + SNEXT --> SCOND + SDONE -->|"غاب (found=0)"| APP["sc_append
ARRAY_APPEND النتيجة، elemExpr"] + SDONE -.->|"موجود"| INC["sc_inc
idx = idx + 1"] + APP --> INC + INC --> COND +``` + > **حدّ معروف:** مقارنة إزالة التكرار (`EQ`) **عدديّة** (كبقيّة بنية الاستيعابات > عدديّة النوع)، فالمجموعات الصحيحة الإزالة للأعداد؛ مجموعات النصوص/العشريّ تتباعد > صامتًا حتى يُعمَّم النوع في الاستيعابات الثلاثة. From cff9b38925bea1b4906333a675e0cb77a9b4af41 Mon Sep 17 00:00:00 2001 From: Sad Lang Dev Date: Fri, 3 Jul 2026 07:47:32 +0300 Subject: [PATCH 3/4] =?UTF-8?q?fix(ci):=20=D8=AA=D8=B3=D8=AC=D9=8A=D9=84?= =?UTF-8?q?=20=D9=81=D8=B5=D9=84=20=D8=A7=D9=84=D8=A7=D8=B3=D8=AA=D9=8A?= =?UTF-8?q?=D8=B9=D8=A7=D8=A8=D8=A7=D8=AA=20=D9=81=D9=8A=20sources.yaml=20?= =?UTF-8?q?+=20=D8=A5=D8=B5=D9=84=D8=A7=D8=AD=20=D8=AC=D8=B0=D8=B1=20lyche?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - sync-guard: سُجِّل src/frontend/comprehensions.md في sync/sources.yaml بمصادره (parser_advanced/expressions.h/بانيَي الاستيعاب/grammar) — كان الفصل غير مسجَّل فيفشل حارس سلامة البيان (check_sync --validate). - check (lychee): أُضيف --root-dir لحلّ رابط الجذر «/» في 404.html المولَّد من mdBook — خللٌ سابق في CI كشفه أوّل PR يمرّ عبر فحص الروابط (لا PR مدموج قبله؛ الفصول السابقة دُفعت مباشرةً لـmain متجاوزةً PR-CI). Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/ci.yml | 6 +++++- sync/sources.yaml | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c5b012..75ffb2a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,7 +37,11 @@ jobs: - name: فحص الروابط الداخليّة (lychee على الإخراج المبنيّ) uses: lycheeverse/lychee-action@v2 with: - args: --offline --no-progress "book/**/*.html" + # (AR) --root-dir يحلّ روابط الجذر «/» المحلّيّة (يولّدها قالب 404.html في mdBook) + # إلى جذر الكتاب المبنيّ، وإلّا فشل lychee دون اتّصال («Cannot convert path '/'»). + # (EN) --root-dir resolves local root links "/" (emitted by mdBook's 404.html) to the + # built book root; otherwise offline lychee errors with "Cannot convert path '/'". + args: --offline --no-progress --root-dir "${{ github.workspace }}/book" "book/**/*.html" fail: true # حُرّاس نظام المزامنة: سلامة البيان + منع «الكتم الصامت» للقفل diff --git a/sync/sources.yaml b/sync/sources.yaml index f940a54..80ede48 100644 --- a/sync/sources.yaml +++ b/sync/sources.yaml @@ -31,6 +31,14 @@ chapters: sources: - shared/ast/include/ast_visitor.h + - file: src/frontend/comprehensions.md + sources: + - shared/parser/src/statements/parser_advanced.cpp # parseArrayLiteral / parseMapLiteral + - shared/ast/include/expressions.h # List/Set/DictComprehensionExpr + - compiler/src/frontend/builders/expression_comprehensions.cpp # بانِي القائمة/القاموس + - compiler/src/frontend/builders/expression_comp2.cpp # بانِي المجموعة (مسح إزالة التكرار) + - language-truth/grammar + - file: src/backend/interpreter.md sources: - interpreter/include/core/interpreter_core.h From dc8d93553d80cb7fa03614b6db05295c2364f54a Mon Sep 17 00:00:00 2001 From: Sad Lang Dev Date: Fri, 3 Jul 2026 20:37:39 +0300 Subject: [PATCH 4/4] =?UTF-8?q?docs(frontend):=20=D8=AA=D9=88=D8=AB=D9=8A?= =?UTF-8?q?=D9=82=20=D8=AA=D9=86=D9=81=D9=8A=D8=B0=20=D9=81=D9=83=D9=91=20?= =?UTF-8?q?=D8=A7=D9=84=D8=B2=D9=88=D8=AC=20=D9=88=D8=A7=D9=84=D8=AA=D9=83?= =?UTF-8?q?=D8=B1=D8=A7=D8=B1=20=D8=B9=D9=84=D9=89=20=D8=A7=D9=84=D8=AE?= =?UTF-8?q?=D8=B1=D8=A7=D8=A6=D8=B7=20=D9=81=D9=8A=20=D8=A7=D9=84=D8=A7?= =?UTF-8?q?=D8=B3=D8=AA=D9=8A=D8=B9=D8=A7=D8=A8=D8=A7=D8=AA=20(RFC=2025=20?= =?UTF-8?q?=D8=A7=D9=84=D8=AA=D8=B9=D8=A7=D8=B1=D8=B6=201=D8=A3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit يوسّع دراسة حالة الاستيعابات بقسم تنفيذيّ (أ/ب/ج/د): أساس تكرار الخريطة في المترجم، الطبقات الخمس، المساعِد المشترك lowerMapComprehensionIterable، وإغلاق الإخراج النصّيّ؛ مع مخطّط mermaid لتدفّق تهيئة الخريطة + تحديث جدول عقد AST (valueVariable) والاختبار. + توسيع مصادر sync/sources.yaml (المفسّر، تكرار الخريطة، الطبع الموسوم). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/frontend/comprehensions.md | 98 ++++++++++++++++++++++++++++++++-- sync/sources.yaml | 12 +++-- 2 files changed, 102 insertions(+), 8 deletions(-) diff --git a/src/frontend/comprehensions.md b/src/frontend/comprehensions.md index c3ca1ec..b773214 100644 --- a/src/frontend/comprehensions.md +++ b/src/frontend/comprehensions.md @@ -81,12 +81,13 @@ flowchart TD | العقدة | الحقول | |---|---| -| `ListComprehensionExpr` | `element`، `variable`، `iterable`، `condition` | -| `SetComprehensionExpr` | `expression`، `variable`، `iterable`، `condition` | -| `DictComprehensionExpr` | `key`، `value`، `variable`، `iterable`، `condition` | +| `ListComprehensionExpr` | `element`، `variable`، `valueVariable`، `iterable`، `condition` | +| `SetComprehensionExpr` | `expression`، `variable`، `valueVariable`، `iterable`، `condition` | +| `DictComprehensionExpr` | `key`، `value`، `variable`، `valueVariable`، `iterable`، `condition` | -القاموس بمتغيّر حلقة **مفرد** (أُسقطت الصيغة الثنائيّة `م، ق` القديمة — كانت في دالّة -ميتة بلا مستهلك). +الحقل `valueVariable` (افتراضيّ فارغ) أُضيف لدعم **فكّ الزوج** على الخرائط +(`لكل مفتاح، قيمة في خريطة`) — انظر قسم **«فكّ الزوج والتكرار على الخرائط»** أدناه. +يبقى فارغًا في الصيغة المفردة، فلا يتأثّر أيّ مستهلك قائم. --- @@ -157,6 +158,87 @@ flowchart TD --- +## فكّ الزوج والتكرار على الخرائط (RFC 25 التعارض 1أ) + +توسعة تجعل **مصدر الاستيعاب خريطةً** لا مصفوفةً، وتضيف صيغة فكّ الزوج +`[لكل مفتاح، قيمة في خريطة أنتج ناتج]`. تمرّ عبر الطبقات الخمس، وتبني على إصلاحٍ +تأسيسيّ لتكرار الخرائط في المترجم. + +### أ) الأساس: تكرار الخريطة في حلقة `لكل` بالمترجم + +قبل هذه التوسعة كان المترجم يعامل الخريطة في حلقة `لكل` **كأنّها مصفوفة**: يطبّق +`ARRAY_GET` على بنية الخريطة `{count, cap, keys*, values*, types*}` مباشرةً ⇒ قمامة +(مؤشّرات خام تُطبع أعدادًا)، بينما المفسّر صحيح. الإصلاح في +[`statement_for_range.cpp`](https://github.com/sadlang/s-programming-language/blob/dev/compiler/src/frontend/builders/statement_for_range.cpp): +عند `iterableResult.type == SadTypeKind::Map` نستبدل المصدر بمصفوفة مفاتيح الخريطة +عبر `__sad_map_keys` (تُرجع `SadArray {len, cap, data}` عبر `getOrCreateMapCollect` +في [`map_ops.cpp`](https://github.com/sadlang/s-programming-language/blob/dev/compiler/src/backend/llvm/builders/collections/map_ops.cpp))، +ونجلب القيم عبر `__sad_map_values` لمتغيّر القيمة إن وُجد. اسما الدالّتين ثابتان +موحَّدان في [`sir_constants.h`](https://github.com/sadlang/s-programming-language/blob/dev/compiler/include/frontend/sir_constants.h) +(`kRuntimeMapKeys`/`kRuntimeMapValues`) يتقاسمهما مسار الحلقة وبانِي الاستيعاب. + +### ب) الطبقات الخمس + +| الطبقة | التغيير | +|---|---| +| **AST** | حقل `valueVariable` (افتراضيّ فارغ) في العقد الثلاث | +| **المحلّل** | بعد المتغيّر الأوّل، `matchComma()` اختياريّ ⇒ متغيّر قيمة ثانٍ (نفس نمط حلقة `لكل` في `parseForStmt`) في `parseArrayLiteral` و`parseMapLiteral` | +| **المفسّر** | الزائرات الثلاث تقبل `isMap()`؛ تمرّ على `toMapRef()` وتربط `variable`=المفتاح و`valueVariable`=القيمة | +| **المترجم** | مساعِد مشترك `lowerMapComprehensionIterable` يستدعيه البانون الثلاثة | +| **SoT** | القواعد الثلاث في [`60_advanced.yaml`](https://github.com/sadlang/s-programming-language/blob/dev/language-truth/grammar/60_advanced.yaml) تضيف `[ '،' Identifier ]` (نفس نمط حلقة `لكل`، قاعدة `gr.stmt.for`) | + +### ج) المساعِد المشترك في المترجم + +بدل تكرار منطق الخريطة في البانين الثلاثة، يجمعه +`ExpressionBuilder::lowerMapComprehensionIterable` +([`expression_comprehensions.cpp`](https://github.com/sadlang/s-programming-language/blob/dev/compiler/src/frontend/builders/expression_comprehensions.cpp)): +إن كان المصدر خريطةً استبدله بمصفوفة مفاتيحها ويُصدِر مصفوفة قيمها، ويحسم نوعَي +المفتاح والقيمة. ثمّ يربط كلّ بانٍ متغيّر القيمة بتسجيل SSA (`registerName = valElemReg`) +مُهيمَن عليه من كتلة الجسم. + +**تصنيف النوع دقيق** (يطابق تمثيل التخزين الفعليّ في `buildExprMap`): + +- **المفتاح دائمًا `String`**: الخريطة تُخزّن المفاتيح بـ`strdup` وتحوّل المفاتيح + العدديّة إلى نصّ (ISSUE-044). +- **القيمة** تُشتقّ من `elementType` الذي يعقّبه بانِي الخريطة الحرفيّة (يُلتقَط **قبل** + دهسه): `Integer`/`Boolean` ⇒ نفسها؛ `String`/`Float` ⇒ `String` (العشريّ يُخزَّن + نصًّا داخليًّا)؛ مختلط (`Void`) ⇒ `Integer`. + +```mermaid +flowchart TD + ITER["buildExpression(المصدر)
iterResult"] --> Q{"iterResult.type == Map؟"} + Q -.->|"لا (مصفوفة)"| ARR["نوع العنصر = iterResult.elementType
لا مصفوفة قيم"] + Q -->|"نعم"| CAP["التقاط mapValueType = elementType
(قبل الدهس)"] + CAP --> KEYS["CALL __sad_map_keys ⇒ keysReg"] + KEYS --> VQ{"valueVar غير فارغ؟"} + VQ -.->|"لا"| DONE["استبدال المصدر بمصفوفة المفاتيح
elementType := String"] + VQ -->|"نعم"| VALS["CALL __sad_map_values ⇒ valuesReg
حسم valueVarType"] + VALS --> DONE + DONE --> BODY["في الجسم: ARRAY_GET المفتاح + (القيمة إن وُجدت)
تسجيل SSA لكلٍّ"] +``` + +### د) إغلاق قيد الإخراج النصّيّ + +المفاتيح نصّيّة، فطبعها كان يكشف قيدًا **كونيًّا** (يمسّ حتّى `اطبع(["أ","ب"])`): نتيجة +الاستيعاب كانت `elementType = Void` فالوصول المفهرَس يطبع مؤشّرًا؛ ومساعِد الطبع +`__sad_array_to_string` غير موسوم فيطبع كلّ عنصر بـ`%lld`. الإصلاح شقّان: + +1. **تمرير نوع العنصر**: البانون يمرّرون `elemExprResult.type` إلى `elementType` + لنتيجة القائمة/المجموعة ⇒ الوصول المفهرَس النصّيّ يعمل (كالمصفوفة الحرفيّة). +2. **طبع كامل موسوم**: أُضيف `elementType` إلى `SIROperand`، يمرّره بانِي الطبع + ([`builtins_core.cpp`](https://github.com/sadlang/s-programming-language/blob/dev/compiler/src/frontend/builders/builtins_core.cpp))؛ + وفي الخلفيّة + ([`io_builtins_ops.cpp`](https://github.com/sadlang/s-programming-language/blob/dev/compiler/src/backend/llvm/builders/builtins/io_builtins_ops.cpp)) + يوزَّع على مساعِد نصّيّ `__sad_array_to_string_str` (تمريرتان: `strlen` للحجم ثمّ + `sprintf("%s")`، يخصّص مخزنه) عند `elementType == String`. غير النصّيّة تبقى على + المسار العدديّ الأصليّ — توافق تامّ. + +> **ترتيب المدخلات غير محدَّد.** المفسّر يستعمل `std::unordered_map` والمترجم ترتيب +> الخانات؛ فترتيب المرور غير مضمون (كحلقة `لكل` على الخرائط). اختبارات التكافؤ تستعمل +> خرائط بمفتاح واحد أو تجميعًا لا-ترتيبيًّا لتفادي هشاشة المقارنة الحرفيّة. + +--- + ## 4) الاختبار (طبقتان) - **سلوك (تكافؤ مزدوج)** — `tests/behavior/rules_matrix/60_advanced/gr.adv.{list,set, @@ -169,6 +251,12 @@ flowchart TD بنية `BinaryExpr` للناتج. مُسجَّل في CTest كـ`ComprehensionAntajTests` (وسم `Unit`) عبر [`cmake/tests.cmake`](https://github.com/sadlang/s-programming-language/blob/dev/cmake/tests.cmake). +> **تغطية فكّ الزوج:** يضيف ملفّ الوحدة قسم `PairUnpack` (يتحقّق أنّ `valueVariable` +> يُملأ بالفاصلة ويبقى فارغًا بدونها، والحالة السلبيّة «فاصلة بلا اسم»)؛ وتضيف مجلّدات +> السلوك حالات فكّ زوج بإخراج **صحيح** أو **فهرسة** (لتفادي عدم تحديد الترتيب) — قائمة +> ومجموعة وقاموس. القِيَم النصّيّة تُختبَر عبر الفهرسة والطبع الكامل بعد إصلاح الإخراج +> النصّيّ (القسم د أعلاه). + --- ## انظر أيضًا diff --git a/sync/sources.yaml b/sync/sources.yaml index 80ede48..ab212de 100644 --- a/sync/sources.yaml +++ b/sync/sources.yaml @@ -33,10 +33,16 @@ chapters: - file: src/frontend/comprehensions.md sources: - - shared/parser/src/statements/parser_advanced.cpp # parseArrayLiteral / parseMapLiteral - - shared/ast/include/expressions.h # List/Set/DictComprehensionExpr - - compiler/src/frontend/builders/expression_comprehensions.cpp # بانِي القائمة/القاموس + - shared/parser/src/statements/parser_advanced.cpp # parseArrayLiteral / parseMapLiteral (+ matchComma فكّ الزوج) + - shared/ast/include/expressions.h # List/Set/DictComprehensionExpr (+ valueVariable) + - interpreter/src/visitors/expression_evaluator_members_advanced.cpp # زائرات الاستيعاب + فرع الخريطة + - compiler/src/frontend/builders/expression_comprehensions.cpp # بانِي القائمة/القاموس + lowerMapComprehensionIterable - compiler/src/frontend/builders/expression_comp2.cpp # بانِي المجموعة (مسح إزالة التكرار) + - compiler/src/frontend/builders/statement_for_range.cpp # أساس تكرار الخريطة في المترجم + - compiler/include/frontend/sir_constants.h # kRuntimeMapKeys/kRuntimeMapValues (عقد الأسماء المشترك) + - compiler/src/backend/llvm/builders/collections/map_ops.cpp # __sad_map_keys/values + getOrCreateMapCollect + - compiler/src/frontend/builders/builtins_core.cpp # تمرير elementType لمُعامل الطبع + - compiler/src/backend/llvm/builders/builtins/io_builtins_ops.cpp # طبع المصفوفة الموسوم (__sad_array_to_string_str) - language-truth/grammar - file: src/backend/interpreter.md