السلطان
  1. الرئيسية
  2. التوثيق
  3. المرجع

منسق المصدر

صفحات التوثيق

منسق المصدر

يعطي sultanc fmt مصدر السلطان ترتيبا قانونيا واحدا. يستدعي أمر المترجم وخادم اللغة المكتبة نفسها، compiler.format.format، فيُنسَّق الملف بالطريقة نفسها أينما نُسِّق. (أما std.fmt، سلاسل التنسيق في المكتبة القياسية، فموضوع آخر: التنسيق.)

العقد

  • أسلوب قانوني واحد. الإزاحة أربع مسافات، ولا خيار لعرض الإزاحة ولا لأي إعداد أسلوب آخر.
  • فواصل الأسطر للمؤلف. لا يلف المنسق الأسطر ولا يدمجها ولا يقسمها (عدا تصريحات الوحدات، سطر لكل منها)، ولا حد لعرض السطر.
  • منسق واحد. يستدعي sultanc fmt وخادم اللغة دالة المكتبة نفسها وينسقان بالطريقة نفسها. ولا يطبق خادم اللغة قواعد خاصة بمحرر، ويتجاهل إعدادات الإزاحة في المحرر.
  • المعنى محفوظ. تُحفظ الرموز والتعليقات والمعرفات العربية واللاتينية وتهجئات الكلمات المحجوزة بأي من اللغتين وكل نص حرفي بايتا بايتا (التفاصيل أدناه).
  • حتمي ومتساوي القوى. المدخل نفسه يعطي البايتات نفسها في كل تشغيل، وتنسيق نص منسق لا يغير شيئا.
  • نص يدخل ونص يخرج. يأخذ المنسق النص نفسه ولا يقرأ شيئا من القرص؛ والمسار لا يسمي المصدر إلا في التشخيصات. ويُنسَّق مخزن محرر لم يُحفظ كما يُنسَّق ملف.
  • كل شيء أو لا شيء. المصدر الذي لا يُحلَّل معجميا أو نحويا يعطي تشخيصاته ولا ناتج: لا نص منسق جزئيا أبدا، ولا يُعاد كتابة ملف جزئيا أبدا.

ما يغيره المنسق

لا يحرك المنسق إلا المسافات.

  • يُنسخ كل رمز بايتا بايتا وبترتيبه. تبقى الكلمات المحجوزة باللغة التي كُتبت بها، ومنها التهجئات المهجورة، ولا تُعاد تهجئة أي معرف، عربيا كان أو لاتينيا.
  • يُحفظ كل تعليق بايتا بايتا إلا المسافات في آخره. وتبقى التعليقات في مواضعها: التعليق على سطر وحده يبقى على سطر وحده، والتعليق بعد الشيفرة يبقى بعدها.
  • لا تُمس النصوص الحرفية أبدا، ومنها الأسطر داخل نص «…» متعدد الأسطر.
  • تُحفظ علامات الاتجاه LRM (U+200E) وRLM (U+200F) وALM (U+061C) بايتا بايتا، في التعليقات وفي النصوص الحرفية وبين الرموز.

تُحفظ فواصل الأسطر التي كتبها المؤلف: عدا تصريحات الوحدات (أدناه)، لا يدمج المنسق سطرين ولا يقسم سطرا، ولا حد لعرض السطر. وما يقرره هو:

  • الإزاحة. أربع مسافات لكل مستوى. العبارات داخل {…} أعمق بمستوى واحد من العبارة التي تفتح الكتلة. والأسطر داخل (…) أو […] أعمق بمستوى واحد من السطر الذي يفتح القوس. والسطر الذي يبدأ بقوس إغلاق في مستوى سطر فتحه. والسطر الذي يكمل عبارة (لم ينته السطر قبله بـ ; أو { أو }، أو بـ , داخل كتلة) أعمق بمستوى واحد، لا أكثر. وأذرع | نمط -> … في طابق … مع في مستوى طابق، أما أسطر | لمتغيرات نوع فأسطر إكمال. والسطر الذي يبدأ بـ ; في مستوى عبارته. وسطر التعليق التوضيحي (@@اختبار، @@سجل(«/أ»)) في مستوى التصريح الذي يعلِّق عليه، ويبدأ التصريح بعده (أو التعليق التوضيحي التالي) في العمود نفسه. والتعليق على سطر وحده يُزاح كالسطر الذي يليه.
  • المسافات في السطر. مسافة واحدة بعد , و; و:، وحول العوامل الثنائية و= و:= و->، وداخل { } وحولها، وبين الكلمات، وبين كلمة مثل إذا أو طالما و(. ولا مسافة قبل , و; و: و) و] و. و؟، ولا بعد ( و[ و. و@ و! و~، ولا بين المستدعى و( (د(س)، طبيعي(س))، ولا قبل [ الفهرسة، ولا بعد - أو * أو & البادئة (-1، *م، &متغير س).
  • اختيار المؤلف محفوظ. تحيط < و> و>> بوسائط نوع (خريطة<م, ق>) أو تقارن وتزيح، ولا تكفي الرموز وحدها لمعرفة أيهما، فتبقى المسافة التي كتبها المؤلف (لا شيء أو واحدة). و< أو > قبل عدد أو - أو ! مقارنة فتُحاط دائما بمسافة. و- أو * أو & المكتوبة بادئة بعد اسم مباشرة (متجه *ط8) تبقى بادئة. وتُحفظ المسافات قبل التعليق اللاحق، واحدة على الأقل، فتبقى التعليقات المحاذاة محاذاة.
  • الأسطر الفارغة. سطر فارغ واحد على الأكثر متتاليا، ولا شيء في بداية الملف أو نهايته. وينتهي الملف بفاصل سطر واحد، وتصير نهايات CRLF نهايات LF، ولا ينتهي سطر بمسافات.
  • تصريحات الوحدات. في الملف الجذر لمجلد، كل تصريح وحدة / module سطر قائم بنفسه: وحدة io { ar: دخ, fr: entree_sortie };. يدمج المنسق التصريح المكتوب على عدة أسطر (ويحفظ التعليق داخله سطره)، ويبدؤه على سطر جديد، ويبدأ ما يلي ; الخاصة به على السطر التالي، إلا التعليق اللاحق. وهذه القاعدة هي الموضع الوحيد الذي يحرك فيه المنسق فاصل سطر.

التنسيق متساوي القوى (idempotent): تنسيق ملف منسق لا يغير شيئا.

الملفات التي لا تُحلَّل

لا ينسق المنسق إلا ملفا يستطيع المترجم تحليله معجميا ونحويا. وأي ملف آخر يُبلغ عنه بالتشخيصات التي يطبعها sultanc check له، ولا يُكتب شيء. ومن ذلك ملف فيه محرف تحكم اتجاه صريح للتضمين أو التجاوز أو العزل (U+202A إلى U+202E، وU+2066 إلى U+2069) في أي موضع، حتى في تعليق أو نص حرفي: يرفضها المحلل المعجمي لأنها قد تعرض الشيفرة بترتيب غير الذي تُترجم به. ويمكن للنص الحرفي أن يحمل واحدا مكتوبا كتسلسل هروب، ويحفظ المنسق التسلسل كما كُتب.

الدلالة

يتحقق المنسق من ناتجه في كل مرة قبل كتابة أي شيء: يُحلَّل الناتج معجميا من جديد بمحلل المترجم، ويجب أن يحمل الرموز نفسها (الأنواع نفسها والبايتات نفسها، فالقيم نفسها)، والتعليقات والعلامات نفسها بالترتيب نفسه، وأن يُحلَّل نحويا. وإن لم يكن كذلك أبلغ المنسق عن إخفاق داخلي في المترجم (SULTANC-ICE-COMPILER-FAILURE، المرحلة formatter) وترك الملف كما كان.

لا يقرأ المحلل النحوي إلا الرموز، لا المسافات بينها، فالرموز نفسها تعطي البرنامج نفسه. وما قد يتغير هو الموضع: يتحرك رقم السطر حين تُحذف أسطر فارغة.

الأمر

sultanc fmt main.sn lib/            # ينسق في المكان؛ المجلد يعني ملفات .sn فيه
sultanc fmt --check main.sn lib/    # لا يغير شيئا؛ يبلغ عن كل ملف غير منسق
sultanc fmt < main.sn               # من الإدخال القياسي إلى الخرج القياسي (وكذلك `sultanc fmt -`)

يبلغ --check عن كل ملف غير منسق بـ SULTANC-FMT-UNFORMATTED عند أول موضع سيغيره المنسق. وحالة الخروج 0 حين يكون كل مدخل منسقا (ومكتوبا، دون --check)؛ و1 حين يجد --check ملفا يحتاج تنسيقا أو حين لا يُحلَّل مدخل معجميا أو نحويا؛ و3 حين يتعذر العثور على مدخل أو قراءته أو كتابته؛ و2 لسطر أوامر غير صالح (--check دون fmt، أو خيار بناء مثل -o أو --target معه). والإدخال القياسي الذي لا يُحلَّل لا يكتب شيئا في الخرج القياسي. ويُعاد كتابة الملف بكتابة ملف مؤقت بجانبه ثم إعادة تسميته فوقه، فلا يترك تشغيل منقطع ملفا ناقصا. وتعمل --lang و--diagnostic-format و--color كما في كل أمر.

التكامل مع المحررات

تستدعي المحررات وخادم اللغة المكتبة compiler.format.format مباشرة. وهي تأخذ النص نفسه: لا يسمي المسار المصدر إلا في التشخيصات، ولا يُقرأ شيء من القرص، فيُنسَّق مخزن لم يُحفظ كما يُنسَّق ملف محفوظ. وللمنسق أسلوب واحد بلا خيارات؛ فلا يتبع عرض الإزاحة في المحرر، ولا حد لعرض السطر.

استورد compiler.format.format;

// النص المنسق، أو تشخيصات مصدر لا يُحلَّل معجميا أو نحويا.
عرف نسق_نص_مصدر(المسار: &نص, النص: &نص): نتيجة_تنسيق
// التعديلات التي تنسق النص: إزاحات بايت UTF-8 فيه، مرتبة وغير متداخلة.
// انعدام التعديلات يعني أن النص منسق أصلا.
عرف تعديلات_تنسيق_نص(المسار: &نص, النص: &نص): نتيجة_تعديلات_تنسيق
// التعديلات نفسها، مقصورة على ما يمس مدى البايتات [البداية, النهاية].
عرف تعديلات_تنسيق_مدى(المسار: &نص, النص: &نص, البداية: طبيعي, النهاية: طبيعي): نتيجة_تعديلات_تنسيق

استدعاء لمخزن كامل:

استورد compiler.format.format;
استورد compiler.diagnostics.record;

عرف نسق_المخزن(العنوان: &نص, المخزن: &نص): اختياري نص {
    طابق نسق_نص_مصدر(العنوان, المخزن) مع
    | نتيجة_تنسيق.منسق(المنسق) -> { أرجع اختياري.موجود(المنسق); }
    | نتيجة_تنسيق.مرفوض(التشخيصات) -> {
        // المصدر لا يُحلَّل: `التشخيصات` هي التي يبلغ عنها `check`. لا ناتج
        // جزئي؛ اترك المخزن كما هو.
        أرجع اختياري.لا_شيء();
    };
}

النتيجة إما النص المنسق كله (منسق) وإما التشخيصات (مرفوض)، ولا نص جزئي أبدا. ويستبدل التعديل، تعديل_تنسيق، بايتات المدخل [البداية, النهاية) بـ النص. ولا يغير المنسق إلا المسافات، فكل تعديل يستبدل المسافات بين رمزين أو تعليقين. وتنسيق المدى دقيق: تعتمد إزاحة السطر على الملف كله، ويُنسَّق المدى كما ينسقه تنسيق الملف كله. ويحول خادم اللغة إزاحات البايت إلى مواضع بروتوكوله.

التحقق

مصادر المترجم والمكتبة القياسية هي المدونة المرجعية للمنسق. يفحص tools/tests/format_test.sh الأمر، وينسق tools/tests/format_corpus.sh نسخة من المدونة كلها ويتحقق من أن كل ملف يحفظ رموزه، وأن تشغيلا ثانيا لا يغير شيئا، وأن المترجم المبني من النسخة المنسقة ينتج الكائنات نفسها التي ينتجها المترجم المبني من الأصل.