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

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

فوائد


هناك الكثير من الأسباب التي تجعل لغة البرمجة الشاملة ليس فقط مفيدة وإنما ضرورية أيضا:
  • تيسير التعليم للمبرمجين.
  • تحسين جودة المنتجات البرمجية. كلما تعددت اللغات المستخدمة لتطوير منتج كلما قلت جودته.
  • زيادة الإبداع. عادة ما يتجاوز المبرمجون تقنيات مفيدة لمجرد غياب الدعم لتلك التقنيات في اللغة التي يستخدمون.
  • تقليل كلفة الإنتاج. الحاجة لعدد أكبر من اللغات في المشروع تعني كلفة إنتاج إعلى.
  • تسريع التقدم في التقنيات البرمجية بدل تشتيت الجهود على عدد كبير من الغات.
  • تيسير الحصول على المبرمجين. كلما زاد عدد اللغات المستخدمة كلما ازداد الانقسام في مجتمع المبرمجين وصَعُبَ معه الحصول على المبرمج الملائم وصعُبَ على المبرمج الحصول على الوظيفة الملائمة.
  • تيسير التعاون بين الفرق البرمجية المختلفة.
  • زيادة قابلية إعادة استخدام الحزم البرمجية.
  • تمكين مزج عدد أكبر من التقنيات البرمجية داخل البرنامج الواحد.
بالإضافة للفوائد المذكورة أعلاه، صُممت لغة الأسُس لتمكين ما يلي:
  • تيسير استغلال موارد الحاسوب لانعدام الحواجز التي تفرضها اللغة.
  • تمكين المجتمع من المشاركة في تطوير اللغة وتيسير تلك العملية.
  • تمكين اللغة من دعم كمية أكبر من الخواص دون تعقيد القواعد.
  • تيسير تنصيب البيئة البرمجية.
  • تمكين المبرمج من العمل على مستويات متعددة تبعاً لحاجة برنامجه. حسب المكتبات المستخدمة يمكن للغة الأسُس التصرف كلغة مرتفعة المستوى أو لغة منخفضة المستوى أو الجمع بين الاثنين.
  • توفير مرونة أكثر في التحكم بناتج البرمجة. على سبيل المثال يمكن إنشاء ملف تشغيلي أو تنفيذ الشفرة مباشرة أو الجمع بين الاثنين كأن تنفَّذ الاختبارات الآلية مباشرة وفي حالة نجاحها يُنشأ الملف التشغيلي.

كيف؟


تمكن لغة الأسس المبرمجين من توسيع اللغة بتوفير الإمكانيات التالية:
  • التوافقية (interoperability) بين المترجم وبرنامج المستخدم. أي، يمكن للمبرمج التواصل مع مترجم الأسس من داخل برنامجه لقراءة بيانات المترجم أو التعديل عليها أو إنشاء شفرات جديدة برمجيًا.
  • التنفيذ وقت الترجمة. أي تنفيذ أجزاء من شفرة المستخدم أثناء عملية الترجمة لإضافة شفرات جديدة أو تعديل الشفرات التي تتُرجم حاليًا.
  • ديناميكية قواعد اللغة. قواعد اللغة مخزنة في المترجم كبيانات وليس كشفرة مترجمة مسبقًا، وبالتالي يمكن لبرنامج المستخدم إضافة قواعد جديدة.
  • ديناميكية شفرة المترجم نفسه. أي يمكن لمكتبة معينة أن تضيف إلى شفرة المترجم نفسه ديناميكيًا، مثلًا باستبدال دالة معينة بأخرى.

تعدد الواجهات التنفيذية


مرونة لغة الأسس تتيح ربطها بعدة واجهات تنفيذية، أي يمكن لأجزاء مختلفة من البرنامج الواحد أن تُترجم أو تنفذ باستخدام واجهات تنفيذية مختلفة. الفكرة معاكسة لأطُر كـ LLVM و JVM و .NET. على سبيل المثال يوفر إطار LLVM وحدة إنشاء شفرة تنفيذية مفردة يُربط بها واجهات أمامية للغات متعددة. الأسُس عكس ذلك، فهي واجهة لغة موحدة يُربط بها العديد من وحدات إنشاء الشفرة التنفيذية حسب حاجة البرنامج.

الربط مع واجهات مختلفة يمكن أن يتم من شفرة المبرمج نفسها، أو من مكتبة يشملها المبرمج في برنامجه.

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

مقارنة


توجد ثلاث اختلافات مهمة بين الأسُس واللغات التقليدية فيما يتعلق بقابلية التوسيع:

  • اللغات التقليدية توسّع بأسلوب ساكن فقط (statically) وذلك بتعديل المترجم ونشر إصدار جديد، بينما يمكن توسيع الأسُس بتوفير مكتبة إضافية دون الحاجة لإعادة بناء المترجم. الشكل التالي يوضح الفرق بين الاثنين:

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

    وكما بُيّن في فقرة سابقة، توفّر الأسُس وسائل لتقليل احتمالية التعارض بين المكتبات المختلفة.
  • توفّر بعض اللغات إضافات يمكن تنصيبها في البيئة البرمجية لتكون متوفرة لجميع المشاريع في تلك البيئة بينما في لغة الأسُس تُضمّن الإضافات على مستوى المشروع الواحد وليس على مستوى النظام كله. بمعنى آخر يمكن لمشروعين مختلفين في نفس البيئة تحميل مجموعتين مختلفتين من الإضافات. بالإضافة لذلك لا تحتاج الإضافات في لغة الأسُس لتغيير إعدادات النظام وإنما يتم تحميل تلك الإضافت من شفرة المشروع المصدرية نفسها عبر الأمر "اشمل" (import).

أمثلة


المثال التالي يوضح خاصية الدالات المغلفة (closure) في لغة الأسس. مترجم لغة الأسس لا يدعم الدالات المغلفة مبدئيًا، ولا يفهم الكلمة المفتاحية `مغلفة` (`closure`) لكن المكتبة التي تُحمل في بداية المثال تضيف الخاصية مع القواعد المطلوبة لها. يُلاحظ في المثال أن المغلفة تُميز تلقائيًا بين الأنواع المختلفة من المتغيرات المستخدمة في متن المغلفة وتعمل على تجهيز الحمولة المطلوبة بناءًا على ذلك، فتضع في حمولة المغلفة المتغير `ح` (`p`) لأنه متغير محلي بينما لا تُضمن المتغير `ع` (`g`) لأنه متغير عمومي وكذلك لا تُضمن المتغير `ك` (`q`) لأنه غير مستخدم في متن الدالة. هذه الدرجة من التحكم في توسعات اللغة مستحيلة في اللغات الشائعة لأنها تتطلب توافقًا تشغيليا بين المكتبة والمترجم.

اشمل "مـتم/طـرفية"؛
اشمل "مغلفة"؛

استخدم مـتم.طـرفية؛

عرف ع: صـحيح؛

دالة هات_مغلفة (): (مغلفة (صـحيح)) {
    عرف ح: صـحيح = 2؛
    عرف ك: صـحيح = 4؛
    أرجع مغلفة (م: صـحيح) {
        اطبع("معطى المغلفة: %d\ج"، م)؛
        اطبع("متغير حمولة: %d\ج"، ح)؛
        اطبع("متغير عمومي: %d\ج"، ع)؛
    }؛
}

عرف د: مغلفة(صـحيح) = هات_مغلفة()؛

ع = 1؛
د(3)؛

// الناتج:
// معطى المغلفة: 3
// متغير حمولة: 2
// متغير عمومي: 1
import "Srl/Console";
import "closure";

use Srl.Console;

def g: Int;

func getClosure (): (closure (Int)) {
    def p: Int = 2;
    def q: Int = 4;
    return closure (a: Int) {
        print("closure arg: %d\n", a);
        print("closure payload var: %d\n", p);
        print("global var: %d\n", g);
    };
}

def c: closure(Int) = getClosure();

g = 1;
c(3);

// Output:
// closure arg: 3
// closure payload var: 2
// global var: 1

المثال التالي يوضح إضافة خصائص جديدة لتسهيل الربط مع قواعد البيانات وكتابة العبارات الاستعلامية. نلاحظ في المثال أنه يبدأ بشمول مدير الحزم، الذي يستخدمه لتنزيل وشمول مكتبة من الشبكة العنكبوتية مباشرة (في هذه الحالة من موقع جت هب) وهذه المكتبة بدورها تضيف خصائص جديدة لمطابقة الأصناف مع ما يقابلها من جداول في قاعدة البيانات، كما تضيف قواعد لكتابة الشروط في العبارات الاستعلامية. ففي دالة `أضف_سيارة` (`addCar`) ترى أن المستخدم لا يحتاج لكتابة عبارات SQL لإضافة القيد الجديد وإنما تستنبطها المكتبة تلقائيًا من المبدلات التي تسم الصنف ومتغيراته، أما في دالة `جد_سيارات` (`findCars`) فتجد شرط البحث مكتوبًا بلغة الأسس نفسها كما لو كنت تكتب شرطًا في جملة شرطية، ولكن المترجم يترجم هذا الشرط إلى عبارة SQL.

اشمل "مـتم/نـص"؛
اشمل "مـتم/نـص"؛
اشمل "مـتم/مـصفوفة"؛
اشمل "مـتم/طـرفية"؛
اشمل "مـتم/نـظام"؛
اشمل "مـتم/سندات"؛
اشمل "مـحا"؛
مـحا.اشمل_ملف("Alusus/Rows"، { "صـفوف.أسس"، "مـشغلات/بـوستغرس.أسس" })؛
استخدم مـتم؛
استخدم صـفوف؛

@جدول["سيارات"]
صنف سـيارة {
    عرف_أساسيات_الجدول[]؛

    @إلزامي
    @فهرس_رئيسي
    @مـعرف_عالمي
    @حقل
    عرف المعرف: صحيح؛

    @مـحارف_مرنة["50"]
    @حقل
    عرف الاسم: نـص؛

    @عـدد_عائم
    @حقل["سعر_السيارة"]
    عرف السعر: عائم؛
}

عرف قب: قـاعدة_بيانات(مـشغل_بوستغرس(مـعطيات_الاتصال().{
    اسم_قاعدة_البيانات = "alusus"؛
    اسم_المستخدم = "alusus"؛
    كلمة_السر = "alusus"؛
    عنوان_الخادم = "0.0.0.0"؛
    المنفذ = 5432؛
}))؛
إذا !قب.أمتصل() {
    نـظام.فشل(1، نـص("فشل الاتصال بقاعدة البيانات: ") + قب.هات_آخر_خطأ())؛
}

قب.مهيكل[سـيارة].أنشئ()؛

دالة أضف_سيارة(الاسم: نـص, السعر: عـائم) {
    عرف س: سـيارة؛
    س.المعرف = أنشئ_معرفا_عالميا()؛
    س.الاسم = الاسم؛
    س.السعر = السعر؛
    قب.احفظ[سـيارة](س)؛
}

دالة جد_سيارات(أقصى_سعر: عـائم): لـا_مضمون[مـصفوفة[سـندنا[سـيارة]]] {
    أرجع قب.من[سـيارة].حيثما[السعر <= أقصى_سعر].اجلب()؛
}
import "Apm";
Apm.importFile("Alusus/Rows", { "Rows.alusus", "Drivers/Postgresql.alusus" });
use Srl;
use Rows;

@model["cars"]
class Car {
    define_model_essentials[];

    @notNull
    @primaryKey
    @Uuid
    @column
    def id: String;

    @VarChar["50"]
    @column
    def name: String;

    @Float
    @column["car_price"]
    def price: Float;
}

def db: Db(PostgresqlDriver(ConnectionParams().{
    dbName = "alusus";
    userName = "alusus";
    password = "alusus";
    host = "0.0.0.0";
    port = 5432;
}));
if !db.isConnected() {
    System.fail(1, String("Error connecting to DB: ") + db.getLastError());
}

db.schemaBuilder[Car].create();

function addCar(name: String, price: Float) {
    def c: Car;
    c.id = generateUuid();
    c.name = name;
    c.price = price;
    db.save[Car](c);
}

function findCars(maxPrice: Float): Possible[Array[SrdRef[Car]]] {
    return db.from[Car].where[price <= maxPrice].select();
}

المثال التالي يوضح كتابة برنامج ويب متكامل يحتوي ضمن ملف واحد على شفرة الخادم وواجهة المستخدم. يبدأ المثال باستخدام مدير الحزم لتحميل مكتبة مـنصة_ويب. من خلال المبدلات المضافة إلى الدالات تعلم مـنصة_ويب أي الدالات ستشغل في الخادم وأي منها في واجهة المستخدم، فتبحث في شفرة الشمروع تلقائيًا عن الدالات التي ستنفذ في الخادم وتضيف استدعاءاتها إلى دالة الخادم الرئيسية، وتبحث أيضًا عن الدالات التي ستنفذ في المتصفح وتترجمها إلى شفرة ويب أسمبلي (WebAssembly) وتجعلها متوفرة للتحميل من الخادم على المنفذ المحدد في مبدل `@منفذ_مرئي` (`@uiEndpoint`). في هذا المثال دالتا `أضف_رسالة` (`postMessage`) و `هات_الرسائل` (`getMessages`) ستترجمان إلى منافذ بيانية على الخادم تحت المسار `/messages`، بينما ستترجم دالة `رئيسي` (`main`) إلى ويب أسمبلي وتوفر على المنفذ `/`. ومن الخطط المستقبلية لهذه المكتبة ترجمة أي استدعاء لدالة خادم تلقائيًا إلى عملية HTTP.

اشمل "مـتم/نـظام"؛
اشمل "بـناء"؛
اشمل "مـحا"؛
مـحا.اشمل_ملف("Alusus/WebPlatform"، "مـنصة_ويب.أسس")؛
مـحا.اشمل_ملف("Alusus/Http"، "بـننف.أسس")؛
مـحا.اشمل_ملف("Alusus/Json"، "جـيسون.أسس")؛
اشمل "مـتم/سندات"؛
اشمل "مـتم/مـصفوفة"؛
اشمل "مـتم/نـص"؛
اشمل "مـتم/طـرفية"؛
اشمل "مغلفة"؛

استخدم مـتم؛
استخدم مـنصة_ويب؛

//==============================================================================
// الخادم

عرف _حد_الرسائل_: 12؛
عرف رسائل : مـصفوفة[نـص]؛

@منفذ_بياني["POST"، "/messages"]
دالة أضف_رسالة (اتصال:مؤشر[بـننف.اتـصال]){
    عرف بيانات: مصفوفة[مـحرف،1024]؛
    عرف حجم_البيانات: صحيح = بـننف.اقرأ(اتصال، بيانات~مؤشر، بيانات~حجم)؛
    إذا رسائل.هات_الطول() >= _حد_الرسائل_ رسائل.أزل(0)؛
    رسائل.أضف(نـص(بيانات~مؤشر، حجم_البيانات))؛
    بـننف.اطبع(اتصال، "HTTP/1.1 200 Ok\r\n\r\n")؛
}

@منفذ_بياني["GET"، "/messages"]
دالة هات_الرسائل (اتصال: مؤشر[بـننف.اتـصال]) {
    عرف الرد: نـص = نـص.ادمج(رسائل، "<br>")؛
    بـننف.اطبع(اتصال، "HTTP/1.1 200 Ok\r\n")؛
    بـننف.اطبع(اتصال، "Content-Type: text/plain\r\n")؛
    بـننف.اطبع(اتصال، "Cache-Control: no-cache\r\n")؛
    بـننف.اطبع(اتصال، "Content-Length: %d\r\n\r\n"، الرد.هات_الطول())؛
    بـننف.اطبع(اتصال، الرد.صوان)؛
}


//=============================================================================
// صـفحات واجهة المستخدم

عرف _جلب_: "GET"؛
عرف _إرسال_: "POST"؛
عرف _المسار_: "/messages"؛
عرف _ترويسة_صنف_بيانات_نصي_: "Content-Type: application/text"؛

@منفذ_مرئي["/"]
@عنوان["مثال منصة ويب - الدردشة"]
دالة رئيسي {
    عرف عند_استلام_بيانات: مغلفة (جـيسون)؛

    نـافذة.النموذج.حدد_المشهد(صـندوق({}).{
        الطراز.{
            الطول = مـسافة.مئوي(100)؛
            ملء_السطر = مـلء_سطر._مسافة_بينية_؛
            الاتجاه = اتـجاه._من_اليمين_؛
            الإظهار = إظـهار._مرن_؛
            النسق = نـسق._عمود_؛
        }؛
        أضف_فروع({
            الـترويسة()،
            صـندوق().{
                الطراز.{
                    العرض = مـسافة.مئوي(100)؛
                    الحشوة = مـسافة4.نقاط(5)؛
                    الإظهار = إظـهار._مرن_؛
                    النسق = نـسق._عمود_؛
                    المرونة = مـرونة(1، 1)؛
                }
                أضف_فروع({
                    كـتابة().{
                        الطراز.{
                            العرض = مـسافة.مئوي(100)؛
                            الطول = مـسافة.مئوي(100)؛
                            لون_الخط = لـون(50، 50، 50)؛
                            حجم_الخط = مـسافة.نقاط(20.0)؛
                        }؛
                        عند_استلام_بيانات = مغلفة (جيسون: جـيسون) {
                            عرف الحالة: صحيح = جيسون
                                .هات_كائن("eventData")
                                .هات_صحيح("status")؛
                            إذا الحالة >= 200 و الحالة &tt; 300 {
                                عرف البيانات: نـص = جيسون
                                    .هات_كائن("eventData")
                                    .هات_نص("body")؛
                                إذا هذا.هات_النص() != البيانات {
                                    هذا.حدد_النص(البيانات)؛
                                }
                            } وإلا {
                                // تتمة: أظهر إشعار خطأ.
                            }
                        }؛
                    }
                })؛
            }،
            مـدخل_نصي().{
                العرض = مـسافة.مئوي(100)؛
                الطول = مـسافة.نقاط(50)؛
                قد_تم_الإدخال = مغلفة (بيانات_جديده: نـص) {
                    أرسل_نداء(
                        _إرسال_،
                        _المسار_،
                        _ترويسة_صنف_بيانات_نصي_،
                        بيانات_جديده،
                        10000،
                        مغلفة(جـيسون) {}
                    )؛
                    أرسل_نداء(_جلب_، _المسار_، 0، 0، 500، عند_استلام_بيانات)؛
                }؛
            }
        })؛
    })؛

    ابدأ_المؤقت_المتكرر(500000، مغلفة (جـيسون) {
        أرسل_نداء(_جلب_، _المسار_، 0، 0، 500، عند_استلام_بيانات)؛
    })؛

     نفذ_حلقة_معالجة_الأحداث()؛
}

//=============================================================================
// البداية

طـرفية.اطبع("تشغيل الخادم على المنفذ 8010...\nURL: http://localhost:8010/\n")؛
شغل_الخادم ({ "listening_ports"، "8010"، "static_file_max_age"، "0" })؛
import "Build";
import "Apm";
Apm.importFile("Alusus/WebPlatform");
use Srl;
use WebPlatform;

//==============================================================================
// Backend

def MAX_MESSAGES: 12;
def messages: Array[String];

@beEndpoint["POST", "/messages"]
func postMessage (conn: ptr[Http.Connection]) {
    def postData: array[Char, 1024];
    def postDataSize: Int = Http.read(conn, postData~ptr, postData~size);
    if messages.getLength() >= MAX_MESSAGES messages.remove(0);
    messages.add(String(postData~ptr, postDataSize));
    Http.print(conn, "HTTP/1.1 200 Ok\r\n\r\n");
}

@beEndpoint["GET", "/messages"]
func getMessages (conn: ptr[Http.Connection]) {
    def response: String = String.merge(messages, "<br>");
    Http.print(conn, "HTTP/1.1 200 Ok\r\n");
    Http.print(conn, "Content-Type: text/plain\r\n");
    Http.print(conn, "Cache-Control: no-cache\r\n");
    Http.print(conn, "Content-Length: %d\r\n\r\n", response.getLength());
    Http.print(conn, response.buf);
}

//==============================================================================
// Frontend Pages

@uiEndpoint["/"]
@title["WebPlatform Example - Chat"]
func main {
    def onFetch: closure (json: Json);

    Window.instance.setView(Box({}).{
        style.{
            height = Length.percent(100);
            justify = Justify.SPACE_BETWEEN;
            display = Display.FLEX;
            layout = Layout.COLUMN;
        };
        addChildren({
            Header(),
            Box({}).{
                style.{
                    width = Length.percent(100) - Length.pt(10);
                    padding = Length4.pt(5);
                    display = Display.FLEX;
                    layout = Layout.COLUMN;
                    flex = Flex(1);
                };
                addChildren({
                    Text(String()).{
                        style.{
                            width = Length.percent(100);
                            height = Length.percent(100);
                            fontColor = Color(50, 50, 50);
                            fontSize = Length.pt(20.0);
                        };
                        onFetch = closure (json: Json) {
                            def status: Int = json
                                .getObject("eventData")
                                .getInt("status");
                            if status >= 200 and status < 300 {
                                def data: String = json
                                    .getObject("eventData")
                                    .getString("body");
                                if this.getText() != data {
                                    this.setText(data);
                                }
                            } else {
                                // TODO: Notify user.
                            }
                        };
                    }
                });
            },
            TextEntry().{
                width = Length.percent(100) - Length.pt(3);
                height = Length.pt(50);
                onNewEntry = closure (newData: String) {
                    sendRequest(
                        "POST", "/messages",
                        "Content-Type: application/text", newData, 10000,
                        closure (Json) {}
                    );
                    sendRequest("GET", "/messages", null, null, 500, onFetch);
                };
            }
        })
    });

    startTimer(500000, closure (json: Json) {
        sendRequest("GET", "/messages", null, null, 500, onFetch);
    });

    runEventLoop();
}

//==============================================================================
// Project Control

Console.print("Starting server on port 8010...\nURL: http://localhost:8010/\n");
runServer({ "listening_ports", "8010", "static_file_max_age", "0" });

لا حدود لما يمكن للمكتبات فعله ولا حدود لعدد أو نوع المكتبات المحملة آنياً وقد صُممت لغة الأسُس بطريقة تسمح بإضافة عدد لا محدد من القواعد اللغوية وتُقلل احتمال تصادمها ببعض وتضمن أيضاً تناسقها. راجع تصميم اللغة في صفحة الوثائق لمزيد من المعلومات.

الاسئلة الشائعة


إسم اللغة مستوحى من تصميمها، فهي تُشكّل الأسس لبرمجة الحواسيب ويُبنى على هذه الأسس كل ما يتعلق بالبرمجة. كما أنها في نفس الوقت لغة مجردة، فمترجم اللغة لا يُقدّم من اللغة إلا أسُسَها.

الشفرة المصدرية متوفرة ويُتاح للجميع استخدامها مجاناً حتى للأغراض التجارية، لكنها متوفرة تحت رخصة أقل تحرراً من رخصة GPL.

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

المشروع مازال في مهده والقائمون عليه يسعون في الفترة الحالية إلى تجنب تشتت المشروع إلى عدة لغات غير متوافقة مع بعضها لذلك تجنب القائمون على المشروع الرخص الشائعة التي تسمح بتفرع المشروع.

نعم، عندما تثبت أسس المشروع فإننا ننوي نشره تحت رخصة GPL. لم يوضع بعد توقيت محدد لهذا الأمر لكن الاحتمال الأغلب أن تنشر الإصدارة 1.0 تحت رخصة GPL.

بكل تأكيد، نحن نبحث بجدية عن مساهمين في المشروع. الرجاء الاتصال بنا لمزيد من المعلومات.

كُتب المترجم بلغة C++17 وباستخدام مكتبات STL فقط، أما المكتبات المعيارية فقد كتبت باستخدام C++17 و STL أيضا، بالإضافة إلى مكتبة LLVM.

نحن ندعم حاليا نظام لينُكس Linux ونوفر له نسخًا مبنية مسبقًا، وندعم macOS لكن ستحتاج لبناء مترجم الأسس من الشفرة المصدرية. كما يمكنك تشغيل الأسس في نظام ويندوز باستخدام WSL ولكننا ننوي مستقبلًا توفير دعم رسمي لنظام ويندوز.