صفحات التوثيق
نظام الأنواع
للسلطان نظام أنواع دلالي قانوني واحد يخدم الشيفرة العربية والإنجليزية والمختلطة. تصف هذه الصفحة الأنواع المدمجة والأنواع المركبة، وقواعد التحويل والحساب التي تنتمي إلى طبقة الأنواع، وفحص الالتقاط عند تمرير الدوال إلى الخيوط، وتوزيع المسؤوليات بين طبقة الأنواع وبقية المترجم. وهي موجهة إلى المبرمجين الذين يحتاجون القواعد الدقيقة، وإلى المساهمين الذين يعملون على تحليل الأنواع.
الهوية القانونية
تُوحَّد التهجئات السطحية قبل أن يرى أي مستهلك لاحق النوع.
التهجئة في المصدر
|
v
الرمز / نوع شجرة النحو المجردة
|
v
حل النوع
|
v
معرّف النوع القانوني
تُحلَّل التهجئتان الإنجليزية والعربية لنوع عددي صحيح مدمج إلى معرف النوع (Type ID) نفسه. فلا تتلقى خلفيات المترجم
ولا MSIR ولا تحليل الأمان ولا الأدوات نظامَي أنواع منفصلين للعربية والإنجليزية. تُولَّد تعريفات الأنواع المدمجة من سجل
الأنواع القانوني tools/generate/registry/type_registry.def، وتُشتق منه النسخ المطابقة في الواجهة الأمامية وفي
شيفرة الإقلاع الذاتي (bootstrap).
الأنواع المدمجة
| الفئة | الإنجليزية | العربية |
|---|---|---|
| أي قيمة | any |
أي |
| منطقي | bool |
منطقي |
| نص | string |
نص |
| حرف | char |
حرف |
| عدد صحيح بإشارة | int |
عدد |
| عدد صحيح بلا إشارة | uint |
طبيعي |
| بلا قيمة | void |
فراغ |
| بإشارة وعرض ثابت | i8, i16, i32, i64 |
ص8, ص16, ص32, ص64 |
| بلا إشارة وعرض ثابت | u8, u16, u32, u64 |
ط8, ط16, ط32, ط64 |
| فاصلة عائمة | f32, f64 |
ع32, ع64 |
طبيعي عدد طبيعي: عدد صحيح أكبر من الصفر أو يساويه، والصفر داخل فيه. التهجئتان العربيتان القديمتان غير_موقع
وغ8…غ64 مرادفان مهملان يُترجمان كالتهجئات الجديدة، ويُبلَّغ عن كل استعمال لهما مرة واحدة بـ
SULTANC-SYNTAX-DEPRECATED-SPELLING. وتسرد صفحة المصطلحات العربية كل
تهجئة أُعيدت تسميتها وسبب ذلك.
الأنواع المركبة
يمثل النموذج الدلالي هذه الأشكال المركبة:
- الصفوف (tuples)، وتُكتب
(عدد, عدد)؛ - الصناديق (boxes)؛
- القيم الاختيارية وقيم النتيجة؛
- أنواع الدوال، وتُكتب
دالة(عدد): عدد؛ - المؤشرات، والمراجع المشتركة والقابلة للتعديل (
&T،&متغير T)؛ - الشرائح والمتجهات؛
- الأغلفة القابلة للتعديل (
متغير T)؛ - أنواع السجلات والتعدادات والمرادفات المسماة، وقد تأخذ معاملات أنواع؛
- الأنواع المعتمة المسماة (
نوع T = معتم;، انظر الأنواع المعتمة).
هوية السجل أو التعداد المسمى هي تصريحه المحلَّل، لا تهجئته. والوسائط العامة (generic) تتداخل، و
مشترك<قفل<ص64>> يغلق القائمتين برمز >> واحد كما في Rust وC++11 وJava، ويعامله المحلل النحوي على أنه قوسا
إغلاق زاويان. يستنتج الاستدعاء العام معامل النوع من نوع القيمة الممررة، فالمتغير المحلي المصرح بـ متغير إذا مُرر
لمعامل ق ربط ق بنوع القيمة لا بـ متغير T (compiler/frontend/types/call_signature.sn). ويجوز لنسخة عامة
نوع نتيجتها فراغ أن تربط تلك النتيجة وتعيدها، كما في دع ن: R = د(); أرجع ن; حين يكون R هو فراغ: الربط لا
يحمل قيمة.
نوع زوج<أ, ب> = { الأول: أ, الثاني: ب };
عرف الرئيسية(): عدد {
دع الزوج: زوج<عدد, منطقي> = { الأول: 1, الثاني: صواب };
دع موجود: اختياري عدد = اختياري.موجود(3);
دع متداخل: متجه متجه عدد = [[1], [2, 3]];
أرجع الزوج.الأول + الطول(متداخل);
}
الاختياري والنتيجة
يحمل اختياري T قيمة أو لا شيء، ومنشئاه اختياري.موجود(س) واختياري.لا_شيء. أما نتيجة T, E فمنشئاه نجح
وخطأ. هذه الأسماء سياقية: فهي من الناحية المعجمية معرفات عادية، ولا تسمي النوع المدمج إلا في موضع نوع أو موضع منشئ، ولذلك
يجوز أن يُسمى متغير محلي اختيار أو نتيجة (tools/generate/registry/type_registry.def؛ وتُطابَق تهجئات المنشئات
في compiler/frontend/types/type_semantic_shape_queries.sn).
التهجئتان العربيتان القديمتان اختيار للنوع وبعض للمنشئ مرادفان مهملان. يسميان النوع والمنشئ نفسيهما، ويُحذَّر
من كل استعمال لهما مرة واحدة بـ SULTANC-SYNTAX-DEPRECATED-SPELLING.
الشرائح
الشريحة [] T عرض لا يملك ما يعرضه، وله تخطيط المتجه في الذاكرة. تُقبل قيمة أو موضع من نوع متجه T حيثما يُتوقع
[] T: وسيطًا في استدعاء، أو في تصريح شريحة أو إسناد إليها. ولا تُقبل قيمةً مُعادة. تعرض الشريحة مخزن المتجه دون
نسخ، ويبقى المتجه مالكًا له (هل_عرض_متجه_كشريحة، compiler/frontend/types/compatibility.sn). ويعامل SSF هذا العرض
على أنه استعارة مشتركة للمتغير المحلي الجذر الذي يحمل المتجه. فالمتجه الممرر وسيطًا ويُعرض كشريحة يُستعار طوال
الاستدعاء ولا يُنقل، والمتغير المحلي من نوع شريحة الذي يعرض موضع متجه يحمل استعارة مشتركة، فلا يمكن تغيير المتجه
ما دام العرض حيًّا. ويعيد MSIR تنميط ترويسة المتجه بـ نقل_تسلسل_مملوك.
تصريح الشريحة المهيأ من حرفي شريحة (دع ش: [] T = [...]) أو من نتيجة استدعاء يبني متجهًا أو يتلقاه، ويتلفه مالك
مجهول في الكتلة المحيطة عند نهايتها، كما يمدد Rust عمر القيمة المؤقتة. والأمر نفسه ينطبق على نتيجة استدعاء تُمرر
مباشرة وسيطًا من نوع شريحة. أما الشريحة التي يُسند إليها حرفي أو نتيجة استدعاء لاحقًا (ش := [...]) فلا تحتفظ
بمالك له، فيتسرب المخزن بدل أن يعيش العرض بعده.
تعابير حرفيات المتجهات
حرفي المتجه [أ, ب, ج] تعبير. يمكن أن يكون وسيطًا في استدعاء، أو قيمة مُعادة، أو حقل سجل، أو عنصرًا في حرفي آخر
([[1], [2, 3]])، أو قيمة مؤقتة مفهرسة ([أ, ب][ي])، أو معامَلًا لدالة قراءة بدائية (الطول([..])). ويحتفظ
دع م: T = [..]; بتعليمة التهيئة (تهيئة_متجه)، وهي تبني الشرائح أيضًا.
- التنميط. التنميط ثنائي الاتجاه كما في Rust وSwift. في سياق
متجه E(معامل، أو نوع مصرح به أو مُعاد، أو حقل، أو عنصر في حرفي خارجي) يُفحص كل عنصر مقابلE، ويكون[]من نوعمتجه E. وبدون هذا السياق يحدد العنصر الأولE، فيكون[1, 2]من نوعمتجه عدد، ويكون[]وحدهSULTANC-TYPE-MISMATCH(ابن_نوع_حرفي_متجه_داخلي،compiler/frontend/types/semantic_pipeline.sn). وفي أي سياق آخر يُقارن نوع الحرفي نفسه، فيكوند([1])معد(م: [] عدد)عدم تطابق لا عرض شريحة. - الملكية. كما في الحرفي المربوط بـ
دع. تُقيَّم العناصر من اليسار إلى اليمين وتُنقل إلى داخله (SSFطبق_آثار_تعبير_لتدفق)، ويحمل الحرفي كل استعارة تحملها عناصره (فإعادة[&محلي]هروب)، وحين يكون الحرفي وسيطًا فإن الاستعارات التي تأخذها عناصره مباشرة أو حمولاتٍ لمنشئات تعدادات تدوم طوال الاستدعاء وتتعارض مع وسائط الاستدعاء الأخرى (ابدأ_استعارة_حجة_مؤقتة). والاستعارة الممررة إلى استدعاء دالة خاص بعنصر ما تنتهي بانتهاء ذلك الاستدعاء. - الخفض. يصير الحرفي قيمة SSA واحدة من
تهيئة_متجه، وهي قيمة مؤقتة مملوكة جديدة مثل نتيجة الاستدعاء (هل_تعبير_طازج_للخفض،هل_أصل_مؤقت_للخفض). تُنقل إلى معامل أو وجهة مملوكة، وتُتلف بعد قراءة عنصر منها أو طولها. ويغطيهاtests/{ar,en}/language/surface/vector_literal_expressions.snوvector_literal_rss_flat.sn.
لا يحلل Stage0، المترجم الأولي (seed) المكتوب بلغة C، تعابير حرفيات المتجهات، ولذلك تحتفظ شيفرة المترجم ووحدات المكتبة
القياسية التي يستوردها المترجم بحرفيات مربوطة بـ دع.
الأنواع المعتمة
يعلن نوع T = معتم; (type T = opaque;) نوعا مسمى له هويته الخاصة، بلا حقول ولا حجم ولا محاذاة. وهو يمثل
بيانات لا تعرف تخطيطها إلا شيفرة أخرى (مكتبة سي عادة)، مثل sqlite3 وsqlite3_stmt. لا توجد في البرنامج قيمة
منه قط، وإنما يوجد مؤشر خام إليه.
عام نوع قاعدة_بيانات = معتم;
عام نوع عبارة = معتم;
عرف متساويتان(أ: *قاعدة_بيانات, ب: *قاعدة_بيانات): منطقي { أرجع أ == ب; }
عرف الرئيسية(): عدد {
دع لا_شيء_منها: *قاعدة_بيانات = 0 مثل *قاعدة_بيانات;
دع المقابض: متغير متجه *قاعدة_بيانات = [];
ألحق(المقابض, لا_شيء_منها);
إذا (متساويتان(المقابض[0], لا_شيء_منها)) { أرجع 0; };
أرجع 1;
}
معتم / opaque كلمة سياقية: لا تعلن نوعا معتما إلا إذا كانت الطرف الأيمن كله من تصريح نوع، وفي غير ذلك هي
معرف عادي، فيجوز أن يسمى محلي أو دالة أو حتى نوع معتم (هل_تعريف_معتم_حالي،
compiler/frontend/parser/declarations.sn). وحيث يكون نوع اسمه معتم / opaque مرئيا، كان نوع X = معتم;
مرادفا له، فيُرفض (SULTANC-TYPE-INVALID-DEFINITION بالسبب type.opaque-hides-visible-type) بدلا من أن يعلن نوعا
جديدا في صمت؛ أعد تسمية ذلك النوع، أو سمّه بالمرادف مرادف X = معتم;. ولا يأخذ النوع المعتم معاملات أنواع (SULTANC-TYPE-INVALID-DEFINITION).
ويتبع قواعد الظهور كأي نوع مسمى (عام والاستيراد)، ومرادفه (نوع مقبض = قاعدة_بيانات;) هو النوع نفسه.
الجائز:
*Tو*متغير T، و0 مثل *Tللمؤشر الفارغ؛==و!=بين مؤشرين إلى النوع المعتم نفسه؛- هذه المؤشرات معاملاتٍ ونواتجَ ومحلياتٍ وحقولَ سجلات وحمولاتِ تعدادات وعناصرَ متجهات؛
- التحويلات بقواعد كل مؤشر خام (تحويلات المؤشرات): إلى كلمة عنوان الهدف (
ط64، وط32على الأهداف ذات المؤشرات 32 بتا) بأمان، وداخلغير_آمنمن كلمة العنوان وإلى أي مؤشر خام آخر، ومنه*فراغو*متغير T.
المرفوض عند الترجمة:
| الاستعمال | التشخيص |
|---|---|
T بالقيمة: محلي أو حقل أو حمولة أو معامل أو ناتج أو قيمة عليا أو هدف تحويل أو &T، أو عنصر متجه أو اختياري أو صف أو حاوية أخرى؛ وقيمة حرفية من T |
SULTANC-TYPE-OPAQUE-BY-VALUE |
مثيل عام يحتاج تخطيط T (انظر أدناه) |
SULTANC-TYPE-OPAQUE-TYPE-ARGUMENT |
*م حيث م: *T، حتى داخل غير_آمن |
SULTANC-TYPE-OPAQUE-DEREFERENCE |
م.ح حيث م: *T |
SULTANC-TYPE-OPAQUE-FIELD-ACCESS |
م[ف] حيث م: *T (تخطو بحجم عنصر ليس لـ T) |
SULTANC-TYPE-OPAQUE-POINTER-ARITHMETIC |
م + 1، كما لكل مؤشر |
SULTANC-TYPE-MISMATCH |
*عبارة حيث يُتوقع *قاعدة_بيانات |
SULTANC-CALL-ARGUMENT-TYPE-MISMATCH (أو SULTANC-TYPE-MISMATCH) |
يجوز أن يكون النوع المعتم حجةَ نوع، مكتوبة (f<T>(...) وG<T>) أو مستنتجة (معامل *A أُعطي *T)، ما دام المثيل
لا يستعمله إلا عبر المؤشرات: فحص الفارغ والمقارنة ومتجهات *A وسجلات حقولها *A. ويُقضى في كل مثيل على أنواعه
المخصصة:
- لا يمرر توقيع النداء المخصص
Tولا يرجعه بالقيمة (تفحصه الواجهة عند النداء، واسم الدالة العامة سياق مرتبط)؛ - لا يحمل مثيل سجل أو تعداد عام
Tفي أعضائه إلا خلف مؤشر؛ - لا يستعمل الجسم المخصص، كما يخصصه التوحيد الشكلي (
أول_استعمال_معتم_في_مثيل،compiler/msir/lowering/monomorphization.sn)،Tبالقيمة: لا فك ولا نسخ، ولا&Tلـحجم_النوع/محاذاة_النوع، ولا محلي ولا متجه ولا حاوية منTتُبنى أو تُتلف.
والمخالفة SULTANC-TYPE-OPAQUE-TYPE-ARGUMENT عند النداء الذي بدأ التخصيص، ولو على عمق عدة نداءات عامة، والاستعمال
داخل الدالة العامة سياق مرتبط.
النموذج القانوني هو تعريف_نوع_مسمى.معتم بالشكل المسمى شكل_نوع_مسمى.معتم
(compiler/frontend/types/type_model.sn)، ويراه مستهلكو التمثيل صنف_شكل_نوع_دلالي.معتم. وقاعدة ألا يظهر النوع
المعتم إلا خلف * مباشرة هي استعمال_معتم_ممنوع_في_نوع (compiler/frontend/types/type_registry.sn). لا يعطي
التخطيط النوع المعتم نفسه تمثيل قيمة، و*T مؤشر عادي بعرض مؤشر الهدف، تعامله الخلفيات الأصلية وLLVM وMSIR
والمفسر معاملة *فراغ. وتصف معلومات التصحيح *T مؤشرا إلى نوع غير محدد (DWARF الأصلي) أو void * (LLVM).
ولا ينشئ التقييم وقت الترجمة مؤشرات خاما، معتمة أو غيرها (SULTANC-COMPTIME-PROHIBITED-EFFECT).
الاختبارات: tests/{ar,en}/language/opaque/ وtests/{ar,en}/target/opaque_pointers_32.sn.
التحويلات العددية
يحول س مثل T بين الأنواع السلمية (scalar). لا يقبل فاحص الأنواع تحويلًا بين نوعين سلميين إلا إذا وُجد
تحويل يجمعهما (تحويل_سلمي_مرفوض، compiler/frontend/types/compatibility.sn). وأي زوج آخر، مثل منطقي مثل عدد،
هو SULTANC-TYPE-MISMATCH عند التحويل، بالسبب type.invalid-cast. أما التحويلات التي تتضمن مراجع أو مؤشرات أو
متجهات بايتات فتُفحص في موضع خفضها. ويتحول المؤشر الخام إلى كلمة عنوانه ومنها (ط64 وص64 وعدد
وطبيعي، وط32 / ص32 على هدف مؤشراته 32 بتا فقط) وإلى أي مؤشر خام آخر (م مثل *فراغ وم مثل *متغير T)،
بعملية MSIR واحدة لكلمة العنوان (مرجع_إلى_مؤشر).
تحويلات المؤشرات
| التحويل | خارج غير_آمن |
|---|---|
النوع نفسه؛ مرجع إلى مؤشر خام؛ *متغير T إلى *T (إسقاط متغير) |
آمن |
مؤشر خام إلى كلمة عنوانه (م مثل ط64؛ وم مثل ط32 على أهداف 32 بتا) |
آمن |
الحرفي الصحيح 0 مكتوبا قبل مثل مباشرة (0 مثل *T، المؤشر الفارغ) |
آمن |
كلمة عنوان إلى مؤشر خام (ك مثل *T)، ومنه (0) مثل *T والصفر المسمى |
SULTANC-SAFETY-UNSAFE-OPERATION بالسبب safety.integer-to-raw-pointer |
مؤشر خام إلى نوع مشار آخر (*A مثل *B)، أو إلى *فراغ أو منه |
SULTANC-SAFETY-UNSAFE-OPERATION بالسبب safety.raw-pointer-other-pointee |
*T إلى *متغير T (إضافة متغير) |
SULTANC-SAFETY-UNSAFE-OPERATION بالسبب safety.raw-pointer-adds-mutable |
مؤشر خام إلى مرجع (م مثل &T) |
SULTANC-SAFETY-UNSAFE-OPERATION |
وإسقاط متغير ضمني أيضا: يُقبل *متغير T حيث يُتوقع *T للنوع T نفسه (حجةً، وفي دع ذي نوع، وفي الإرجاع، وفي
حقل سجل)، فيأخذ المعامل المخصص للقراءة مقبضا قابلا للكتابة بلا تحويل. أما العكس (*T حيث يُتوقع *متغير T) وأي
تغيير للنوع المشار إليه فيبقيان عدم تطابق في النوع. ويصدر الخفض إعادة تفسير كلمة العنوان نفسها التي يصدرها التحويل
الصريح.
التصنيف هو صنف_تحويل_بين (compiler/frontend/types/compatibility.sn)، وبوابة غير_آمن واستثناء الفارغ في
compiler/frontend/types/unsafe_operations.sn. ولا يُستثنى إلا الحرفي المجرد: الأقواس لا تترك عقدة نحوية، فتقرأ
البوابة البايت الذي يلي الحرفي، ويحتاج (0) مثل *T غير_آمن كالثابت المسمى. ولا تولد البوابة شفرة، ولا تتغير
عروض المؤشرات ولا واجهة سي الثنائية.
| من | إلى | النتيجة |
|---|---|---|
| عدد صحيح | عدد صحيح | اقتطاع أو توسيع بنظام المتمم الثنائي؛ يلتف ولا يتوقف أبدًا |
ط8 |
حرف |
نقطة الترميز |
حرف |
عدد صحيح بلا إشارة بعرض 32 بتًا أو أكثر | نقطة الترميز |
| فاصلة عائمة | عدد صحيح | يُبتر نحو الصفر ويُشبع عند حدود النوع؛ وNaN يعطي 0 |
| عدد صحيح | فاصلة عائمة | أقرب عدد عائم، وعند التساوي إلى الزوجي |
ع32 |
ع64 |
دقيق |
ع64 |
ع32 |
أقرب ع32، وعند التساوي إلى الزوجي؛ ما خرج عن المدى يعطي لانهاية؛ وNaN يبقى NaN |
تتبع تحويلات الفاصلة العائمة سلوك as في Rust (التحويل المشبع من عائم إلى صحيح، الذي حدده rust-lang/rust#71269)،
وهو أيضًا سلوك d2l في Java وiNN.trunc_sat_fMM غير المتوقف في WebAssembly. أما Go وC فتتركان نتيجة التحويل من
عائم خارج المدى إلى صحيح معرَّفة بحسب التنفيذ أو غير معرَّفة؛ والسلطان لا تفعل ذلك. والتقريب من صحيح إلى عائم هو
roundTiesToEven من IEEE 754، كما في Rust وGo وSwift وC.
عرف الرئيسية(): عدد {
دع صغير: ط8 = 200;
دع واسع: ط32 = (صغير مثل ط32) + 100;
دع ملتف: ط8 = (واسع مثل ط8); // يلتف 300 إلى 44
دع النسبة: ع64 = 7.9;
أرجع (النسبة مثل عدد) + (ملتف مثل عدد);
}
كل تحويلات الفاصلة العائمة عملية MSIR واحدة هي تحويل_عائم (compiler/msir/msir_model.sn)، وتحمل معلومة الإشارة
لطرف العدد الصحيح. وتخفضها كل خلفية على النحو الآتي:
- تستعمل الخلفية الأصلية لـ x86_64 التعليمتين
CVTTSD2SI/CVTTSS2SIبعد المقارنة بالحدود كأعداد عائمة (قوى دقيقة للعدد اثنين)، فلا ترى التعليمة إلا قيمًا داخل المدى. وقيمةط64فوق 2^63 يُطرح منها 2^63 ويُضبط البت 63. ويستعمل الاتجاه المعاكسCVTSI2SD/CVTSI2SS، مع تسلسل التنصيف اللاصق لقيمةط64فوق 2^63، وCVTSS2SD/CVTSD2SSبين عرضي الفاصلة العائمة. - تستعمل الخلفية الأصلية لـ arm64 التعليمتين
FCVTZS/FCVTZU، وهما تُشبعان أصلًا وتحولان NaN إلى 0، بعرض 32 و64 بتًا. أما النتائج بعرض 8 و16 بتًا فتُحصر أولًا بـFMIN/FMAX، وهما تحفظان NaN. وتستعملSCVTF/UCVTFوFCVTللاتجاه المعاكس وبين العرضين. - تستعمل الخلفية الأصلية لـ wasm32 التعليمات
iNN.trunc_sat_fMM_s/uوfMM.convert_iNN_s/uوf32.demote_f64وf64.promote_f32، مع الحصر نفسه بـmin/maxلعرضي 8 و16 بتًا. - تستعمل LLVM
llvm.fptosi.sat/llvm.fptoui.satوsitofp/uitofpوfpext/fptrunc. والأهداف ذات السجلات بعرض 32 بتًا كانت ستحوّل التحويلات بعرض 64 بتًا إلى استدعاءات compiler-rt (__aeabi_d2lz،__fixdfdi)، ولا يوفرها أي ربط في السلطان، ولذلك يبنيهاcompiler/backend/provider/llvm/wide_conversion.snمن تحويلات بعرض 32 بتًا وخطوات عائمة دقيقة، كما يفعلwide_division.snللقسمة بعرض 64 بتًا. ولا تملك AVR وMSP430 وحدة فاصلة عائمة (FPU)، فتستدعي ملفاتهما الكائنية إجراءات الفاصلة العائمة البرمجية (soft-float) المعتادة لكل عملية عائمة، ومنها التحويلات، وتوفرها سلسلة الأدوات التي تربطها. - يستعمل المفسر والتقييم وقت الترجمة حساب IEEE 754 البرمجي
(
compiler/interpreter/operations/float_software.sn). وثابت الوحدة مثلدع ك: عدد = 2.5 مثل عدد;يُطوى بالشيفرة نفسها، والنتيجة العائمة تُحفظ بنصها العشري الدقيق (نص_عشري_دقيق_من_بتات،compiler/msir/decimal_float_bits.sn).
أنماط بتات الأعداد العائمة متاحة عبر بتات_ع64 وع64_من_بتات وصيغ ع32 في
std.math.float، وهي مبنية على الدوال الجوهرية (intrinsics) لإعادة تفسير البتات في المترجم.
الحساب الملتف
تتوقف العمليات + و- و* و<< عند الفيض. أما الحساب الملتف، أي النتيجة بترديد 2^N، فتوفره أربع عمليات MSIR
(جمع_ملتف، طرح_ملتف، ضرب_ملتف، إزاحة_يسرى_ملتفة) تُخفض إلى تعليمة الآلة البسيطة في كل خلفية. ويُوصل إليها عبر
الدوال الجوهرية للمترجم بدائي_جمع_ملتف وبدائي_طرح_ملتف وبدائي_ضرب_ملتف وبدائي_إزاحة_يسرى_ملتفة
وبدائي_إزاحة_يمنى_ملتفة، ويشترك معاملاها في نوع صحيح واحد. وتأخذ الإزاحة مقدارها بترديد العرض، كما تفعل
wrapping_shl في Rust.
يعطي std.math.wrapping كل نوع صحيح صيغة ملتفة جمع_T_ملتف (ومثلها طرح_T_ملتف وضرب_T_ملتف
وإزاحة_يسرى_T_ملتفة وإزاحة_يمنى_T_ملتفة)، وصيغة متحققة جمع_T_متحقق تعيد اختياري، وصيغة مشبعة جمع_T_مشبع،
على نمط wrapping_* وchecked_* وsaturating_* في Rust.
عمليات الفاصلة العائمة
إلى جانب + - * / والمقارنات، فإن عمليات IEEE 754 التي يعرضها Rust توابعَ على f64 هي بدائيات في المترجم. كل منها
هوية_بدائي_مترجم.عملية_عائمة واحدة تحمل عملية_عائمة_بدائية، ومعاملاتها ونتيجتها من نوع الفاصلة العائمة للمعامل
الأول، ع32 أو ع64.
| العملية | الدالة الجوهرية | std.math.float | النتيجة |
|---|---|---|---|
| الجذر التربيعي | بدائي_جذر_تربيعي_عائم |
جذر_تربيعي64 |
مقرَّب تقريبًا صحيحًا (squareRoot في IEEE)؛ -0 يعطي -0، والمعامل السالب يعطي NaN |
| القيمة المطلقة | بدائي_قيمة_مطلقة_عائمة |
مطلق64 |
يمسح بت الإشارة، حتى في NaN |
| الأرضية والسقف والبتر | بدائي_أرضية_عائمة, بدائي_سقف_عائم, بدائي_بتر_عائم |
أرضية64, سقف64, بتر64 |
دقيقة؛ والنتيجة الصفرية تحتفظ بإشارة المعامل |
| التقريب إلى الأقرب، وعند التساوي إلى الزوجي | بدائي_تقريب_زوجي_عائم |
تقريب_زوجي64 |
دقيق (roundToIntegralTiesToEven) |
| الأدنى والأقصى | بدائي_أدنى_عائم, بدائي_أقصى_عائم |
أصغر64, أكبر64 |
الأدنى والأقصى في IEEE 754-2019: المعامل NaN يعطي NaN، و-0 < +0 |
| نسخ الإشارة | بدائي_نسخ_إشارة_عائمة |
نسخ_إشارة64 |
مقدار المعامل الأول بإشارة الثاني |
| الضرب والجمع المدمج | بدائي_ضرب_جمع_مدمج_عائم |
ضرب_جمع_مدمج64 |
a * b + c بتقريب واحد |
وصيغ ع32 موجودة أيضًا. تنتج كل الخلفيات البتات نفسها: الخلفيات الأصلية وLLVM تخفض كل عملية إلى تعليمة الهدف (انظر
MSIR وتوليد الشيفرة)، والمفسر يحسبها بدقة على البتات. وحيث لا يملك طقم التعليمات
الأساسي للهدف تقريبًا إلى عدد صحيح (فـ x86-64 الأساسي لا يملك ROUNDSD) أو لا يملك الضرب والجمع المدمج، تختار
std.math صيغة دقيقة على مستوى البتات بحسب المعمارية بدل البدائية، كما تفعل libm في Rust، فلا حاجة أبدًا إلى استدعاء
libm. وحمولة نتيجة NaN وإشارتها غير محددتين، كما في Rust؛ أما مطلق64 ونسخ_إشارة64 فلا يحركان إلا بت الإشارة.
النفي والحساب على الثوابت
يُطبَّق السالب الأحادي على الأعداد الصحيحة ذات الإشارة وعلى الأعداد العائمة. وهو على العدد العائم نفي IEEE، أي
-0.0 - س، فيكون -س لـ +0.0 هو -0.0. وعلى قيمة من نوع بلا إشارة (طبيعي، ط8…ط64) يكون
SULTANC-TYPE-MISMATCH بالسبب type.unsigned-negation، مثل E0600 في Rust، داخل الدالة وفي ثابت الوحدة على حد سواء.
ويحتفظ الحرفي العددي الصحيح بفحص قيمته الخاص، فـ -0 يناسب النوع بلا إشارة و-1 خارج المدى. اطرح بدلًا من ذلك، أو
حوّل إلى نوع بإشارة أولًا.
يُقيَّم ثابت الوحدة وقت الترجمة بدلالات وقت التشغيل. والعملية التي كانت ستتوقف وقت التشغيل (فيض عدد صحيح، أو قسمة أو
باقٍ على صفر، أو قسمة الحد الأدنى ذي الإشارة على -1، أو إزاحة بمقدار العرض أو أكثر) تكون
SULTANC-COMPTIME-EVALUATION-FAILED بالسبب comptime.execution-trapped، كما يكون E0080 في Rust لـ const. والثابت
الذي نوعه المصرح به أوسع من نوع تعبيره، مثل دع ك: عدد = (250 مثل ط8) + 3;، توسيع يقبله فاحص الأنواع، ويحمل الثابت
العدد نفسه بالنوع المصرح به.
قواعد الالتقاط في الخيوط
الدالة المغلقة (closure) المسلَّمة إلى خيط آخر لا يجوز أن تلتقط إلا قيمًا آمنًا إرسالها إليه، وهو الدور الذي يؤديه قيد
F: Send + 'static في Rust على std::thread::spawn. ولا توجد سمات (traits) في السلطان، فتفحص الواجهة الأمامية حرفي
الدالة المغلقة عند الاستدعاء (compiler/frontend/types/thread_capture.sn، ويعمل بعد فحص غير الآمن وقبل SSF).
| الملتقَط | الحكم | التشخيص |
|---|---|---|
قيمة يحمل نوعها مؤشرًا خامًا (*T، *متغير T، في أي موضع داخل السجلات أو التعدادات أو الصفوف أو الاختياريات أو النتائج أو المتجهات أو الصناديق) |
مرفوضة، إلا إذا كان الاستدعاء الذي يسلم الدالة المغلقة داخل غير_آمن (يضمن المبرمج تزامن ما يشير إليه المؤشر، كما في unsafe impl Send) |
SULTANC-THREAD-CAPTURE-RAW-POINTER |
قيمة يحمل نوعها مرجعًا مستعارًا أو شريحة (&T، &متغير T، [] T) |
مرفوضة: قد يعيش الخيط أطول من التخزين المستعار ('static) |
SULTANC-THREAD-CAPTURE-REFERENCE |
| متغير وحدة قابل للكتابة مذكور في جسم الدالة المغلقة، خارج كتلة غير آمنة في ذلك الجسم | مرفوض: تتشاركه كل الخيوط، وقراءاته وكتاباته ليست ذرية (static mut في Rust) |
SULTANC-THREAD-CAPTURE-NON-ATOMIC-SHARED |
القيم البسيطة (الأعداد، والسجلات المكونة منها)، والقيم المملوكة (تُنقل إلى الدالة المغلقة)، وقيم الدوال ومقابض std.sync المبنية عليها (مشترك، أي Arc في Rust، وعدّاده ذري)، ومعاملات الأنواع |
مقبولة | لا شيء |
يذكر كل تشخيص الرمز الملتقَط ونوعه عند أول استعمال له في الدالة المغلقة، بالعربية والإنجليزية (iSpeak).
الاستدعاءات التي ترسل دالة مغلقة تُستنتج ولا تُسرد. فالمعاملات ذات أنواع الدوال في دالة تستدعي دالة جوهرية لعنوان
الدالة المغلقة (بدائي_عنوان_دالة، بدائي_مدخل_سي_لدالة، وبهما تسلم std.thread الدالة المغلقة إلى خيط جديد في كل
نظام تشغيل) معاملات مرسِلة، والمعامل الذي تمرره دالة إلى معامل مرسِل مرسِلٌ أيضًا، حتى نقطة ثابتة (fixpoint) على كل
الوحدات. وحين لا تذكر أي وحدة تلك الدوال الجوهرية، كما في المترجم نفسه وفي معظم البرامج، لا يفعل هذا الفحص شيئًا.
وانظر التزامن للجانب الذي يراه المستخدم.
مسؤوليات طبقة الأنواع
تملك طبقة الأنواع الهوية القانونية للأنواع، وبيانات الأنواع المدمجة الوصفية، وإنشاء الأنواع وتوحيد نسخها (interning)، وتحليل الأنواع المسماة، والتساوي والتوافق، وتصنيف التحويلات، والاستعلامات عن السلمية والإشارة، وفحوص ملاءمة الحرفيات العددية الصحيحة، والشكل الدلالي للنوع المعروض على المستهلكين اللاحقين. ويسأل المستهلكون هذه الواجهات عن حقائق الأنواع بدل إعادة بنائها من شجرة الصياغة المجردة (AST) أو من التهجئة في الشيفرة.
هوية النوع منفصلة عن تمثيله الفعلي وعن اصطلاح الاستدعاء في الآلة. فنظام الأنواع لا يقرر تقطيع الشيفرة إلى رموز ولا القواعد النحوية، ولا البحث عن الوحدات والأسماء، ولا مشروعية الاستعارة والأعمار، ولا اختيار هدف الترجمة، ولا إزاحات الحقول الفعلية أو محاذاتها، ولا مواضع الوسائط والقيم المعادة في الواجهة الثنائية (ABI)، ولا تخصيص السجلات، ولا صيغة الملف الكائني، ولا ترميز التعليمات. فتلك حقائق تنتمي إلى طبقات الواجهة الأمامية والتخطيط والهدف والواجهة الثنائية والخلفية.
بعد تحليل الأنواع، تستعلم الطبقات المدركة للهدف عن شكل النوع وتجمعه مع نموذج البيانات للهدف المختار:
semantic Type ID
|
+--> safety / semantic queries
|
+--> layout + target data model
|
+--> ABI
+--> native code generation
يبقى معنى النوع محايدًا تجاه الهدف، بينما يختلف تمثيله الفعلي بحسب الهدف حيث يلزم ذلك.
حجج النوع الصريحة
د<أ, ب>(..) يربط معاملات نوع المستدعى المعلنة بترتيبها قبل الاستنتاج من الحجج والناتج المتوقع: فارغ<ط8>() (معامل
لا يستعمله إلا الناتج)، وهو<ط8>(30) (تُنوَّع الحجة ط8). وبعد اسم مستدعى أو اسم مؤهل لا يبدأ < حجج نوع إلا إذا
تبعته قائمة أنواع ثم > ثم (؛ وإلا فهو المقارنة. والعدد الخاطئ SULTANC-CALL-ARGUMENT-COUNT-MISMATCH. يغلف المحلل
المستدعى (تعبير.حجج_نوع بنطاق المستدعى نفسه)، وتبذر طبقة الأنواع استبدالات الاستدعاء
(استبدالات_حجج_نوع_صريحة_داخلي). ويغطيه tests/*/language/surface/explicit_type_arguments.sn.
الملفات المضمنة
ضمن_ملف(«مسار») (embed_file("path")) بايتات الملف حرفيَّ نص يُقرأ عند تحليل المصدر؛ ويُحل المسار النسبي من
مجلد الملف المصدر. والملف الذي لا يُقرأ SULTANC-PARSE-SYNTAX (parser.embed-file-unreadable). ويغطيه
tests/*/language/surface/embed_file.sn.
القيود
- الشريحة التي يُسند إليها حرفي أو نتيجة استدعاء بعد تصريحها (
ش := [...]) لا تملك شيئًا، فيتسرب المخزن. []بلا عنصر وبلا سياق متجه عدم تطابق في الأنواع.- الدالة المغلقة الممررة عبر متغير بدل حرفي لا يفحصها فحص الالتقاط في الخيوط، والدالة المغلقة الملتقَطة معتمة (لا
تُتتبع التقاطاتها هي)، ومتغير الوحدة القابل للكتابة الذي يُوصل إليه عبر استدعاء داخل الدالة المغلقة لا يُرى. أما Rust
فيتتبع الثلاثة عبر السمات التلقائية (auto traits) وقواعد
static. - النوع الذي لم يُثبَّت تخطيطه الفعلي عمدًا (النصوص والمتجهات والشرائح وقيم الدوال) ليس له حجم ولا محاذاة؛ وطلب أحدهما وقت الترجمة تشخيص (التقييم وقت الترجمة).