المطابقةُ النحويّةُ بالبناءِ لا بالنيّة
مجموعةُ مطابقةٍ عاديّةٌ تُجيبُ سؤالَ «أتنجحُ هذه الاختبارات؟». والسؤالُ الأهمُّ الذي لا تُجيبُه: أيُّ قاعدةٍ لا اختبارَ لها أصلًا؟ فالتغطيةُ الغائبةُ لا تُخفِقُ؛ إنّها ببساطةٍ غيرُ موجودة.
الجوابُ ههنا بنيويّ: اسمُ مجلَّدِ البذورِ هو معرّفُ القاعدةِ حرفًا.
tests/behavior/rules_matrix/
└── 10_statements/
└── gr.stmt.break/ ← الاسمُ = المعرّفُ في language-truth/grammar/
├── basic/ 001_in_while.ص …
├── edge/ 001_inner_only.ص …
└── negative/ 001_top_level.ص …فالقاعدةُ بلا مجلَّدٍ يُقاسُ غيابُها بفرقِ مجموعتَين، لا بحدسِ مراجع.
١ · الأرقامُ، وكيف تُعادُ
python - <<'EOF'
import glob, os, yaml
ids = set()
for f in glob.glob("language-truth/grammar/*.yaml"):
if os.path.basename(f) in ("lowers_to.yaml", "_notation.yaml"):
continue
def walk(o):
if isinstance(o, dict):
if isinstance(o.get("id"), str) and o["id"].startswith("gr."):
ids.add(o["id"])
for v in o.values(): walk(v)
elif isinstance(o, list):
for v in o: walk(v)
walk(yaml.safe_load(open(f, encoding="utf-8")))
root = "tests/behavior/rules_matrix"
dirs = {d for c in os.listdir(root) if os.path.isdir(f"{root}/{c}")
for d in os.listdir(f"{root}/{c}") if os.path.isdir(f"{root}/{c}/{d}")}
print("قواعدُ مُعلَنة:", len(ids))
print("مجلَّدات:", len(dirs), "· منها بمعرّفِ قاعدة:", len(ids & dirs))
print("قواعدُ بلا مجلَّد:", sorted(ids - dirs))
EOF| المقيس | القيمة |
|---|---|
| قواعدُ نحوٍ مُعلَنةٌ (معرّفاتٌ فريدة) | ١٠٧ |
مجلَّداتٌ في rules_matrix | ١٢٦ |
| منها اسمُها معرّفُ قاعدة | ١٠٣ |
ملفّاتُ بذورٍ .ص تحتَ rules_matrix | ٣٬٠٥٥ |
المجلَّداتُ الثلاثةُ والعشرونَ الزائدةُ ليست قواعدَ: _combos و_generated ومجلَّداتُ تداخلٍ بأسماءٍ موضوعيّةٍ (إذا_تداخلات، شرط_متغير_نطاق، …). والأربعُ بلا مجلَّد: gr.adv.ffi_ctype · gr.adv.ffi_extern_block · gr.adv.ffi_linkage · gr.adv.property_test.
٢ · المرساةُ وسمٌ لا موضعٌ فحسب
المجلَّدُ ليس المقياسَ الوحيد. كلُّ بذرةٍ تحملُ في سطرِها الأوّلِ وسمًا:
# @rule: gr.stmt.break
# @description: توقف في بينما
# @expected: 0
1فبذرةُ تداخلٍ في _interactions/ تشهدُ لعدّةِ قواعدَ دفعةً واحدة. وبعدّ الوسومِ لا المجلَّدات، الصورةُ تتغيّر: قاعدتانِ فقط بلا شاهدٍ في الشجرةِ كلِّها — gr.adv.ffi_ctype وgr.adv.property_test. والحارسُ check_anchor_integrity.py يطبعُها بندًا مستقلًّا:
② مُعلَنٌ بلا مرساة — دَينُ شهادةٍ نازلٌ لا يُرفَع:
النحو 105 / 107 · بلا شهادة: 2 (السقف 2)
① مرساةٌ يتيمة (ترسو على غيرِ مُعلَن): 0 (المسموح 0 — لا سقفَ له)الاتّجاهانِ محروسانِ معًا: مُعلَنٌ بلا شاهدٍ سقفُه ٢ ولا يُرفَع، وشاهدٌ يرسو على قاعدةٍ مخترَعةٍ صفرٌ بلا سقف. فوسمُ @rule ليس تعليقًا؛ هو مفتاحُ ربطٍ يُحَلُّ في مصدرِ الحقيقة.
٣ · أزواجُ التداخلِ مشتقّةٌ من النحوِ لا من حاصلِ ضرب
gen_rules_matrix.py يبني رسمَ قابليّةِ التركيبِ من مصدرِ الحقيقةِ نفسِه: القاعدةُ A تحتوي B إن أشارت alternatives إلى { kind: nonterminal, ref: gr.B }. فالأزواجُ المطلوبةُ هي حوافُ الرسم لا ١٠٧×١٠٧ زوجًا أعمى.
python scripts/codegen/check_grammar_conformance.py④ تغطية الأزواج (تداخل قاعدتين قابلتين للتركيب نحويًا):
مُغطّى 164/170 — ناقص 6٤ · ما يحرسُه البناءُ فعلًا — وما لا يحرسُه
تصريحٌ يلزمُ ألّا يُطوى
check_grammar_conformance.py — الذي يقيسُ ميزانيّاتِ الفئاتِ لكلِّ قاعدة — يُخفِقُ اليومَ برمزِ ١ ولا يُشغَّلُ في x.py gen --check. المُشغَّلُ في البوّابةِ هو gen_rules_matrix.py --check، وهو يحرسُ السلامةَ المرجعيّةَ وحدَها:
✓ [rules_matrix --check] سلامة مرجعيّة: 107 قاعدة · 3055 ملف اختبار
· لا وسوم @rule مجهولة.فالمحروسُ في الدمجِ ثلاثةٌ: أن يكونَ لكلِّ قاعدةٍ مدخلٌ، وألّا يرسوَ وسمٌ على قاعدةٍ لا وجودَ لها، وألّا ينموَ دَينُ الشهادةِ فوقَ سقفِه النازل. أمّا عمقُ التغطيةِ لكلِّ فئةٍ فمقيسٌ ومنشورٌ وليس بوّابة.
٥ · النحوُ يعلنُ ما يُقبَل، ولا يعلنُ ما يجبُ رفضُه
هذا أهمُّ قيدٍ مفهوميٍّ في المسارِ كلِّه. مدخلُ القاعدةِ في language-truth/grammar/ يحملُ ebnf وalternatives — أي لغةَ المقبول. ولا يحملُ حقلًا يقولُ «وهذه الصياغةُ يجبُ أن تُرفَضَ بالرمزِ كذا».
وينتجُ عن ذلك أثرٌ عمليٌّ صريح: بذرةٌ في negative/ تدّعي رفضًا قد لا يكونُ خلفَها قاعدةٌ في مصدرِ الحقيقة. فهي رأيُ بذرةٍ لا قاعدةُ لغة. والمقيسُ اليومَ بـpython scripts/codegen/check_seed_contract.py:
④ وسمٌ سالبٌ بلا رمزِ خطأ 360 (السقف 360 — نازل)ثلاثُمئةٍ وستّونَ وسمًا سالبًا لا يُسمّي رمزَ خطأٍ من الكتالوج. الوسمُ السالبُ الذي يُسمّي رمزًا يُقابَلُ به الكتالوجُ فعلًا — والمِحقنةُ تُثبِتُ ذلك بحقنِ SEM999 والتحقّقِ من احمرارِ الحارس.
خمسةُ رموزٍ لا تُدرَّسُ
INT008 · INT009 · INT010 · RUN059 · SEM027 مُعلَنةٌ retired لأنّ تعريفَها نفسَه كان المفسّرَ المحذوف. توجيهُ بذرةٍ سالبةٍ إليها يحملُ سلوكَ محرّكٍ محذوفٍ في ثوبِ قاعدةٍ مُعلَنة، و check_retired_error_codes.py يمنعُ عودةَ باعثٍ لها.
٦ · حدودٌ مقيسة
- عشرٌ من ١٠٧ قاعدةً وسمُها
experimental— كلُّها في60_advanced(FFI الثلاث، الأسمبليّ المضمَّن ولهجتُه، وخمسُ قواعدِ واجهة). - وصفٌ إنجليزيٌّ على قاعدةٍ واحدةٍ من ١٠٧، ومثالٌ على ٥٢ منها. الوصفُ العربيُّ على ١٠٧ كلِّها.
- أربعُ بذورٍ بلا وسمِ
@ruleأصلًا في20_declarations/gr.decl.variable/negative/— يطبعُها فاحصُ المطابقةِ بندًا ② ولا يُوقِفُ الدمج.