إنشاء لغة برمجة خاصة بنا: DSL باستخدام JavaScript

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

ماذا لو كان بإمكانك ابتكار لغتك الخاصة؟

\n\n

تخيل: أنت تكتب كودًا يُقرأ كنص إنجليزي عادي. لا أقواس زائدة، ولا for أو if، فقط تعليمات نقية وواضحة. يبدو هذا كخيال علمي؟ لكنه ليس كذلك. إنها DSL (لغة مخصصة للمجال) — لغة مصممة خصيصًا لمهمة محددة.

\n\n

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

\n\n

هل أنت مستعد لأن تصبح لغويًا في عالم البرمجة؟ هيا بنا!

\n\n

DSL: ما هي ولماذا تحتاجها؟

\n\n

DSL (لغة مخصصة للمجال) هي لغة برمجة (أو امتداد نحوي لها) تم إنشاؤها لحل مشاكل في مجال واحد محدد. على عكس اللغات العامة (C++، Python، Java)، لا تحاول DSL تغطية كل شيء. مهمتها هي أن تكون معبرة قدر الإمكان في مجالها الخاص.

\n\n

أمثلة من الواقع:

\n
    \n
  • SQL — لغة للعمل مع قواعد البيانات.
  • \n
  • HTML — لغة ترميز صفحات الويب.
  • \n
  • Regex — لغة للبحث باستخدام الأنماط.
  • \n
  • Makefile — لغة لوصف بناء المشاريع.
  • \n
\n\n

والآن تخيل أن بإمكانك إنشاء لغة مريحة مماثلة لمهمتك: لوصف قواعد الأعمال، لتكوين البوتات، لبناء استعلامات معقدة لـ API. إنشاء DSL باستخدام JavaScript هي قوة خارقة تجعل الكود موثقًا ذاتيًا وتخفض حاجز الدخول للمطورين الجدد.

\n\n

DSL داخلي وخارجي: طريقان نحو هدف واحد

\n\n

DSL داخلي (Embedded DSL)

\n

هي طبقة فوق لغة موجودة. تستخدم تركيب JavaScript ولكنك تبني منه "لبنات" لغة جديدة. المثال الأكثر شيوعًا هو Fluent API (سلاسل الدوال).

\n\n

الإيجابيات: لا حاجة لكتابة محلل (parser)، تستخدم كل إمكانيات اللغة المضيفة (التصحيح، الأنواع، الأدوات).
\nالسلبيات: مقيد بتركيب JavaScript (لا يمكن إضافة عوامل تشغيل جديدة).

\n\n

DSL خارجي

\n

تخترع تركيبك الخاص من الصفر، ثم تكتب محللًا (أو مترجمًا) يحوله إلى JavaScript.

\n\n

الإيجابيات: حرية كاملة في التركيب، يمكنك إنشاء لغة موجزة جدًا.
\nالسلبيات: تحتاج لكتابة وصيانة محلل، أصعب في التصحيح.

\n\n

معظم المشاريع DSL باستخدام JavaScript تبدأ بالنهج الداخلي — فهو أبسط ويمكن تطبيقه اليوم.

\n\n

كتابة أول DSL: من التكوين إلى الشعر

\n\n

لنقم بإنشاء DSL داخلي لوصف المسارات في تطبيق ويب. بدلاً من كتابة:

\n\n
const routes = [\n    { path: '/users', handler: usersHandler, method: 'GET' },\n    { path: '/users/:id', handler: userById, method: 'GET' },\n    { path: '/users', handler: createUser, method: 'POST' }\n];
\n\n

نريد الكتابة بهذا الشكل:

\n\n
const router = new Router();\nrouter\n    .get('/users', usersHandler)\n    .get('/users/:id', userById)\n    .post('/users', createUser);
\n\n

أفضل بالفعل، أليس كذلك؟ لكن هذه مجرد البداية. DSL الحقيقي يجب أن يكون أكثر تعبيرًا.

\n\n

الخطوة 1: Fluent API (سلاسل الدوال)

\n\n

أبسط طريقة لإنشاء لغة مخصصة للمجال هي إرجاع this من كل دالة.

\n\n
class Router {\n    constructor() {\n        this.routes = [];\n    }\n\n    get(path, handler) {\n        this.routes.push({ path, handler, method: 'GET' });\n        return this; // مفتاح السلسلة\n    }\n\n    post(path, handler) {\n        this.route                

المدونات

توصيات الكتب