// std.error: one common error value with an identity, a message, a cause
// chain and notes (docs/en/reference/errors.md). Code decides by identity, never by text.
import std.error.failure;
import std.error.from_number;
import std.error.from_os;
import std.fs.read_file;
import std.io.println;
import std.text.number;
def read_port(text: string): result int, Error {
match parse_int(&text) with
| result.ok(value) -> {
if (value < 1 || value > 65535) {
return result.err(error_with_kind("server", "port_out_of_range", "the port must be between 1 and 65535"));
};
return result.ok(value);
}
| result.err(problem) -> {
// Typed std errors stay the primary API; a converter turns one into
// an Error that keeps its identity («std.text.number», kind).
let cause: Error = error_from_integer_parse_error(&problem);
let failure: mutable Error = error_caused_by("the port is not a number", cause);
error_add_note(&mutable failure, "the port comes from the PORT setting");
return result.err(failure);
};
}
def load_config(path: string): result string, Error {
match read_file(&path) with
| result.ok(text) -> { return result.ok(text); }
| result.err(code) -> {
let cause: Error = error_from_fs_error(&code);
return result.err(error_caused_by("could not read the configuration", cause));
};
}
def main(): int {
match read_port("8080") with
| result.ok(port) -> { println(int_to_text(port)); }
| result.err(failure) -> { error_print(&failure); };
let number_domain: string = "std.text.number";
let invalid_digit: string = "رقم_غير_صالح";
match read_port("80x0") with
| result.ok(port) -> { println(int_to_text(port)); }
| result.err(failure) -> {
println(error_describe(&failure));
if (error_is(&failure, &number_domain, &invalid_digit)) {
println("decided by identity: an invalid digit");
};
};
let server_domain: string = "server";
let out_of_range: string = "port_out_of_range";
match read_port("70000") with
| result.ok(port) -> { println(int_to_text(port)); }
| result.err(failure) -> {
println(error_describe(&failure));
if (error_is(&failure, &server_domain, &out_of_range)) {
println("decided by identity: out of range");
};
};
let fs_domain: string = "std.fs";
let not_found: string = "غير_موجود";
match load_config("examples-missing-config.conf") with
| result.ok(text) -> { println(text); }
| result.err(failure) -> {
println(error_describe(&failure));
if (error_is(&failure, &fs_domain, ¬_found)) {
println("decided by identity: the file is missing");
};
};
return 0;
}// std.error: قيمة خطأ مشتركة لها هوية ورسالة وسلسلة أسباب وملاحظات
// (docs/en/reference/errors.md). الشيفرة تقرر بالهوية، لا بنص الرسالة.
استورد std.error.failure;
استورد std.error.from_number;
استورد std.error.from_os;
استورد std.fs.read_file;
استورد std.io.println;
استورد std.text.number;
عرف اقرأ_المنفذ(النص: نص): نتيجة عدد, فشل {
طابق حلل_عدد(&النص) مع
| نتيجة.نجح(القيمة) -> {
إذا (القيمة < 1 || القيمة > 65535) {
أرجع نتيجة.خطأ(فشل_بهوية("server", "منفذ_خارج_المدى", "يجب أن يكون المنفذ بين 1 و65535"));
};
أرجع نتيجة.نجح(القيمة);
}
| نتيجة.خطأ(المشكلة) -> {
// أخطاء std ذات الأنواع تبقى الواجهة الأساسية؛ والمحوّل يجعل أحدها
// فشلا يحتفظ بهويته («std.text.number»، النوع).
دع السبب: فشل = فشل_من_خطأ_تحليل_عدد(&المشكلة);
دع الفشل: متغير فشل = فشل_بسبب("المنفذ ليس عددا", السبب);
أضف_ملاحظة(&متغير الفشل, "المنفذ مأخوذ من الإعداد PORT");
أرجع نتيجة.خطأ(الفشل);
};
}
عرف حمل_الإعدادات(المسار: نص): نتيجة نص, فشل {
طابق اقرأ_الملف(&المسار) مع
| نتيجة.نجح(النص) -> { أرجع نتيجة.نجح(النص); }
| نتيجة.خطأ(الرمز) -> {
دع السبب: فشل = فشل_من_خطأ_ملف(&الرمز);
أرجع نتيجة.خطأ(فشل_بسبب("تعذرت قراءة الإعدادات", السبب));
};
}
عرف الرئيسية(): عدد {
طابق اقرأ_المنفذ("8080") مع
| نتيجة.نجح(المنفذ) -> { اطبع_سطر(عدد_إلى_نص(المنفذ)); }
| نتيجة.خطأ(الفشل) -> { اطبع_فشل(&الفشل); };
دع نطاق_الأعداد: نص = "std.text.number";
دع رقم_غير_صالح: نص = "رقم_غير_صالح";
طابق اقرأ_المنفذ("80x0") مع
| نتيجة.نجح(المنفذ) -> { اطبع_سطر(عدد_إلى_نص(المنفذ)); }
| نتيجة.خطأ(الفشل) -> {
اطبع_سطر(صف_فشل(&الفشل));
إذا (هل_من_نوع(&الفشل, &نطاق_الأعداد, &رقم_غير_صالح)) {
اطبع_سطر("القرار بالهوية: محرف غير رقمي");
};
};
دع نطاق_الخادم: نص = "server";
دع خارج_المدى: نص = "منفذ_خارج_المدى";
طابق اقرأ_المنفذ("70000") مع
| نتيجة.نجح(المنفذ) -> { اطبع_سطر(عدد_إلى_نص(المنفذ)); }
| نتيجة.خطأ(الفشل) -> {
اطبع_سطر(صف_فشل(&الفشل));
إذا (هل_من_نوع(&الفشل, &نطاق_الخادم, &خارج_المدى)) {
اطبع_سطر("القرار بالهوية: خارج المدى");
};
};
دع نطاق_الملفات: نص = "std.fs";
دع غير_موجود: نص = "غير_موجود";
طابق حمل_الإعدادات("examples-missing-config.conf") مع
| نتيجة.نجح(النص) -> { اطبع_سطر(النص); }
| نتيجة.خطأ(الفشل) -> {
اطبع_سطر(صف_فشل(&الفشل));
إذا (هل_من_نوع(&الفشل, &نطاق_الملفات, &غير_موجود)) {
اطبع_سطر("القرار بالهوية: الملف غير موجود");
};
};
أرجع 0;
}
Run it
With the interpreter, without compiling:
./build/sultanc run examples/en/errors/error_values.snOr compile it to an executable:
./build/sultanc examples/en/errors/error_values.sn -o build/example && ./build/example