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

البدء

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

البدء

يأخذك هذا الدليل من نسخة من المستودع إلى برنامج يعمل. يتناول بناء المترجم، وكتابة أول برنامج، وترجمته وتفسيره وفحصه، والترجمة لمنصات أخرى (cross-compiling)، وخلفية LLVM، ولغة رسائل التشخيص وصيغتها. يفترض الدليل أنك معتاد على سطر الأوامر وعلى لغة ذات أنواع ثابتة مثل Rust أو Go أو C.

بناء المترجم

السلطان مستضافة ذاتيا (self-hosted): المترجم مكتوب بلغة السلطان ويبني نفسه على مراحل. يبدأ البناء من seed صغير (Stage0)، ويُستخدم لبناء Stage1، ثم يُستخدم Stage1 لبناء المترجم النهائي Stage2. يتولى build.sh تشغيل كل المراحل عبر CMake.

git clone https://github.com/sultan-language/sultanc.git
cd sultanc
./build.sh

المترجم النهائي هو build/sultanc. وتبقى نواتج المراحل في build/bootstrap/cmake/bin (وcmake-wasm/bin عند استخدام seed الخاص بـ WebAssembly). انسخ build/sultanc إلى أي مجلد ضمن PATH، أو شغّله من مكانه.

يمكن أن يأتي الـ seed من ثلاثة مصادر، تختار بينها بالخيار --bootstrap:

الطريق الأمر المتطلبات
seed بلغة C (الافتراضي) ./build.sh مترجم C وLLVM
seed الخاص بـ WebAssembly ./build.sh --bootstrap=wasm مترجم C فقط
مترجم موجود مسبقا ./build.sh --bootstrap=existing نسخة مبنية من build/sultanc، أو نسخة تحددها بـ --with=PATH

ينفذ طريق المترجم الموجود خطوة استضافة ذاتية واحدة ويستغرق نحو دقيقة، ولذلك فهو الحلقة السريعة أثناء التطوير. استخدم طريق C أو WebAssembly على نظام جديد، وعندما يكون المترجم الموجود أقدم من أن يترجم المصادر، وعند التحقق من إصدار.

افتراضيا لا يحتوي المترجم النهائي إلا على الخلفية الأصلية (Native)، ولا يعتمد على libLLVM. أضف --enable-llvm لتضمين خلفية LLVM فيه (انظر خلفية LLVM). يستخدم seed بلغة C خلفية LLVM دائما، ولذلك يجب تثبيت LLVM من الإصدار 19 إلى 23 للطريق الافتراضي. على macOS مع Homebrew، وجّه البناء إليه أولا:

export LLVM_CONFIG="$(brew --prefix llvm)/bin/llvm-config"

اختر نسخة LLVM أخرى بـ LLVM_CONFIG=/path/to/llvm-config، أو بـ -DLLVM_DIR عند البناء المباشر عبر CMake.

بقية وسائط build.sh تسمّي مرحلة أو فحصا:

الوسيط الأثر
stage0، stage1، stage2 البناء حتى تلك المرحلة.
bootstrap بناء Stage0 وStage1 فقط.
verify بناء Stage2، ثم التحقق من أن Stage3 وStage4 متطابقان بايتا ببايت. ومع --enable-llvm يتحقق أيضا من تقارب LLVM.
--target=TRIPLE البناء لهدف آخر.
--backend=native|llvm الخلفية التي يستخدمها Stage1 لتوليد Stage2 (الافتراضية native).
OUTPUT المكان الذي يُنسخ إليه المترجم النهائي.

لا توجد الخلفية الأصلية على Windows. ابنِ هناك بالأمر ./build.sh --bootstrap=c --enable-llvm --backend=llvm.

أين يبحث المترجم عن المكتبة القياسية

يعرف المترجم المكتبة القياسية (الحزمة std، وبالعربية المكتبة) ويجدها من بنيتها كما يجد rustc جذر نظامه: يأخذ أول دليل مكتبة مما يلي فيه مجلد std/، وملف جذره std/std.sn يعلن تهجئات وحدات المكتبة (انظر تهجئات الوحدات):

  1. $SULTANC_STD، وهو مجلد المكتبة نفسه (إذا كان معرّفا فإنه يُستخدم حتى إذا كان خاطئا، كي تذكره رسالة الخطأ)؛
  2. المجلد library/ في المجلد الحالي (جذر المستودع)؛
  3. بجوار المترجم: <bin>/library، و<bin>/../library (كما هو حال build/sultanc في نسخة من المستودع)، و <bin>/../lib/sultanc/library (بادئة تثبيت، <prefix>/bin/sultanc).

لا يُخلط بين مجلد library/ الخاص بمشروع ما وبين المكتبة القياسية. وإن لم يوجد أي منها فالخطأ هو SULTANC-STD-NOT-FOUND.

المشاريع ذات الاعتماديات: استعمل سوباكس

يترجم sultanc الملفات المعطاة له واستيراداتها النسبية والمكتبة القياسية، ولا يقرأ أي Supax.toml. داخل مشروع سوباكس شغّل supax check أو supax build أو supax run: يحل سوباكس الاعتماديات ويمرر للمترجم رسم حزم (--package-graph). أما sultanc check src/main.sn وحده في مشروع كهذا فلا يرى اعتمادياته ولا اسم الحزمة نفسها.

يمكن تسمية الملف المصدري بمسار نسبي (بما في ذلك ..) أو بمسار مطلق. المصادر النسبية الواقعة تحت مجلد العمل تُنسب إليه، وغيرها يُنسب إلى المجلد المشترك بينها. ويبقى الجذر الذي تبلغه المصادر النسبية نسبيا (.)، فتُقرأ الوحدات بمسارات نسبية ولا تتوقف النتيجة على كيفية إبلاغ المضيف عن مجلد العمل. على Windows يفصل كل من \ و/ بين مكونات المسار، وأحرف الأقراص جذور.

أول برنامج

يقرأ السلطان الملفات المصدرية ذات الامتداد .sn. دالة الدخول اسمها main بالإنجليزية والرئيسية بالعربية. وهي ترجع عدد، تصبح قيمته حالة خروج العملية. الكتابتان قابلتان للتبادل في كل موضع، ويمكن أن يجمع الملف الواحد بينهما.

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

عرف الرئيسية(): عدد {
    اطبع_سطر("مرحبا من السلطان");
    دع الجواب: عدد = 6 * 7;
    اطبع_سطر(عدد_إلى_نص(الجواب));
    أرجع 0;
}

يستورد السطران الأولان وحدتين من المكتبة القياسية. توفر المكتبة.دخ.println الدالة اطبع_سطر، وتوفر المكتبة.نصوص.number الدالة عدد_إلى_نص. تنتهي الجمل بفاصلة منقوطة، وكذلك الكتلة المستخدمة جملةً، مثل إذا. البرنامج موجود في المستودع باسم examples/ar/basics/hello.sn، ونسخته الإنجليزية باسم examples/ar/basics/hello.sn.

الترجمة والتشغيل

مرّر الملف المصدري، ومسار الإخراج إن أردت:

sultanc examples/ar/basics/hello.sn -o hello
./hello
Hello from SultanC
42

بدون -o يأخذ الملف التنفيذي الاسم الأساسي للملف المصدري. الناتج الافتراضي ملف تنفيذي أصلي للمضيف. وتُختار النواتج الأخرى بـ --emit:

القيمة الناتج
exe ملف تنفيذي (الافتراضي)
obj ملف كائن قابل لإعادة التموضع (relocatable object)، والصيغة المختصرة -c
asm نص بلغة التجميع
llvm-ir نص LLVM IR بعد التحسين (خلفية LLVM)

تُقبل أيضا القيم shared وreloc وmodule. وقدرة الهدف والخلفية على إنتاجها تختلف، ويبلّغ المترجم SULTANC-LINK-OUTPUT-UNSUPPORTED عندما لا يستطيعان.

لربط مكتبة C، مرّر -l name للمكتبة libname، و-L dir لإضافة مجلد إلى البحث قبل المواضع القياسية. ولا يربط البناء إلا المكتبات المسماة، ومنها مكتبة C نفسها: فالدالة الخارجية من C مثل labs تحتاج -l c.

التشغيل بالمفسر

ينفذ sultanc run البرنامج دون إنتاج ملف:

sultanc run examples/ar/basics/hello.sn

يشغّل المفسر التمثيل الوسيط المتحقق منه نفسه (MSIR) ومصادر المكتبة القياسية نفسها التي يستخدمها المترجم، فيتصرف البرنامج بالطريقة نفسها تحت run وكملف تنفيذي. الوسائط التي تأتي بعد الملف المصدري تُمرَّر إلى البرنامج دون تغيير. وهو أسرع طريقة لتجربة مقتطف من الشيفرة، ويعمل على Linux وmacOS وWindows وFreeBSD. انظر المفسر لمعرفة طريقة عمله.

يعني الخياران -l و-L مع run (وinterpret) ما يعنيانه في البناء، ويُكتبان قبل الملف المصدري؛ أما بعده فهما من وسائط البرنامج نفسه (sultanc run app.sn -l x يمرر -l x إلى app.sn):

sultanc run -l sqlite3 app.sn
sultanc run -L vendor/lib -l mylib app.sn

يُبحث عن كل -l name كما يُبحث عنه في البناء (مجلدات -L ثم مجلدات الهدف)، وتُحمَّل المكتبة المشتركة الموجودة في البرنامج أثناء عمله؛ أما البرنامج الذي لا تعمل دوال C فيه إلا من ملف تنفيذي فيربطها. والخياران -l c و-l m مستوفيان دائما، لأن عملية المفسر توفر مكتبة C ومكتبة الرياضيات أصلا. والمكتبة التي لا توجد إلا أرشيفا ساكنا (libname.a) تُربط حين يعمل البرنامج ملفا تنفيذيا (مترجم بلا محمّل ديناميكي، أو شيفرة C لا يستطيع المفسر نداءها)؛ أما حين يشغّله المفسر، وهو لا يحمّل إلا المكتبات المشتركة، فيبلَّغ عنها بالتشخيص SULTANC-RUN-LIBRARY-STATIC-ONLY. ولا يغيّر الأرشيف طريقة تشغيل البرنامج أبدا. وعلى macOS يحمّل الملف النصي libname.tbd مكتبة dylib التي يسميها (والتشخيص SULTANC-RUN-LIBRARY-NO-INSTALL-NAME إن لم يسمّ شيئا)؛ وعلى Windows يحمّل -l name الملف name.dll من أحد مجلدات -L، أو عبر بحث النظام عن ملفات DLL.

يوفر run دائما مكتبة C ومكتبة الرياضيات للبرنامج، فالدالة الخارجية من C التي تعمل تحت run قد تحتاج مع ذلك -l c (أو -l m) حين يُبنى البرنامج.

الفحص دون بناء

يحلل sultanc check الشيفرة، ويحل الأسماء، ويفحص الأنواع، ويجري تحليل الملكية والاستعارة، ثم يتوقف قبل توليد الشيفرة:

sultanc check src/main.sn
sultanc check --target wasm32-wasi src/main.sn

يخرج بالحالة 0 عندما يُقبل البرنامج، وبالحالة 1 عندما تبلّغ رسائل التشخيص عن خطأ. ومع --target يجري الفحص لذلك الهدف، وهذا مهم للشيفرة التي تعتمد على المنصة. وبدونه يُفترض أن الهدف هو المضيف.

الاختبار

الدالة الموسومة بـ@@اختبار (@@test) اختبار. يبني sultanc test اختبارات البرنامج ويشغّل كلا منها في عملية مستقلة، ثم يطبع ملخصا:

sultanc test src/main.sn
sultanc test --filter حلل src/main.sn
sultanc test --list src/main.sn

ويخرج بالحالة 0 إذا نجحت كل الاختبارات، و1 إذا فشل أحدها، و2 إذا تعذر بناء الاختبارات. ولا يشغّل البناء العادي اختبارا أبدا. وفي الاختبار التفاصيل.

الترجمة لمنصات أخرى

يختار --target (-t) ثلاثية الهدف (target triple)، وينتج المترجم ملفا تنفيذيا لها دون أي إعداد إضافي:

sultanc --target=aarch64-linux-gnu examples/ar/basics/hello.sn -o hello-arm
sultanc --target=x86_64-windows-msvc examples/ar/basics/hello.sn -o hello.exe
sultanc --target=wasm32-wasi examples/ar/basics/hello.sn -o hello.wasm

يعرض sultanc targets كل هدف مسجل مع معماريته ونظام تشغيله وصيغة ملف الكائن ومستوى دعمه. للمترجم روابط (linkers) خاصة به لصيغة ELF على Linux بمعماريتي x86_64 وaarch64، ولـ Mach-O وCOFF وWebAssembly. أما أهداف ELF الأخرى على Linux وFreeBSD فتُربط بـ ld.lld، ويمكنك استبداله بمتغير البيئة SULTANC_LINKER. الملفات التنفيذية على Linux وFreeBSD ثابتة الربط (static) ولا تستخدم libc. ويبيّن مرجع الأهداف ما يدعمه كل هدف حاليا.

خلفية LLVM

يوجد مولدان للشيفرة. تولّد الخلفية الأصلية شيفرة x86_64 وarm64 وwasm32 مباشرة. وتغطي خلفية LLVM كل الأهداف وتحسّن الشيفرة بمستوى O2. يطبع sultanc targets الخلفيات التي يحتويها مترجمك. اختر إحداها بـ -b أو --backend:

sultanc --backend=llvm examples/ar/basics/hello.sn -o hello
sultanc --backend=llvm --target=riscv64-linux-gnu examples/ar/basics/hello.sn -o hello-rv
sultanc --backend=llvm --emit=llvm-ir examples/ar/basics/hello.sn -o hello.ll

المترجم المبني بدون --enable-llvm لا يحتوي إلا على الخلفية الأصلية. انظر MSIR وتوليد الشيفرة لمعرفة كيف تستهلك الخلفيتان التمثيل الوسيط نفسه.

رسائل التشخيص

لكل رسالة تشخيص هوية ثابتة على الصورة SULTANC-<AREA>-<NAME>، ونص رسالة، ومواضع المصدر المعنية. تُكتب رسائل التشخيص بالعربية افتراضيا. ويختار --lang اللغة: ar أو en أو auto الذي يتبع إعدادات اللغة والمنطقة (locale) في المضيف.

إذا احتوى الملف bad.sn على:

عرف الرئيسية(): عدد {
    دع س: عدد = "نص";
    أرجع 0;
}

فإن:

sultanc check bad.sn

يكتب:

خطأ[SULTANC-TYPE-MISMATCH]: النوع الموجود ⁨`نص`⁩ لا يطابق النوع المتوقع ⁨`عدد`⁩ — القيمة لا تطابق النوع المصرح به لوجهتها.
  --> bad.sn:2:17..2:21
   |
 2 |     دع س: عدد = "نص";
   |                 ^^^^
   |

تُحاط الأسماء المقتبسة بعوازل الاتجاه الثنائي في Unicode (bidirectional isolates)، كي يحتفظ المعرّف اللاتيني داخل النص العربي باتجاهه. ويختار --diagnostic-format طريقة كتابة رسائل التشخيص:

الصيغة الناتج
human مقتطف المصدر المشروح المعروض أعلاه (الافتراضي)
short سطر واحد لكل رسالة تشخيص: file:line:column: severity[ID]: message [reason]
json كائن JSON واحد لكل رسالة تشخيص، للمحررات والأدوات

تحمل رسالة التشخيص بصيغة JSON إصدار المخطط، واللغة، والهوية، ودرجة الخطورة، ونص الرسالة، والمدى الأساسي مع الملف وإزاحات البايت والسطر والعمود، ووسائط الرسالة باللغتين. ويقبل --color القيم auto وalways وnever.

يشرح sultanc explain هوية رسالة تشخيص، باللغة التي يختارها --lang:

sultanc --lang=en explain SULTANC-OWNERSHIP-USE-AFTER-MOVE
SULTANC-OWNERSHIP-USE-AFTER-MOVE

Value used after move. Find the move in the related spans.

البرنامج الذي ينتهي بخطأ أو بانهيار أو بتأكيد فاشل يطبع إطاره الخاص على الخرج القياسي للأخطاء، بلغة بيئة البرنامج (SULTANC_LANG، ثم LC_ALL وLC_MESSAGES وLANG، ثم قيمة --lang التي تُرجم بها). وتصف صفحة الأخطاء هذا المسار.

إلى أين بعد ذلك

انظر أيضا