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

الأخطاء

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

الأخطاء

يعامل السلطان الفشل على أنه قيمة. تحدد هذه الصفحة كيف تُحمل الأخطاء (نتيجة واختياري)، وكيف تُمرر إلى الأعلى بـ؟، وكيف تُوصف بعقد std.error (فشل)، وكيف يُبلغ عنها حين يتوقف البرنامج. وتتناول أيضا النسخ الاختيارية لرسالة الخطأ بلغات أخرى، وقيم اللغة التي تختار بينها. والصفحة موجهة إلى المبرمجين الذين يكتبون شيفرة قد تفشل، وإلى المساهمين الذين يعملون على المكتبة القياسية وعلى مسار الفشل وقت التشغيل.

الطبقات

الطبقة ما هي موضعها
الحمل نتيجة T, E واختياري T المترجم (tools/generate/registry/type_registry.def)
التمرير إلى الأعلى عامل الانتشار ؟ المترجم، توسيع في الواجهة الأمامية (compiler/frontend/desugar/propagation.sn)
الإيقاف دالة الإيقاف الأساسية إنهيار: تطبع رسالة وتنهي البرنامج library/std/process/panic.sn؛ ويعلم المترجم أنها لا تعود أبدا
العقد القيمة فشل ودوال إنشائها والوصول إليها library/std/error/
الأدوات المساعدة الملاحظات، واللف، والبحث في السلسلة، والعرض للمطورين، ودوال التحويل من أخطاء المكتبة القياسية المحددة النوع، ودوال السياق لـ؟ library/std/error/
نسخ اللغات نصوص اختيارية للخطأ الواحد بكل لغة، وقيم اللغة، ووسوم BCP 47، وعزل الاتجاه library/std/error/failure.sn، library/std/text/ (language.sn، system_language.sn، bidi.sn)

لا يقع في المترجم إلا الطبقات الأولى: الأنواع الحاملة، وتوسيع ؟، والعلم بأن دالة الإيقاف لا تعود أبدا. أما تشخيصات المترجم فنظام منفصل. إذ يملك iSpeak وcompiler/diagnostics/** كل رسالة من رسائل المترجم ومصائد وقت التشغيل والمفسر، والإطارات التي يطبعها البرنامج حين ينتهي بخطأ أو يتوقف (انظر حالات فشل البرنامج وقت التشغيل). لا تستورد std.error شيئا من المترجم، ولا تعرّف رمز SULTANC- ولا سجل تشخيص ولا درجة خطورة ولا سجل رسائل. وتفشل مجموعة اختبارات المعمارية في المشغل (tests/runner/suites/architecture.sn) إذا ذكر ملف تحت library/std/error/ أيا من compiler. أو compiler/ أو SULTANC-.

قواعد التصميم

  • أي نوع يمكن أن يكون خطأ. يقبل نتيجة T, E أي E. وتبقى تعدادات الأخطاء المحددة النوع مثل خطأ_تحليل_عدد وخطأ_جسون الواجهة الأساسية في std. أما فشل فهو الشكل المشترك للشيفرة التي تجمع أخطاء من مصادر مختلفة، وليس إلزاميا في أي موضع.
  • لا تفحص الشيفرة نص الرسالة أبدا. يُبنى القرار على تعداد محدد النوع أو على هوية فشل، ولا يُبنى على رسالته.
  • رسالة واحدة من المؤلف لكل فشل. الرسالة هي نص المؤلف بلغة المؤلف، وكل الدوال تعمل عليها وحدها ما عدا الدوال التي تراعي اللغة. ولا يتبع لغة البرنامج إلا الإطار المحيط بها. ونسخ اللغات إضافات اختيارية لا تقرؤها إلا الدوال التي تأخذ قيمة لغة.
  • تستعمل الأنماط أسماء المتغيرات العربية المعتمدة لأخطاء المكتبة القياسية المحددة النوع، حتى في الشيفرة المكتوبة بالإنجليزية (examples/ar/errors/results.sn).

النتائج والقيم الاختيارية

يحمل نتيجة T, E إما نتيجة.نجح(القيمة) وإما نتيجة.خطأ(الخطأ)، ويحمل اختياري T إما اختياري.موجود(القيمة) وإما اختياري.لا_شيء. يفكك طابق أيا منهما، ويمرر ؟ الخطأ أو الغياب إلى الأعلى.

استورد المكتبة.دخ.println;
استورد المكتبة.نصوص.number;

عرف اقسم(أ: عدد, ب: عدد): نتيجة عدد, نص {
    إذا (ب == 0) { أرجع نتيجة.خطأ("القسمة على صفر"); };
    أرجع نتيجة.نجح(أ / ب);
}

عرف أول_عنصر(القيم: &متجه عدد): اختياري عدد {
    إذا ((الطول(*القيم) مثل طبيعي) == 0) { أرجع اختياري.لا_شيء(); };
    أرجع اختياري.موجود((*القيم)[0]);
}

عرف الرئيسية(): عدد {
    طابق اقسم(84, 2) مع
    | نتيجة.نجح(ق) -> { اطبع_سطر(عدد_إلى_نص(ق)); }
    | نتيجة.خطأ(رسالة) -> { اطبع_سطر(رسالة); };
    دع فارغ: متجه عدد = [];
    طابق أول_عنصر(&فارغ) مع
    | اختياري.موجود(ع) -> { اطبع_سطر(عدد_إلى_نص(ع)); }
    | اختياري.لا_شيء -> { اطبع_سطر("لا عناصر"); };
    أرجع 0;
}

الانتشار: ؟

يمرر EXPR؟ خطأ أو غيابا إلى الدالة المستدعية. ولا يُقبل إلا لاحقةً أخيرة للطرف الأيمن كاملا من التعليمة، في أربعة أشكال:

الشكل المعنى عند النجاح
دع x: T = EXPR؟; يأخذ x القيمة
x := EXPR؟; يأخذ الموضع القيمة
أرجع EXPR؟; تُرجع القيمة
EXPR؟; تُهمل القيمة

وفي أي موضع آخر، كأن يكون داخل وسيط استدعاء أو معاملا في عملية، يكون ؟ رمزا غير متوقع (SULTANC-PARSE-SYNTAX). و؟ (U+061F) و? كتابتان لرمز واحد (QUESTION_OPERATOR، tools/generate/registry/token_registry.def).

عرف اقسم(أ: عدد, ب: عدد): نتيجة عدد, نص {
    إذا (ب == 0) { أرجع نتيجة.خطأ("القسمة على صفر"); };
    أرجع نتيجة.نجح(أ / ب);
}

عرف نصف_الناتج(أ: عدد, ب: عدد): نتيجة عدد, نص {
    دع ق: عدد = اقسم(أ, ب)؟;
    أرجع نتيجة.نجح(ق / 2);
}

قواعد الأنواع هي:

  • EXPR: نتيجة T, E داخل دالة ترجع نتيجة U, E يعطي T. وعند الخطأ ترجع الدالة نتيجة.خطأ(e). ويجب أن يكون نوع الخطأ هو E نفسه: لا شيء يحوله، لأن اللغة لا تملك السمات (traits)، فيُبلغ عن نوع خطأ مختلف عند ؟ مع ذكر النوعين (SULTANC-CALL-ARGUMENT-TYPE-MISMATCH). حوّل صراحة بـدوال السياق.
  • EXPR: اختياري T داخل دالة ترجع اختياري U يعطي T. وعند اختياري.لا_شيء ترجع الدالة اختياري.لا_شيء().
  • في دالة لا ترجع أيا منهما، يكون ؟ عدم تطابق في نوع الإرجاع عند ؟ (SULTANC-TYPE-RETURN-MISMATCH، مع ذكر نوع الدالة ونوع التعبير). والقيمة الاختيارية داخل دالة ترجع نتيجة تُبلغ بـSULTANC-PATTERN-INVALID عند ؟.
  • يرجع أرجع EXPR؟; القيمة T نفسها، فيجب أن يكون T نوع نتيجة الدالة، كما في Rust.

تتبع الفروع نوع الإرجاع كما هو مكتوب. فـاختياري … يعطي فروع القيمة الاختيارية، ونتيجة … أو اسم نوع (اسم بديل لنتيجة) يعطي فروع النتيجة. ولا يُتعرف على الاسم البديل لنوع اختياري، فاكتب اختياري … في توقيع الدالة التي تستعمل ؟ على قيم اختيارية.

كيف يُبنى

يوسّع compiler/frontend/desugar/propagation.sn كل تعليمة معلّمة بعد التحليل مباشرة، وقبل تحليل الأسماء، فترى الأسماء والأنواع والأنماط وتدفق الملكية (SSF) وMSIR وكل خلفية والمفسر تعليمات عادية. ففي دع x: T = EXPR؟; داخل دالة ترجع نتيجة يكون التوسيع:

دع x: T;
طابق EXPR مع
| مخفي -> {
    طابق مخفي مع
    | نتيجة.نجح(القيمة) -> { x := القيمة; }
    | نتيجة.خطأ(الخطأ) -> { أرجع نتيجة.خطأ(الخطأ); };
};
  • يُربط EXPR أولا بمتغير محلي مخفي مملوك، بنمط ربط لا يفشل نوعه هو نوع التعبير نفسه، ويكون طابق الموزع على ذلك المتغير المحلي، لا على نتيجة الاستدعاء أبدا.
  • يربط كل فرع حمولة واحدة، والإرجاع المبكر هو الإرجاع العادي، فيحرر إطار الإسقاط كل متغير محلي مملوك مرة واحدة بالضبط. ويرجع tests/{ar,en}/language/propagation/drops.sn إرجاعا مبكرا 10^5 مرة من دالة تحمل نصا ومتجها وصندوقا، ويتحقق من أن البايتات الحية في المخصص متساوية قبل ذلك وبعده.
  • التوسيع نص السلطان يُلحق بعد نص الوحدة نفسها ويحلله المحلل العادي، كما يحدث في توسيع المزخرفات، فيكون لكل اسم مولد موضع في المصدر. ويحتفظ EXPR وهدف الإسناد بموضعيهما، إذ يُنقلان من التعليمة الأصلية. وتبدأ الأسماء المخفية بـانتشار__.
  • تسجل خريطة المصدر كل منطقة مولدة و؟ الذي تمثله (compiler/source/source_map.sn، إحالة_نص_مولد)، فيُبلغ عن أي تشخيص داخل التوسيع عند ؟.

ينفذ Stage0 المكتوب بلغة C التوسيع نفسه في محلله (bootstrap/src/frontend/parser/parser_statement_propagation.c): متغير مؤقت مخفي نوعه مستنتج، ثم طابق. ويستعمل المترجم ووحدات المكتبة القياسية التي يستوردها ؟، ومن أمثلة ذلك compiler/driver/package_graph.sn وstd.toml.parser.

الوحدة std.error

الوحدة الاستيراد بالعربية المحتوى
std.error.failure المكتبة.أخطاء.failure القيمة فشل وواجهتها كاملة
std.error.from_os المكتبة.أخطاء.from_os دوال التحويل لـstd.fs وstd.io وstd.process
std.error.from_number المكتبة.أخطاء.from_number دالة التحويل لـstd.text.number
std.error.from_json المكتبة.أخطاء.from_json دالة التحويل لـstd.json
std.error.from_net المكتبة.أخطاء.from_net دوال التحويل لـstd.net
std.error.from_command المكتبة.أخطاء.from_command دالة التحويل لـخطأ_أمر في std.process.command (النطاق std.process، والنوع تشغيل أو دخل_خرج أو انتظار، والسبب = خطأ النظام المصنف)
std.error.from_duration المكتبة.أخطاء.from_duration دالة التحويل لـخطأ_مدة في std.time.duration_text (النطاق std.time)
std.error.from_fmt المكتبة.أخطاء.from_fmt دالة التحويل لـخطأ_تنسيق في std.fmt (النطاق std.fmt، والنوع = اسم المتغير، وإزاحة البايت أو رقم الوسيط أو حالة الكاتب ملاحظةً)
std.error.context المكتبة.أخطاء.context دوال السياق لـ؟
std.text.language المكتبة.نصوص.language قيمة اللغة لغة، ووسوم BCP 47، وAccept-Language
std.text.system_language المكتبة.نصوص.system_language لغة بيئة البرنامج
std.text.bidi المكتبة.نصوص.bidi عزل الاتجاه

أخطاء هي الكتابة العربية لاسم الحزمة error (تُعلن في library/std/std.sn؛ انظر الوحدات والاستيراد). ويحل Stage0 المكتوب بلغة C أسماء الحزم العربية من الملف نفسه (bootstrap/src/support/path/source_import_path.c).

القيمة

تحمل قيمة فشل (library/std/error/failure.sn):

  • هوية (النطاق, النوع)، أي النطاق والنوع. يسمي النطاق المالك، وهو مسار وحدة مثل std.fs أو حزمة مثل payments. والنوع اسم آلي ثابت داخل ذلك النطاق، مثل غير_موجود. والنوع الفارغ يعني خطأ عارضا بلا هوية. وهذه فكرة ErrorInfo (domain, reason) في gRPC وtype في RFC 9457؛
  • رسالة للمطورين: جملة واحدة بلغة المؤلف، بلا نقطة في آخرها؛
  • سببا اختياريا، وهو فشل آخر، فتشكل الأخطاء سلسلة؛
  • ملاحظات، بترتيب إضافتها (add_note في Python)؛
  • نسخ لغات اختيارية للرسالة (انظر نسخ اللغات).

القيمة معتمة. استعمل الدوال أدناه لا حقولها، حتى يمكن إضافة حقول لاحقا. وهي تملك نصا ومتجها وصندوقا، فتُتلف تلقائيا كأي قيمة مالكة، ولا يلزم تحرير شيء يدويا. والنسخ صريح: بالدالة الأساسية استنسخ أو بـانسخ_فشل. وتحرر شيفرة الإسقاط النص ومتجه الملاحظات وسلسلة الأسباب المحفوظة في صندوق، وتنسخها شيفرة الاستنساخ.

الواجهة

العربية الإنجليزية التوقيع المعنى
فشل Error نوع قيمة الخطأ
فشل_من error_new (الرسالة: نص): فشل خطأ عارض بهوية فارغة (errors.New في Go)
فشل_بهوية error_with_kind (النطاق: نص, النوع: نص, الرسالة: نص): فشل خطأ له هوية
فشل_بسبب error_caused_by (الرسالة: نص, السبب: فشل): فشل خطأ عارض يلف سببا يُنقل إليه (%w في Go)
فشل_بهوية_وسبب error_with_kind_caused_by (النطاق: نص, النوع: نص, الرسالة: نص, السبب: فشل): فشل خطأ له هوية يلف سببا
انسخ_فشل error_copy (&فشل): فشل نسخة عميقة مستقلة تشمل الأسباب؛ نتيجتها نتيجة استنسخ نفسها، بصيغة يترجمها Stage0
رسالة_فشل error_message (&فشل): نص نسخة من الرسالة
نطاق_فشل error_domain (&فشل): نص نسخة من النطاق
نوع_فشل error_kind (&فشل): نص نسخة من النوع
له_سبب error_has_cause (&فشل): منطقي هل يوجد سبب
سبب_فشل error_cause (&فشل): اختياري فشل نسخة من السبب المباشر
ملاحظات_فشل error_notes (&فشل): متجه نص نسخة من الملاحظات
هل_من_نوع error_is (&فشل, النطاق: &نص, النوع: &نص): منطقي هل لهذا الخطأ أو لأي سبب في سلسلته هذه الهوية (errors.Is في Go)
أضف_ملاحظة error_add_note (&متغير فشل, الملاحظة: نص): فراغ تضيف ملاحظة في الآخر؛ ولا تتغير الهوية ولا الرسالة (PEP 678)
صف_فشل error_describe (&فشل): نص العرض للمطورين، أدناه
اطبع_فشل error_print (&فشل): فراغ تكتب صف_فشل وسطرا جديدا إلى الخطأ القياسي

ترجع دوال الوصول نسخا مملوكة، لأن Stage0 لا يستطيع إرجاع المراجع. ولا تطابق هل_من_نوع نوعا فارغا أبدا: فالخطأ العارض لا هوية له تطابَق.

استورد المكتبة.أخطاء.failure;
استورد المكتبة.دخ.println;

عرف الرئيسية(): عدد {
    دع الجذر: فشل = فشل_بهوية("std.fs", "غير_موجود", "الملف غير موجود");
    دع الملفوف: متغير فشل = فشل_بهوية_وسبب("app", "إعدادات", "تعذر تحميل الإعدادات", الجذر);
    أضف_ملاحظة(&متغير الملفوف, "المسار: /etc/app.toml");
    اطبع_سطر(صف_فشل(&الملفوف));
    دع النطاق: نص = "std.fs";
    دع النوع: نص = "غير_موجود";
    إذا (هل_من_نوع(&الملفوف, &النطاق, &النوع)) { اطبع_سطر("موجود في السلسلة"); };
    أرجع 0;
}

العرض للمطورين

يعطي صف_فشل الرسالة، ثم كل ملاحظة في سطر يبدأ بـملاحظة: ، ثم لكل سبب في السلسلة سطرا يبدأ بـبسبب: تليه رسالة السبب، ثم ملاحظات ذلك السبب. وتفصل بين الأسطر \n، ولا يوجد سطر جديد في النهاية. وكلمتا الربط نص ثابت تملكه المكتبة القياسية، بالعربية، وهي اللغة الافتراضية للمشروع. وليستا من نصوص iSpeak، ولا يغيرهما صف_فشل أبدا، فتظهر رسائل المؤلف الإنجليزي بين كلمات ربط عربية. أما صف_فشل_بلغة فيختار كلمات الربط بحسب اللغة.

أثناء بدء الخادم
ملاحظة: مسار الإعدادات من SULTANC_CONFIG
بسبب: تعذر قراءة الإعدادات
بسبب: ملف الإعدادات فارغ
ملاحظة: الحجم 0 بايت

دوال التحويل من أخطاء المكتبة القياسية المحددة النوع

تأخذ كل دالة تحويل خطأها المحدد النوع بالمرجع، وهو شكل قيمة دالة التحويل (دالة(&E): فشل). النطاق هو الوحدة، والنوع هو الاسم العربي المعتمد للمتغير، والرسالة جملة عربية ثابتة. والتفاصيل المتغيرة ملاحظات: الحالة الرقمية، وإزاحة البايت، وموضع البايت.

دالة التحويل الإنجليزية من النطاق الأنواع الملاحظة
فشل_من_فئة_خطأ_نظام error_from_os_error_class &فئة_خطأ_نظام std.fs متغيرات فئة_خطأ_نظام الأحد عشر لا شيء
فشل_من_خطأ_ملف error_from_fs_error &عدد، حالة من std.fs std.fs كما سبق رمز الحالة: N
فشل_من_خطأ_دخل_خرج error_from_io_error &عدد، حالة من std.io std.io كما سبق رمز الحالة: N
فشل_من_خطأ_عملية error_from_process_error &عدد، حالة من std.process std.process كما سبق رمز الحالة: N
فشل_من_خطأ_تحليل_عدد error_from_integer_parse_error &خطأ_تحليل_عدد std.text.number نص_فارغ، إشارة_بلا_أرقام، رقم_غير_صالح، تجاوز، سالب_لطبيعي موضع البايت: N مع رقم_غير_صالح
فشل_من_خطأ_جسون error_from_json_error &خطأ_جسون std.json متغيرات صنف_خطأ_جسون التسعة إزاحة البايت: N
فشل_من_خطأ_تحليل_آيبي error_from_ip_parse_error &خطأ_تحليل_آيبي std.net صيغة_غير_صالحة، جزء_خارج_المدى لا شيء
فشل_من_خطأ_تحليل_عنوان_مقبس error_from_socket_address_parse_error &خطأ_تحليل_عنوان_مقبس std.net صيغة_غير_صالحة، عنوان_غير_صالح، منفذ_غير_صالح لا شيء
فشل_من_خطأ_تنسيق error_from_fmt_error &خطأ_تنسيق std.fmt متغيرات خطأ_تنسيق الأحد عشر موضع البايت: N أو رقم الوسيط: N أو رمز الحالة: N

تبلغ std.fs وstd.io وstd.process عن حالة وقت التشغيل الرقمية الموروثة (عدد، سالبة عند الفشل)، لا عن تعداد. وتصنفها دوال التحويل الخاصة بها بـصنف_خطأ_نظام من std.fs، وهو مصنف أخطاء الملفات الخاص بالهدف، فيكون النوع أحد متغيرات فئة_خطأ_نظام (-2 يعطي غير_موجود على Linux وmacOS). وهي، مثل ذلك المصنف، ليست مخصصة لحالات المقابس. ويشترك تعدادا std.net في النوع صيغة_غير_صالحة، ومعناه صيغة غير صالحة في أي منهما.

ترجع الوصلات والأذونات والسمات والمسارات القانونية والملفات المؤقتة في std.fs، وكذلك std.env.variables، نتيجة T, فئة_خطأ_نظام، وتُحوّل بـفشل_من_فئة_خطأ_نظام. وترجع std.process.command خطأ_أمر (فشل_من_خطأ_أمر)، وترجع std.time.duration_text خطأ_مدة (فشل_من_خطأ_مدة). وتحتفظ std.net.socket_names بالحالات الرقمية لـstd.net.

يعرض examples/{ar,en}/errors/error_values.sn برنامجا كاملا.

دوال السياق

توفر std.error.context دوالا عادية تعمل على نتيجة وهي في طريقها، صُممت لتُستعمل مع ؟. تأخذ كل منها النتيجة بالقيمة وتنقل قيمة النجاح كما هي، فلا يحتاج T المالك (نص، متجه) إلى قيد بساطة.

العربية الإنجليزية التوقيع المعنى
مع_سياق with_context <T>(نتيجة T, فشل, الرسالة: نص): نتيجة T, فشل عند الخطأ، فشل عارض جديد بهذه الرسالة سببه ذلك الخطأ
إلى_فشل to_error <T, E>(نتيجة T, E, حول: دالة(&E): فشل): نتيجة T, فشل خطأ محدد النوع محوّل بقيمة دالة تحويل، مثل فشل_من_خطأ_تحليل_عدد
مع_ملاحظة with_note <T>(نتيجة T, فشل, الملاحظة: نص): نتيجة T, فشل عند الخطأ، الخطأ نفسه مع ملاحظة إضافية
استورد المكتبة.أخطاء.failure;
استورد المكتبة.أخطاء.context;
استورد المكتبة.أخطاء.from_number;
استورد المكتبة.نصوص.number;

عرف اقرأ_المنفذ(النص: نص): نتيجة عدد, فشل {
    دع المنفذ: عدد = إلى_فشل(حلل_عدد(&النص), فشل_من_خطأ_تحليل_عدد)؟;
    أرجع نتيجة.نجح(المنفذ);
}

عرف الرئيسية(): نتيجة عدد, فشل {
    دع المنفذ: عدد = مع_سياق(اقرأ_المنفذ("80x"), "أثناء بدء الخادم")؟;
    أرجع نتيجة.نجح(المنفذ);
}

قيود Stage0

تبقى std.error.failure وstd.error.from_os وstd.error.from_number وstd.error.context ضمن ما يترجمه Stage0 المكتوب بلغة C: لا دالة نسخ أساسية (ومن هنا انسخ_فشل)، ولا إرجاع للمراجع، ولا مراجع في السجلات أو في المتغيرات المحلية القابلة للتغيير، ولا استدعاءات في القيم الحرفية للمتجهات، ولا ثوابت على المستوى الأعلى. ويتحقق tests/{ar,en}/stdlib/error/stage0_contract.sn من ذلك حين يُعطى المشغل ملفا تنفيذيا لـStage0 في SULTANC_STAGE0_BIN. ولا تستطيع std.error.from_json وstd.error.from_net الالتزام بذلك، لأن std.json وstd.net.socket_address تستعملان أصلا صيغا يرفضها Stage0. ولا يستورد المترجم std.error.

نسخ اللغات

نسخ اللغات اختيارية. يجوز للمؤلف أن يضيف رسالة فشل بلغات أخرى، كل منها تحت وسم BCP 47، والشيفرة التي تعرف لغة القارئ تمرر قيمة لغة فتحصل على النص المطابق. ولا يتغير شيء آخر: الهوية، ورسالة المؤلف، وصف_فشل، وهل_من_نوع، ودوال السياق، والإطار الذي تطبعه الرئيسية، كلها تعمل كما كانت. ولا توجد لغة عامة للبرنامج كله. فاللغة قيمة تُمرر إلى الدالة التي تحتاجها، فيجيب الخادم كل طلب بلغته.

استورد المكتبة.أخطاء.failure;
استورد المكتبة.نصوص.language;
استورد المكتبة.دخ.println;

عرف الرئيسية(): عدد {
    دع الفشل: متغير فشل = فشل_بهوية("settings", "فارغ", "ملف الإعدادات فارغ");
    أضف_نسخة_لغة(&متغير الفشل, "en", "the settings file is empty");

    دع الترويسة: نص = "fr-CH, fr;q=0.9, en;q=0.8";
    دع الطلب: لغة = لغة_من_قبول_اللغة(&الترويسة);
    اطبع_سطر(نص_فشل_بلغة(&الفشل, &الطلب));
    أرجع 0;
}

يعرض examples/{ar,en}/errors/languages.sn برنامجا كاملا.

النسخ في قيمة فشل

النسخ حقل خاص في فشل: قائمة أزواج (وسم، نص) بترتيب إضافتها.

العربية الإنجليزية التوقيع المعنى
أضف_نسخة_لغة error_add_language_version (&متغير فشل, الوسم: نص, النص: نص): فراغ تضيف الرسالة بلغة. يُخزن الوسم بحالة الأحرف المعتمدة (en_gb يصير en-GB)، والنسخة الثانية تحت الوسم نفسه تحل محل الأولى. ولا يُتحقق من صحة الوسم: فالوسم غير الصحيح لا يجده البحث أبدا، لكنه قد يكون مع ذلك النسخة الأولى
نص_فشل_بلغة error_text_in (&فشل, &لغة): نص رسالة هذا الخطأ للغة معينة (البحث أدناه)؛ ولا تُضمّن الأسباب
صف_فشل_بلغة error_describe_in (&فشل, &لغة): نص صف_فشل للغة معينة (أدناه)
اطبع_فشل_بلغة error_print_in (&فشل, &لغة): فراغ تكتب صف_فشل_بلغة وسطرا جديدا إلى الخطأ القياسي

يتبع نص_فشل_بلغة البحث المحدد في RFC 4647 القسم 3.4:

  1. لكل وسم من وسوم اللغة، بدءا بالأكثر تفضيلا، يأخذ النسخة التي تحت هذا الوسم بالضبط، ثم تحت كل صيغة أقصر منه وصولا إلى لغته الأساسية (ar-SA إلى ar؛ zh-Hant-TW إلى zh-Hant إلى zh). والوسم الفرعي المفرد (singleton) الذي يبقى في الآخر يُحذف مع الوسم الفرعي الذي يليه (en-GB-x-test إلى en-GB).
  2. وإلا يرجع رسالة المؤلف.
  3. وإن كانت فارغة، يرجع أول نسخة أضيفت.

لا يطابق الوسم إلا نسخة مساوية له في التحديد أو أقل تحديدا، فاللغة en لا تجد النسخة en-GB. والمقارنة لا تفرق بين الأحرف الكبيرة والصغيرة، لأن الطرفين بحالة الأحرف المعتمدة. وفي لغة من وسم واحد فيه وسم فرعي أو اثنان، يكون الترتيب: الوسم بالضبط، ثم اللغة الأساسية، ثم رسالة المؤلف، ثم أول نسخة.

صف_فشل_بلغة هو صف_فشل مع ثلاثة فروق:

  • تُختار رسالة كل خطأ في السلسلة بـنص_فشل_بلغة مع اللغة نفسها، فتُقرأ السلسلة بلغة واحدة بقدر ما تتوفر نسخها.
  • تتبع كلمات الربط اللغة: ملاحظة: وبسبب: حين تكون لغتها الأساسية ar أو حين لا يكون لها وسم، وnote: وcaused by: لأي لغة أخرى. وهي نص ثابت في المكتبة القياسية، وليست من iSpeak ولا جدول ترجمة.
  • الرسالة أو الملاحظة التي تأتي بعد كلمة ربط ويختلف اتجاهها عن اتجاه كلمات الربط (رسالة لاتينية بعد بسبب: ، أو عربية بعد caused by: ) تُحاط بـU+2068 … U+2069 (std.text.bidi). ويُترك السطر الأول، الذي لا كلمة ربط فيه، كما هو.

ليس للملاحظات نسخ: فهي تفاصيل (مسار، حالة) بنص المؤلف. ومع لغة عربية وعدم وجود نسخة عربية، يعطي صف_فشل_بلغة ما يعطيه صف_فشل بالضبط للنص العربي.

اللغات: std.text.language

العربية الإنجليزية التوقيع المعنى
لغة Locale نوع قائمة أولويات اللغة (RFC 4647 القسم 2.3): وسم واحد، أو نطاقات ترويسة Accept-Language، بدءا بالأكثر تفضيلا؛ وقد لا يكون فيها وسم. معتمة
لغة_من_وسم locale_from_tag (&نص): لغة لغة من وسم واحد، بحالة الأحرف المعتمدة، مع حذف المسافات حوله، وقبول _؛ والنص الذي ليس وسما صحيح البنية يعطي لغة بلا وسم
لغة_من_قبول_اللغة locale_from_accept_language (&نص): لغة نطاقات ترويسة HTTP Accept-Language (RFC 9110 القسم 12.5.4) مرتبة بحسب q، من الأعلى إلى الأدنى، والأوزان المتساوية بترتيب كتابتها. ويُستبعد النطاق ذو الوزن 0، والحرف البديل *، والنطاق الذي ليس وسما صحيح البنية، والعنصر ذو الوزن غير الصحيح (q=1.5، q=.5، أكثر من ثلاث خانات عشرية)؛ وتُتجاهل المعاملات الأخرى
وسوم_لغة locale_tags (&لغة): متجه نص نسخة من الوسوم، بدءا بالأكثر تفضيلا
وسم_لغة locale_tag (&لغة): نص الوسم الأكثر تفضيلا، أو نص فارغ
اللغة_الأساسية locale_language (&لغة): نص اللغة الأساسية للوسم الأكثر تفضيلا (ar-SA يعطي ar)، أو نص فارغ
انسخ_لغة locale_copy (&لغة): لغة نسخة؛ مثل استنسخ، بصيغة يترجمها Stage0

fr-CH, fr;q=0.9, en;q=0.8, *;q=0.5 يعطي fr-CH، fr، en.

وسوم BCP 47 (RFC 5646) منفذة مرة واحدة في المكتبة القياسية لأي مستخدم:

العربية الإنجليزية التوقيع المعنى
وسم_لغة_صالح is_language_tag (&نص): منطقي هل النص وسم صحيح البنية: لغة (من 2 إلى 8 أحرف، مع ما يصل إلى ثلاثة وسوم فرعية ممتدة بعد 2 إلى 3 أحرف)، ونظام كتابة (4 أحرف)، ومنطقة (حرفان أو 3 أرقام)، ومتغيرات، وامتدادات، واستعمال خاص؛ أو وسم استعمال خاص x-…. ويُقبل _ فاصلا. ولا يُتحقق من التسجيل، ولا تُقبل الوسوم الموروثة غير المنتظمة (i-klingon)
طبع_وسم_لغة normalize_language_tag (&نص): نص حالة الأحرف المعتمدة مع - (RFC 5646 القسم 2.1.1): أحرف صغيرة، والمنطقة بأحرف كبيرة، ونظام الكتابة بحرف أول كبير، وكل ما بعد الوسم الفرعي المفرد بأحرف صغيرة (sr_latn_rs يعطي sr-Latn-RS)
اللغة_الأساسية_لوسم language_tag_base (&نص): نص الوسم الفرعي للغة الأساسية بأحرف صغيرة
اختصر_وسم_لغة truncate_language_tag (&نص): نص خطوة رجوع واحدة من بحث RFC 4647 (zh-Hant-CN يعطي zh-Hant؛ ar يعطي نصا فارغا)

لغة البيئة: std.text.system_language

العربية الإنجليزية التوقيع المعنى
لغة_من_البيئة locale_from_environment (): لغة لغة البرنامج: SULTANC_LANG، ثم LC_ALL وLC_MESSAGES وLANG، ثم اللغة التي تُرجم بها البرنامج (--lang، ويكتبها المترجم في std.process.failure_text)، ثم العربية. وهي دائما وسم واحد

تُقرأ القيمة كما هو موضح في حالات فشل البرنامج وقت التشغيل: وسم أو لغة POSIX، مع تخطي C وPOSIX والقيمة الفارغة والقيمة غير الصحيحة البنية. ويستعمل مسار الفشل وقت التشغيل هذه الدالة نفسها لتحديد لغة إطاراته، فلا يكون في المكتبة القياسية إلا قراءة واحدة لهذه المتغيرات. وهي تقرأ البيئة في كل استدعاء؛ والنتيجة قيمة، لا ذاكرة مؤقتة (cache).

عزل الاتجاه: std.text.bidi

العربية الإنجليزية التوقيع المعنى
اتجاه_نص text_direction نوع: محايد / neutral، من_اليسار_إلى_اليمين / left_to_right، من_اليمين_إلى_اليسار / right_to_left اتجاه
اتجاه_النص text_direction_of (&نص): اتجاه_نص اتجاه أول حرف قوي، مع تخطي ما يقع داخل العوازل (UAX #9 من P2 إلى P3): وهو الاتجاه الذي يعطيه عازل الحرف القوي الأول للنص
اعزل_اتجاه bidi_isolate (&نص): نص U+2068 (عازل الحرف القوي الأول)، ثم النص، ثم U+2069 (إنهاء العزل الاتجاهي)
اعزل_اتجاه_في bidi_isolate_in (&نص, السياق: اتجاه_نص): نص النص معزولا حين يكون اتجاهه قويا ومختلفا عن اتجاه السياق؛ وإلا نسخة غير معدلة

يُحدد اتجاه الحرف من نطاقات أنظمة الكتابة، لا من جدول Bidi_Class في Unicode. فالعبرية والعربية والسريانية والثانا وأنكو وسائر الكتل التي تُكتب من اليمين إلى اليسار اتجاهها من اليمين إلى اليسار، ما عدا أرقامها وعلاماتها المركبة. واللاتينية واليونانية والسيريلية والأرمنية وأنظمة الكتابة الهندية وأنظمة شرق آسيا اتجاهها من اليسار إلى اليمين. وكل ما عدا ذلك محايد، ومنه الأرقام وعلامات الترقيم. وتستعمل الأنماط أسماء المتغيرات العربية.

يحتفظ iSpeak في المترجم بعزله الخاص للحقائق المقتبسة في التشخيصات العربية على الطرفية (compiler/diagnostics/output/terminal.sn): فهو يعزل المقاطع المحاطة بعلامة الاقتباس المائلة (backtick) أثناء النسخ. ولا تعتمد المكتبة القياسية على iSpeak ولا تحمل أيا من جداوله.

النسخ الإنجليزية لأخطاء المكتبة القياسية نفسها

تضيف كل دالة تحويل في std.error.from_os وfrom_number وfrom_json وfrom_net نسخة إنجليزية (en) لرسالتها العربية. ولا تتغير الرسالة ولا الهوية ولا الملاحظات، وتبقى الملاحظات كما كُتبت (رمز الحالة: -2).

تقع std.text.language وstd.text.bidi وstd.text.system_language ودوال اللغة في std.error.failure ضمن لغة Stage0 المكتوب بلغة C، ويستدعي tests/{ar,en}/stdlib/error/stage0_contract.sn كلا منها.

فهارس الرسائل

للرسائل التي ليست أخطاء (رسائل التحقق وصفحات الرفض ونصوص الواجهة) يحفظ std.text.messages فهرسًا: معرّف رسالة وقالب لكل وسم لغة، ووسائط مسماة بين معقوفين ({field})، وصيغ جمع CLDR يختارها عدد (صفر وواحد واثنان وقليل وكثير وآخر في العربية، وواحد وآخر في الإنجليزية). لغات القارئ قيمة لغة (يقرأ std.http.locale لغة_طلب_ويب ترويسة Accept-Language للطلب)؛ ويجرب البحث كل وسم مفضل وصيغه الأقصر، ثم اللغة الافتراضية للفهرس. وتُعزل الوسيطة التي يخالف اتجاهها اتجاه الرسالة (std.text.bidi). ويغطيه tests/*/stdlib/behavior/text_messages.sn.

إيقاف البرنامج

إنهيار

استورد المكتبة.عمليات.panic;

عرف اقسم(أ: عدد, ب: عدد): عدد {
    إذا (ب != 0) { أرجع أ / ب; };
    إنهيار("القسمة على صفر");
}

يطبع إنهيار(الرسالة: نص) (std.process.panic) الإطار "توقف البرنامج" والرسالة، ثم ينهي العملية بالحالة 1 عبر دالة الخروج من العملية في المكتبة القياسية، كما يفعل اخرج. وهي دالة من المكتبة القياسية، لا دالة أساسية في المترجم. وانهيار بلا همزة يسمي المعرّف نفسه.

  • لا تعود أبدا. تتعرف الواجهة الأمامية على إنهيار الموجودة في وحدة المكتبة القياسية الموثوقة process/panic.sn من خلال RootID ومفتاح الوحدة، بالطريقة التي توثق بها عقد نواة Linux، ولا تتعرف عليها أبدا من كتابة يمكن لوحدة مستخدم أن تنسخها. ثم تسلم الرمز إلى خفض MSIR. وتعليمة الاستدعاء لها تنهي كتلتها بمصيدة، كما يحدث في فشل وقت الترجمة، فلا تحتاج الدالة التي ترجع قيمة إلى إرجاع بعد الاستدعاء. ويفعل Stage0 المكتوب بلغة C الشيء نفسه (bootstrap/src/semantic/never_return.c): فهو يتعرف على إنهيار من المسار المعتمد لـ library/std/process/panic.sn تحت جذر المشروع، وينهي المسار في فحص التدفق لديه، ويُصدر unreachable بعد الاستدعاء.
  • دلالة الإجهاض (abort). تنتهي العملية فورا. ولا تُسقط القيم المملوكة التي ما زالت حية، كما في panic=abort في Rust، ويستعيد نظام التشغيل الذاكرة.

التأكيدات

يوقف تأكد وتأكد_برسالة (std.debug.assert) البرنامج عبر المسار نفسه: الإطار "توقف البرنامج" مع السبب "فشل تأكيد"، والرسالة الاختيارية تحته، والحالة 1. وتحددهما صفحة التقييم وقت الترجمة.

حالات فشل البرنامج وقت التشغيل

يطبع البرنامج سبب انتهائه عبر مسار واحد، هو std.process.failure (library/std/process/failure.sn)، سواء كان ملفا تنفيذيا أصليا (x86_64، arm64) أو wasm32 أو ناتج خلفية LLVM أو كان يعمل في المفسر. والمخرجات هي إطار هوية فشل وقت التشغيل، ثم الحمولة في الأسطر التي تحته، على الخطأ القياسي.

الهوية الإطار (بالعربية / بالإنجليزية) متى
SULTANC-RUNTIME-PROGRAM-ERROR خطأ[…]: انتهى البرنامج بخطأ / error[…]: the program ended with an error أرجعت الرئيسية خطأ؛ والحمولة: نص صف_فشل الخاص به
SULTANC-RUNTIME-PROGRAM-STOPPED خطأ[…]: توقف البرنامج / error[…]: the program stopped إنهيار؛ والحمولة: رسالته
SULTANC-RUNTIME-PROGRAM-STOPPED مع السبب runtime.assertion-failed … — فشل تأكيد. / … — An assertion failed. فشل تأكد؛ ثم --> <ملف>:<سطر>:<عمود>، موضع النداء (@@يتتبع_المستدعي)؛ والحمولة: الرسالة الاختيارية

الإطارات من iSpeak. والهويتان والسبب مسجلة كأي تشخيص (compiler/diagnostics/identity.sn، reason.sn، registry.sn، باللغتين)، والإطار هو العنوان الذي يظهر به تشخيص تلك الهوية على الطرفية. ولا يستطيع البرنامج تشغيل iSpeak، فيعرض المترجم الإطارات باللغتين (compiler/driver/program_failure_text.sn) ويكتبها، في كل ترجمة، نصا لوحدة المكتبة القياسية std.process.failure_text (طبقة مصدر فوق library/std/process/failure_text.sn)، مع اللغة التي يُترجم بها البرنامج. ونص الملف نفسه هو العرض العربي، الذي يقرؤه Stage0 المكتوب بلغة C والأدوات؛ ويتحقق tests/{ar,en}/ispeak/check_program_failure_text.sn من مطابقته لعرض المترجم. ولا تحمل المكتبة القياسية جدولا خاصا بها.

لغة البرنامج هي لغة لغة_من_البيئة() (std.text.system_language)، وهو الموضع الوحيد الذي تقرأ فيه المكتبة القياسية هذه المتغيرات. وهي أول ما يتوفر مما يلي:

  1. SULTANC_LANG؛
  2. LC_ALL، LC_MESSAGES، LANG؛
  3. قيمة --lang التي تُرجم بها البرنامج (بلا --lang تكون العربية؛ ومع --lang=auto تكون لغة المضيف الذي يعمل عليه المترجم)؛
  4. العربية.

القيمة وسم BCP 47 (en-US) أو لغة POSIX (ar_SA.UTF-8، de_DE@euro، وتُقرآن ar-SA، de-DE). واللغة التي لغتها الأساسية ar تعطي إطارات عربية، وأي لغة أخرى تعطي إطارات إنجليزية. والقيمة الفارغة وC وC.… وPOSIX والقيمة التي ليست وسم لغة لا تحمل لغة، فيُقرأ المصدر التالي، ولذلك يصل جهاز التكامل المستمر (CI) الذي قيمته LANG=C.UTF-8 إلى اللغة التي تُرجم بها البرنامج.

الرئيسية ترجع خطأ

استورد المكتبة.أخطاء.failure;
استورد المكتبة.أخطاء.context;
استورد المكتبة.أخطاء.from_number;
استورد المكتبة.نصوص.number;

عرف اقرأ_المنفذ(النص: نص): نتيجة عدد, فشل {
    دع المنفذ: عدد = إلى_فشل(حلل_عدد(&النص), فشل_من_خطأ_تحليل_عدد)؟;
    أرجع نتيجة.نجح(المنفذ);
}

عرف الرئيسية(): نتيجة عدد, فشل {
    دع المنفذ: عدد = مع_سياق(اقرأ_المنفذ("80x"), "أثناء بدء الخادم")؟;
    أرجع نتيجة.نجح(المنفذ);
}

عند نتيجة.نجح(n) يخرج البرنامج بالحالة n. وعند نتيجة.خطأ(f) يطبع الإطار "انتهى البرنامج بخطأ" وصف_فشل(&f)، ثم يخرج بالحالة 1. ومع SULTANC_LANG=ar تكون مخرجات البرنامج أعلاه:

خطأ[SULTANC-RUNTIME-PROGRAM-ERROR]: انتهى البرنامج بخطأ
أثناء بدء الخادم
بسبب: في النص محرف ليس رقما عشريا
ملاحظة: موضع البايت: 2

يتولى compiler/frontend/desugar/entry_result.sn ذلك في الواجهة الأمامية. ففي الوحدة الجذر، تحتفظ دالة الدخول (الرئيسية) التي لا معاملات لها والتي كُتبت نتيجتها نتيجة T, E بجسمها تحت اسم مخفي (نقطة_دخول__…)، وتصير دالة الدخول دالة عادية ترجع T. فهي تطابق نتيجة الدالة المخفية، وترجع القيمة، أو تستدعي أبلغ_عن_خطأ_نقطة_الدخول وترجع 1. ويستورد النص المولد std.process.failure. وبذلك يرى محول الدخول في كل خلفية (backend/target/executable_entry_query_context.sn، وentry.sn في LLVM) والمفسر دالة دخول لها حالة خروج، ويُطبق فحص الدخول (SULTANC-ENTRYPOINT-INVALID-SIGNATURE) على T: فإذا لم يكن T حالة خروج، أو لم يكن E هو فشل، يُبلغ عن ذلك عند نوع النتيجة المكتوب. ويُنقل الخطأ إلى التقرير ويُسقط في مسار الإرجاع العادي، فينتهي البرنامج انتهاء سليما.

المفسر

ينفذ sultanc run شيفرة المكتبة القياسية نفسها، فيطبع الإطارات نفسها. ويعطي المفسر البرنامج متغيرات اللغة من بيئته (SULTANC_LANG، LC_ALL، LC_MESSAGES، LANG) بيئةً لبدء التشغيل؛ ولا تتوفر المتغيرات الأخرى. واستدعاء exit_group الخام في Linux ينهي التفسير بالحالة، فينهي اخرج وإنهيار والتأكيدات البرنامج المفسَّر بالحالة الأصلية نفسها.

الاختبارات

تأتي الاختبارات أزواجا عربية وإنجليزية، ويكتب الاختبار الإنجليزي ?.

  • يغطي tests/{ar,en}/language/propagation/ المواضع الأربعة على النتائج والقيم الاختيارية (يتفق الملف التنفيذي الأصلي والمفسر وStage0)، وصحة الإسقاط عبر 10^5 إرجاع مبكر، وحالات الرفض في موضع غير مسموح، وفي دالة لا ترجع نتيجة، وعلى قيمة اختيارية في دالة ترجع نتيجة.
  • يتحقق tests/{ar,en}/diagnostics/e2e/propagation_error_type.* من نوع خطأ مختلف، يُبلغ عنه عند ؟ مع ذكر النوعين، بمخرجات عربية وإنجليزية مطابقة حرفيا.
  • يغطي tests/{ar,en}/stdlib/error/ دوال الإنشاء والوصول، وسلسلة من ثلاثة مستويات يُبحث فيها عند كل مستوى، وترتيب الملاحظات، ونص صف_فشل الدقيق، ودورات النسخ ذهابا وإيابا بـاستنسخ وانسخ_فشل، وكل متغير في كل تعداد محوّل، ودوال السياق، والبحث عن اللغة، وتحليل Accept-Language، والسلسلة بعدة لغات، والعزل ثنائي الاتجاه، وعقد Stage0، وثبات الذاكرة (يشغل rss_flat.sn وlanguage_rss_flat.sn 10^5 سلسلة ويتحققان من أن البايتات الحية في المخصص متساوية قبل ذلك وبعده؛ ولا يستعمل المفسر مخصص المكتبة القياسية، فلا تعمل هذه الاختبارات إلا أصليا).
  • يغطي tests/{ar,en}/runtime/failure/ إرجاع الرئيسية خطأ (SULTANC_LANG=ar وen) ونجاحه، وإنهيار والتأكيدات الفاشلة بلغتي البرنامج، مع الخطأ القياسي الدقيق، وحالة الخروج، واتفاق الملف التنفيذي الأصلي والمفسر. وتضبط الترويسة // بيئة: في المشغل بيئة البرنامج، وتسمي // خطأ-قياسي-ملف: الخطأ القياسي المتوقع.
  • يتحقق tests/{ar,en}/ispeak/check_program_failure_text.sn من مطابقة وحدة الكلمات لعرض المترجم.

ما لم يُدعم بعد

  • لا يتوفر فشل_وقت_الترجمة مع فشل؛ إذ يأخذ فشل_وقت_الترجمة نصا.
  • ملفات الفهارس وأدوات الترجمة والصيغ المختصرة من نوع .ar() خارج النطاق.
  • حمولة الإطار الذي تطبعه الرئيسية هي صف_فشل، أي رسائل المؤلف. ولم تُنفذ طباعتها بـصف_فشل_بلغة ولغة البرنامج.
  • لا يتعرف ؟ على الاسم البديل لنوع اختياري.

انظر أيضا