إنشاء لغات JVM قابلة للاستخدام: نظرة عامة
نشرت: 2022-03-11هناك عدة أسباب محتملة لإنشاء لغة ، بعضها ليس واضحًا على الفور. أود أن أقدمها مع نهج لإنشاء لغة لـ Java Virtual Machine (JVM) تعيد استخدام الأدوات الحالية قدر الإمكان. بهذه الطريقة ، سنقلل من جهود التطوير ونوفر سلسلة أدوات مألوفة للمستخدم ، مما يجعل من السهل اعتماد لغة البرمجة الجديدة الخاصة بنا.
في هذه المقالة ، وهي الأولى من السلسلة ، سأقدم نظرة عامة على الإستراتيجية والأدوات المختلفة المتضمنة في إنشاء لغة البرمجة الخاصة بنا لـ JVM. في المقالات المستقبلية ، سوف نتعمق في تفاصيل التنفيذ.
لماذا تنشئ لغة JVM الخاصة بك؟
يوجد بالفعل عدد لا حصر له من لغات البرمجة. فلماذا عناء إنشاء واحدة جديدة؟ هناك العديد من الإجابات المحتملة على ذلك.
بادئ ذي بدء ، هناك العديد من أنواع اللغات المختلفة: هل تريد إنشاء لغة برمجة للأغراض العامة (GPL) أم لغة محددة بمجال معين؟ النوع الأول يشمل لغات مثل Java أو Scala: لغات تهدف إلى كتابة حلول مناسبة كافية لمجموعة كبيرة من المشاكل. تركز اللغات الخاصة بالمجال (DSL) بدلاً من ذلك على حل مجموعة محددة من المشكلات بشكل جيد. فكر في HTML أو Latex: يمكنك الرسم على الشاشة أو إنشاء مستندات في Java ولكن سيكون الأمر مرهقًا ، باستخدام DSLs بدلاً من ذلك ، يمكنك إنشاء مستندات بسهولة شديدة ولكنها تقتصر على هذا المجال المحدد.
لذلك ربما توجد مجموعة من المشكلات التي تعمل عليها كثيرًا والتي قد يكون من المنطقي إنشاء DSL لها. لغة تجعلك منتجًا للغاية أثناء حل نفس أنواع المشكلات مرارًا وتكرارًا.
ربما تريد بدلاً من ذلك إنشاء GPL لأن لديك بعض الأفكار الجديدة ، على سبيل المثال لتمثيل العلاقات كمواطنين من الدرجة الأولى أو تمثيل السياق.
أخيرًا ، قد ترغب في إنشاء لغة جديدة لأنها ممتعة ورائعة ولأنك ستتعلم الكثير في هذه العملية.
الحقيقة هي أنك إذا استهدفت JVM يمكنك الحصول على لغة قابلة للاستخدام بجهد أقل ، وذلك بسبب:
- تحتاج فقط إلى إنشاء رمز ثنائي وسيكون الرمز الخاص بك متاحًا على جميع الأنظمة الأساسية التي يوجد بها JVM
- ستكون قادرًا على الاستفادة من جميع المكتبات والأطر الموجودة لـ JVM
لذلك يتم تقليل تكلفة تطوير لغة بشكل كبير في JVM وقد يكون من المنطقي إنشاء لغات جديدة في سيناريوهات قد تكون غير اقتصادية خارج JVM.
ما الذي تحتاجه لجعله قابلاً للاستخدام؟
هناك بعض الأدوات التي تحتاجها تمامًا لاستخدام لغتك - من بين هذه الأدوات محلل ومترجم (أو مترجم). على اية حال، هذا غير كافي. لجعل لغتك قابلة للاستخدام حقًا في الممارسة العملية ، تحتاج إلى توفير العديد من المكونات الأخرى لسلسلة الأدوات ، وربما تتكامل مع الأدوات الحالية.
من الناحية المثالية ، تريد أن تكون قادرًا على:
- إدارة المراجع إلى التعليمات البرمجية المجمعة لـ JVM من لغات أخرى
- قم بتحرير ملفات المصدر في IDE المفضل لديك مع تمييز بناء الجملة وتحديد الخطأ والإكمال التلقائي
- تريد أن تكون قادرًا على تجميع الملفات باستخدام نظام البناء المفضل لديك: maven أو gradle أو غيره
- تريد أن تكون قادرًا على كتابة الاختبارات وتشغيلها كجزء من حل التكامل المستمر
إذا كان بإمكانك فعل ذلك ، فسيكون تبني لغتك أسهل بكثير.
فكيف نحقق ذلك؟ في بقية المنشور نقوم بفحص القطع المختلفة التي نحتاجها لجعل هذا ممكنًا.
الاعراب والترجمة
أول شيء عليك القيام به لتحويل ملفاتك المصدر في برنامج ما هو تحليلها ، والحصول على تمثيل Abstract-Syntax-Tree (AST) للمعلومات الواردة في الكود. في هذه المرحلة ، ستحتاج إلى التحقق من صحة الشفرة: هل توجد أخطاء نحوية؟ أخطاء دلالية؟ تحتاج إلى العثور عليها جميعًا وإبلاغ المستخدم بها. إذا سارت الأمور بسلاسة ، فلا تزال بحاجة إلى حل الرموز. على سبيل المثال ، هل تشير "قائمة" إلى java.util.List أو java.awt.List ؟ عندما تستدعي طريقة محملة بشكل زائد ، ما الطريقة التي تستدعيها؟ أخيرًا ، تحتاج إلى إنشاء رمز ثانوي لبرنامجك.
لذلك ، من الكود المصدري إلى الرمز الثانوي المترجم ، هناك ثلاث مراحل رئيسية:
- بناء AST
- تحليل وتحويل AST
- إنتاج رمز بايت من AST
دعونا نرى تلك المراحل بالتفصيل.
بناء AST : الاعراب هو نوع من حل المشكلة. هناك العديد من الأطر ولكن أقترح عليك استخدام ANTLR. إنه معروف جيدًا ويتم صيانته جيدًا وله بعض الميزات التي تجعل من السهل تحديد القواعد النحوية (يتعامل مع قواعد أقل تكرارية - لا تحتاج إلى فهم ذلك ولكن كن شاكراً لأنه يفعل ذلك!).
تحليل وتحويل AST : قد تكون كتابة نظام الكتابة والتحقق من الصحة ودقة الرمز صعبة وتتطلب الكثير من العمل. هذا الموضوع وحده يتطلب وظيفة منفصلة. في الوقت الحالي ، ضع في اعتبارك أن هذا هو الجزء من المترجم الذي ستنفق عليه معظم الجهد.
إنتاج كود بايت من AST : هذه المرحلة الأخيرة ليست بهذه الصعوبة في الواقع. يجب أن تكون قد حللت الرموز في المرحلة السابقة وأعدت التضاريس بحيث يمكنك بشكل أساسي ترجمة العقد الفردية من AST المحول إلى تعليمات رمز بايت واحد أو عدد قليل. قد تتطلب هياكل التحكم بعض العمل الإضافي لأنك ستقوم بترجمة الحلقات التكرارية والمفاتيح و ifs وما إلى ذلك في سلسلة من القفزات الشرطية وغير المشروطة (نعم ، أسفل لغتك الجميلة ستظل هناك مجموعة من الأشياء). أنت بحاجة إلى معرفة كيفية عمل JVM داخليًا ، لكن التنفيذ الفعلي ليس بهذه الصعوبة.
التكامل مع اللغات الأخرى
عندما تحصل على السيطرة العالمية للغتك ، ستتم كتابة جميع التعليمات البرمجية باستخدامها حصريًا. ولكن كخطوة وسيطة ، من المحتمل أن يتم استخدام لغتك جنبًا إلى جنب مع لغات JVM الأخرى. ربما سيبدأ شخص ما في كتابة فصلين دراسيين أو وحدات صغيرة بلغتك داخل مشروع أكبر. من المعقول أن تتوقع أن تكون قادرًا على مزج عدة لغات JVM. إذن ، كيف تؤثر على أدوات لغتك؟

تحتاج إلى التفكير في سيناريوهين مختلفين:
- لغتك والآخرون يعيشون في وحدات مجمعة بشكل منفصل
- لغتك والآخرون يعيشون في نفس الوحدات ويتم تجميعهم معًا
في السيناريو الأول ، تحتاج التعليمات البرمجية الخاصة بك فقط إلى استخدام التعليمات البرمجية المجمعة المكتوبة بلغات أخرى. على سبيل المثال ، يمكن تجميع بعض التبعيات مثل Guava أو الوحدات النمطية في نفس المشروع بشكل منفصل. يتطلب هذا النوع من التكامل شيئين: أولاً ، يجب أن تكون قادرًا على تفسير ملفات الفصل التي تنتجها اللغات الأخرى لحل الرموز لها وإنشاء الرمز الثانوي لاستدعاء هذه الفئات. النقطة الثانية خاصة بالنقطة الأولى: قد ترغب الوحدات الأخرى في إعادة استخدام الكود المكتوب بلغتك بعد تجميعها. الآن ، هذه ليست مشكلة عادة لأن Java يمكن أن تتفاعل مع معظم ملفات الفصل. ومع ذلك ، لا يزال بإمكانك كتابة ملفات فئة صالحة لـ JVM ولكن لا يمكن استدعاؤها من Java (على سبيل المثال لأنك تستخدم معرفات غير صالحة في Java).
السيناريو الثاني أكثر تعقيدًا: افترض أن لديك فئة A محددة في كود Java وفئة B مكتوبة بلغتك. افترض أن الفئتين تشيران إلى بعضهما البعض (على سبيل المثال ، يمكن أن يمتد A إلى B و B يمكن أن يقبل A كمعامل لنفس الطريقة). النقطة المهمة الآن هي أن مترجم Java لا يمكنه معالجة الكود في لغتك ، لذلك عليك أن تزوده بملف فئة للفئة B. ولكن لتجميع الفئة B ، فأنت بحاجة إلى إدراج مراجع للفئة A. للحصول على نوع من برنامج التحويل البرمجي الجزئي لجافا ، والذي يمنحك ملف مصدر جافا قادرًا على تفسيره وإنتاج نموذج منه يمكنك استخدامه لتجميع صنفك ب. لاحظ أن هذا يتطلب منك القدرة على تحليل كود جافا (باستخدام شيء مثل JavaParser) وحل الرموز. إذا لم تكن لديك فكرة من أين تبدأ ، فقم بإلقاء نظرة على برنامج java-code-solver.
الأدوات: Gradle ، Maven ، Test Frameworks ، CI
الخبر السار هو أنه يمكنك جعل حقيقة أنهم يستخدمون وحدة مكتوبة بلغتك شفافة تمامًا للمستخدم من خلال تطوير مكون إضافي لـ gradle أو maven. يمكنك توجيه نظام الإنشاء لتجميع الملفات بلغة البرمجة الخاصة بك. سيستمر المستخدم في تشغيل تجميع mvn أو تجميع gradle ولا يلاحظ أي فرق.
النبأ السيئ هو أن كتابة ملحقات Maven ليس بالأمر السهل: الوثائق سيئة للغاية وغير مفهومة وقديمة في الغالب أو ببساطة خاطئة . نعم ، لا يبدو ذلك مريحًا. لم أكتب بعد الإضافات الخاصة بـ gradle ولكن يبدو الأمر أسهل بكثير.
لاحظ أنه يجب عليك أيضًا التفكير في كيفية إجراء الاختبارات باستخدام نظام الإنشاء. بالنسبة للاختبارات الداعمة ، يجب أن تفكر في إطار عمل أساسي للغاية لاختبار الوحدة ويجب عليك دمجه مع نظام البناء ، بحيث يبحث تشغيل الاختبار المخضرم عن الاختبارات في لغتك ، وتجميعها وتشغيلها لإبلاغ المستخدم بالإخراج.
نصيحتي هي إلقاء نظرة على الأمثلة المتاحة: أحدها هو البرنامج المساعد Maven للغة برمجة تورين.
بمجرد تنفيذه ، يجب أن يكون كل شخص قادرًا على تجميع ملفات المصدر المكتوبة بلغتك بسهولة واستخدامها في خدمات التكامل المستمر مثل Travis.
البرنامج المساعد IDE
سيكون المكون الإضافي لـ IDE هو الأداة الأكثر وضوحًا لمستخدميك وشيء سيؤثر بشكل كبير على إدراك لغتك. يمكن أن يساعد المكون الإضافي الجيد المستخدم على تعلم اللغة من خلال توفير الإكمال التلقائي الذكي والأخطاء السياقية وإعادة البناء المقترحة.
الآن ، الإستراتيجية الأكثر شيوعًا هي اختيار IDE واحد (عادةً Eclipse أو IntelliJ IDEA) وتطوير مكون إضافي محدد له. ربما تكون هذه هي القطعة الأكثر تعقيدًا في سلسلة أدواتك. هذا هو الحال لعدة أسباب: أولاً وقبل كل شيء ، لا يمكنك إعادة استخدام العمل الذي ستقضيه في تطوير المكون الإضافي الخاص بك لـ IDE واحد للآخرين. سيكون Eclipse والمكوِّن الإضافي IntelliJ منفصلين تمامًا. النقطة الثانية هي أن تطوير البرنامج المساعد IDE ليس شائعًا جدًا ، لذلك لا يوجد الكثير من الوثائق والمجتمع صغير. هذا يعني أنه سيتعين عليك قضاء الكثير من الوقت في اكتشاف الأشياء بنفسك. لقد قمت شخصيًا بتطوير مكونات إضافية لـ Eclipse و IntelliJ IDEA. بقيت أسئلتي على منتديات Eclipse بدون إجابة لأشهر أو سنوات. كان حظي أفضل في منتديات IntelliJ ، وأحيانًا أحصل على إجابة من المطورين. ومع ذلك ، فإن قاعدة المستخدمين لمطوري المكونات الإضافية أصغر و API بيزنطية للغاية. استعد للمعاناة.
هناك بديل لكل هذا ، وهو استخدام Xtext. Xtext هو إطار عمل لتطوير المكونات الإضافية لـ Eclipse و IntelliJ IDEA والويب. لقد وُلد على Eclipse وتم تمديده مؤخرًا لدعم المنصات الأخرى ، لذلك لا توجد خبرة كبيرة في ذلك ولكن يمكن أن يكون بديلاً يستحق النظر فيه. دعني أوضح هذا الأمر: الطريقة الوحيدة لتطوير مكون إضافي جيد جدًا هو تطويره باستخدام واجهة برمجة التطبيقات الأصلية لكل IDE. ومع ذلك ، مع Xtext ، يمكنك الحصول على شيء لائق بشكل معقول بجزء بسيط من الجهد - كل ما عليك هو إعطائه لبناء جملة لغتك وتحصل على أخطاء في بناء الجملة / إكمال مجانًا. لا يزال يتعين عليك تنفيذ دقة الرمز والأجزاء الصعبة ، ولكن هذه نقطة بداية مثيرة للاهتمام ؛ ومع ذلك ، فإن البتات الصعبة هي التكامل مع مكتبات النظام الأساسي المحددة لحل رموز Java ، لذا فإن هذا لن يحل جميع مشاكلك حقًا.
الاستنتاجات
هناك العديد من الطرق التي قد تفقد بها المستخدمين المحتملين الذين أبدوا اهتمامًا بلغتك. يعد تبني لغة جديدة تحديًا لأنه يتطلب تعلمها وتكييف عاداتنا التنموية. من خلال تقليل الاستنزاف قدر الإمكان والاستفادة من النظام البيئي المعروف بالفعل لمستخدميك ، يمكنك منع المستخدمين من الاستسلام قبل أن يتعلموا ويحبوا لغتك.
في السيناريو المثالي ، يمكن للمستخدم استنساخ مشروع بسيط مكتوب بلغتك ، وبنائه باستخدام الأدوات القياسية (Maven أو Gradle) دون ملاحظة أي اختلاف. إذا أراد تعديل المشروع ، فيمكنه فتحه في محرره المفضل وسيساعد المكون الإضافي في توضيح الأخطاء وتقديم الإكمالات الذكية. هذا سيناريو يختلف كثيرًا عن الاضطرار إلى معرفة كيفية استدعاء المترجم الخاص بك وتحرير الملفات باستخدام المفكرة. يمكن للنظام البيئي المحيط بلغتك أن يحدث فرقًا حقًا ، وفي الوقت الحاضر يمكن بناؤه بجهد معقول.
نصيحتي هي أن تكون مبدعًا في لغتك ، ولكن ليس في أدواتك. قلل الصعوبات الأولية التي يتعين على الأشخاص مواجهتها لتبني لغتك باستخدام معايير مألوفة.
تصميم لغة سعيد!
مزيد من القراءة على مدونة Toptal Engineering:
- كيفية الاقتراب من كتابة المترجم الفوري من الصفر
