ترجمهی شرطی
گاهی کد باید روی ویندوز، مک و لینوکس کمی فرق کند، یا نسخهی اشکالزدایی با نسخهی نهایی. سلام این انتخاب را در زمان ترجمه انجام میدهد؛ شاخهای که به کار نمیآید اصلاً وارد برنامه نمیشود و هیچ هزینهای در زمان اجرا ندارد.
اگر در زمان ترجمه
اگر در سطح بالای پرونده، با شرطی که هنگام ترجمه معلوم است، فقط شاخهی درست را نگه میدارد. هر چه درون آن تعریف شود، از ثابت و متغیر سراسری گرفته تا بلوک درونداد و تابع، فقط روی سیستمی وجود دارد که آن شاخه برایش انتخاب شده است. در این نمونه هر سیستم جداکنندهی مسیر خودش را میگیرد و باقی برنامه بیآنکه بداند کجا اجرا میشود از جداکننده استفاده میکند:
واردسازی رشته
اگر سلام سیستم ویندوز:
پایا جداکننده := "\\"
وگرنه:
پایا جداکننده := "/"
پایان
تابع ریشه:
مسیر := "home" + جداکننده + "sara" + جداکننده + "notes.txt"
تکهها := رشته.تفکیک کردن(مسیر، جداکننده)
دیرکن تکهها.آزادکن()
سرچاپ تکهها.طول()، "تکه"
سرچاپ تکهها.بگیر(۲)
پایانشرط اگر سطح بالا باید چیزی باشد که مترجم خودش بتواند حساب کند. نوشتن اگر شمار > ۳: در سطح بالا خطای «top-level if condition must be a compile-time constant» میدهد.
پرچمهای آماده
مترجم چند پرچم منطقی تعریف میکند که سیستم مقصد را توصیف میکنند. یک پرچم سیستمعامل و یک پرچم پردازنده درست است، به اضافهی پرچمهای خانواده: لینوکس و مک سلام سیستم یونیکس را هم روشن میکنند، اندروید سلام سیستم لینوکس را هم، و مک و بیاسدیها سلام سیستم بیاسدی را. در برنامهی فارسی باید نام فارسی را بنویسید؛ نام انگلیسی در پروندهی فارسی شناخته نمیشود و پیام خطا نام فارسیاش را پیشنهاد میدهد.
| پرچم | نام انگلیسی | درست است وقتی برای این ساخته شود |
|---|---|---|
سلام سیستم ویندوز | SALAM_OS_WINDOWS | ویندوز، همراه با سلام سیستم ویندوز۶۴ یا سلام سیستم ویندوز۳۲ |
سلام سیستم لینوکس | SALAM_OS_LINUX | لینوکس و اندروید |
سلام سیستم مک | SALAM_OS_MAC | مک |
سلام سیستم اندروید | SALAM_OS_ANDROID | اندروید |
سلام سیستم فریبیاسدی، سلام سیستم اوپنبیاسدی، سلام سیستم نتبیاسدی | SALAM_OS_FREEBSD، SALAM_OS_OPENBSD، SALAM_OS_NETBSD | هر کدام از بیاسدیها |
سلام سیستم بیاسدی | SALAM_OS_BSD | مک و بیاسدیها |
سلام سیستم یونیکس | SALAM_OS_UNIX | همهی سیستمهای شبهیونیکس، وباسمبلی هم |
سلام سیستم وباسمبلی | SALAM_OS_WASM | وباسمبلی |
سلام معماری ایکس۶۴، سلام معماری ایکس۸۶ | SALAM_ARCH_X64، SALAM_ARCH_X86 | اینتل و ایامدی ۶۴ و ۳۲ بیتی |
سلام معماری آرم۶۴، سلام معماری آرم | SALAM_ARCH_ARM64، SALAM_ARCH_ARM | آرم ۶۴ و ۳۲ بیتی |
سلام معماری ریسکوی۶۴ | SALAM_ARCH_RISCV64 | ریسکوی ۶۴ بیتی |
سلام معماری وباسمبلی | SALAM_ARCH_WASM | وباسمبلی |
سلام ایمن | SALAM_SAFE | هر ساختی که بدون --release باشد |
چند نام دیگر به جای درست و نادرست مقدار دارند. سلام سیستم متنی است مثل "windows"، "linux"، "mac"، "android" یا "freebsd"، و سلام معماری یکی از "x64"، "x86"، "arm64"، "arm"، "riscv64" یا "wasm". این مقدارها همیشه انگلیسیاند. برنامهای که به جاوااسکریپت ترجمه میشود (salam js و اسکریپتهای صفحه) برای هر دو "js" میگیرد و همهی پرچمهای سیستم و معماری در آن نادرست است، چون همان کد در هر مرورگری یا در Node اجرا میشود. سلام نگارش نگارش مترجم به شکل متن است، مثلاً "0.5.0"، و سلام کد نگارش همان نگارش به شکل عدد، 500. فهرست کامل این نامها در واژهنامه آمده است.
درون تابع
همین اگر درون بدنهی تابع هم کار میکند. وقتی شرط فقط از این پرچمها ساخته شده باشد، مترجم شاخهی درست را نگه میدارد و بقیه را دور میریزد، درست مثل سطح بالا. با وگرنهی شرطدار میشود سیستمها را پشت هم آورد:
تابع پوشه تنظیمات(برنامه: رشته): رشته:
اگر سلام سیستم ویندوز:
برگشت "C:\\Users\\Public\\AppData\\" + برنامه
وگرنه سلام سیستم مک:
برگشت "/Users/Shared/Library/Application Support/" + برنامه
وگرنه:
برگشت "/etc/" + برنامه
پایان
پایان
تابع ریشه:
سرچاپ پوشه تنظیمات("salam")
اگر سلام سیستم یونیکس:
سرچاپ "دسترسی: chmod 600"
پایان
پایانشاخههای سیستمعامل را همیشه با وگرنه ببندید. تابعی که اگر سلام سیستم ویندوز: برگشت ... پایان مینویسد و بعد کد یونیکس را ادامه میدهد روی لینوکس بیمشکل ساخته میشود، اما روی ویندوز آن اگر به «همیشه برگرد» تبدیل میشود و کد بعدش خطای E070، کد دستنیافتنی، میگیرد. با وگرنه هر دو ساخت تمیزند.
شاخهای که نگه داشته میشود بلوک جداگانهای نیست و هر چه درونش تعریف شود پس از اگر هم دیده میشود. میتوانید در شاخهی ویندوز کاربر := "USERNAME" و در شاخهی دیگر کاربر := "USER" بنویسید و پایینتر از کاربر استفاده کنید.
پرچمها بهعنوان مقدار معمولی
بیرون از اگر این نامها ثابتهای معمولیاند. میشود چاپشان کرد، در متغیر نگهشان داشت، در ترابرد به کارشان برد یا با شرطی که در زمان اجرا سنجیده میشود ترکیبشان کرد، مثل اگر سلام سیستم ویندوز و تلاشها > ۰: که فقط نیمهی دومش برای زمان اجرا میماند:
تابع خانواده(): رشته:
ترابرد سلام سیستم:
"linux"، "android":
برگشت "لینوکس"
پایان
"mac"، "freebsd"، "openbsd"، "netbsd":
برگشت "بیاسدی"
پایان
"windows":
برگشت "ویندوز"
پایان
وگرنه:
برگشت "دیگر"
پایان
پایان
پایان
تابع ریشه:
سرچاپ "ساختهشده برای"، سلام سیستم، "روی"، سلام معماری
سرچاپ "خانواده:"، خانواده()
پهن := سلام معماری ایکس۶۴ یا سلام معماری آرم۶۴
سرچاپ "۶۴ بیتی:"، پهن
سرچاپ "سلام"، سلام نگارش
پایانخروجی این برنامه به سیستمی بستگی دارد که برایش ساخته میشود، برای همین اینجا بدون خروجی آمده است. روی یک رایانهی لینوکس ۶۴ بیتی چاپ میکند ساختهشده برای linux روی x64، بعد خانواده: لینوکس، ۶۴ بیتی: true و نگارش مترجم.
پرچمهای خودتان با -D
پرچمهای خودتان را هم میتوانید از خط فرمان بدهید. -Dنام پرچمی میسازد که درست است و -Dنام=مقدار پرچمی که متن نگه میدارد. نام پرچم میتواند فارسی باشد. تعریفشده(نام) میپرسد آیا پرچم اصلاً داده شده است یا نه:
اگر تعریفشده(حالت) و حالت == "سریع":
پایا نمونهها := ۱۰
وگرنه:
پایا نمونهها := ۱۰۰۰
پایان
تابع ریشه:
سرچاپ "نمونهها:"، نمونهها
اگر تعریفشده(پرحرف):
سرچاپ "خروجی مفصل روشن است"
وگرنه:
سرچاپ "برای جزئیات بیشتر -Dپرحرف را بدهید"
پایان
پایاناین خروجی یک salam run ساده است. با salam run app.salam -Dحالت=سریع -Dپرحرف همین برنامه نمونهها: 10 و خروجی مفصل روشن است را چاپ میکند. راه معمول برای بیرون نگه داشتن یک امکان، یک قلاب آزمایشی یا گزارشهای اضافه از ساخت عادی همین است.
دو نکته مهم است. در سطح بالا پرچمی که کسی تعریفش نکرده نادرست حساب میشود، اما درون تابع نام ناشناخته همچنان ناشناخته است: اگر پرحرف: بدون -Dپرحرف خطای E001 میدهد. مقایسهی پرچمِ تعریفنشده با متن، مثل حالت == "سریع"، هم اصلاً شرط زمان ترجمه نیست. پرسیدن تعریفشده(...) پیش از آن، مثل نمونهی بالا، در هر دو جا درست کار میکند.
ثابتها از خط فرمان
پرچم تعیین میکند کدام کد ترجمه شود. اگر فقط یک مقدار میخواهید، مثل شمارهی درگاه یا برچسب ساخت، از -d استفاده کنید: salam build app.salam -dPORT=9090 -dLABEL=beta ثابتهای PORT و LABEL را به برنامه میدهد، انگار در پرونده نوشته باشید پایا PORT := 9090. مقدار اگر شبیه عدد یا true و false باشد همان خوانده میشود و در غیر این صورت متن است؛ -dDEBUG تنها یعنی درست. نام این ثابتها باید با حروف بزرگ لاتین نوشته شود، حتی در برنامهی فارسی، و ثابتی که خود پرونده تعریف کرده بر مقدار -d مقدم است.
بررسیهای مخصوص اشکالزدایی
سلام ایمن در هر ساختی که بدون --release باشد درست است. پس جای مناسبی است برای بررسیهایی که هنگام نوشتن برنامه لازمشان دارید ولی نمیخواهید هزینهشان را در برنامهی نهایی بپردازید:
اگر سلام ایمن:
پایا ساخت := "اشکالزدایی"
وگرنه:
پایا ساخت := "انتشار"
پایان
تابع جستجو(عددها: صحیح[]، خواسته: صحیح): صحیح:
اگر سلام ایمن:
تکرار طول(عددها) - ۱ در ای:
اگر عددها[ای] > عددها[ای + ۱]:
نادرستسرچاپ "جستجو: ورودی مرتب نیست"
بشکن
پایان
پایان
پایان
ناپایا پایین := ۰
ناپایا بالا := طول(عددها) - ۱
تا پایین <= بالا:
وسط := (پایین + بالا) / ۲
اگر عددها[وسط] == خواسته:
برگشت وسط
وگرنه عددها[وسط] < خواسته:
پایین = وسط + ۱
وگرنه:
بالا = وسط - ۱
پایان
پایان
برگشت -۱
پایان
تابع ریشه:
سرچاپ "ساخت:"، ساخت
سرچاپ جستجو([۲، ۵، ۸، ۱۳، ۲۱]، ۱۳)
سرچاپ جستجو([۹، ۴، ۷، ۱]، ۹)
پایانجستجوی دودویی فقط روی ورودی مرتب درست کار میکند. در ساخت اشکالزدایی حلقهی اضافه آرایهی نامرتب را میبیند و خبر میدهد، و همین روشن میکند چرا جستجوی دوم عددی را که در آرایه هست پیدا نکرد. با --release این حلقه اصلاً ترجمه نمیشود و برنامه فقط دو نتیجه را چاپ میکند.
آزمودن سیستمهای دیگر
شاخههایی که به کار نمیآیند پیش از بررسی گونهها دور ریخته میشوند، پس اشتباهِ درون آنها روی رایانهی شما پنهان میماند: صدا زدن تابعی که وجود ندارد، اگر در شاخهی ویندوز باشد، روی لینوکس بیهیچ پیامی ترجمه میشود. برای آزمودن سیستمی که در دسترس ندارید، برایش با --target ترجمه کنید:
salam obj app.salam --target=x86_64-windows-gnuشاخههای ویندوز را بررسی میکندsalam obj app.salam --target=aarch64-apple-darwinشاخههای مک را بررسی میکند
فرمان obj پس از ساختن پروندهی شیء میایستد، پس به پیونددهنده و کتابخانههای سیستم مقصد نیازی ندارد و هر خطایی که نشان دهد خطای واقعی است.
چند قاعدهی سرانگشتی
- تفاوت سیستمها را در یک جای کوچک نگه دارید، مثل یک ثابت یا یک تابع کوتاه، و باقی برنامه را همهجا یکسان.
- هر
اگرسیستمعامل را باوگرنهببندید، بهخصوص وقتی شاخهای برمیگردد. - پرچمهای خودتان را با
تعریفشده(نام)بسنجید تا ساخت بدون آنها هم ترجمه شود. - پیش از همرسانی کد ویژهی سیستمها، آن را یک بار با
--targetبرای هر سیستمی که پشتیبانی میکنید بسازید.
برای صدا زدن کتابخانهی C متفاوت روی هر سیستم، خود اعلانهای درونداد را درون یک اگر سطح بالا بگذارید. درس بعد، همکاری با C، از همینجا شروع میکند.