Kullanılabilir JVM Dilleri Oluşturma: Genel Bir Bakış

Yayınlanan: 2022-03-11

Bir dil yaratmanın birkaç olası nedeni vardır ve bunlardan bazıları hemen açık değildir. Java Sanal Makinesi (JVM) için mevcut araçları mümkün olduğunca yeniden kullanarak bir dil yapma yaklaşımı ile birlikte sunmak istiyorum. Bu şekilde geliştirme çabasını azaltacağız ve kullanıcıya tanıdık bir araç zinciri sağlayarak yeni programlama dilimizi benimsemeyi kolaylaştıracağız.

Kullanılabilir JVM Dilleri Oluşturma: Genel Bir Bakış

Serinin ilki olan bu makalede, JVM için kendi programlama dilimizi oluşturmaya dahil olan strateji ve çeşitli araçlara genel bir bakış sunacağım. gelecek makalelerde, uygulama ayrıntılarına gireceğiz.

Neden JVM Dilinizi Oluşturun?

Zaten sonsuz sayıda programlama dili var. Öyleyse neden yeni bir tane yaratma zahmetine giresiniz? Bunun birçok olası cevabı var.

Her şeyden önce, birçok farklı türde dil vardır: genel amaçlı bir programlama dili (GPL) mi yoksa alana özel bir programlama dili mi oluşturmak istiyorsunuz? İlk tür, Java veya Scala gibi dilleri içerir: çok sayıda soruna yeterince iyi çözümler yazmayı amaçlayan diller. Etki Alanına Özgü Diller (DSL) bunun yerine belirli bir dizi sorunu çok iyi çözmeye odaklanır. HTML veya Latex'i düşünün: Java'da ekranda çizim yapabilir veya belgeler oluşturabilirsiniz, ancak bu hantal olurdu, bunun yerine bu DSL'ler ile belgeleri çok kolay bir şekilde oluşturabilirsiniz, ancak bunlar o belirli alanla sınırlıdır.

Belki de üzerinde çok sık çalıştığınız ve bir DSL oluşturmanın mantıklı olabileceği bir dizi problem vardır. Aynı türden sorunları defalarca çözerken sizi çok üretken kılacak bir dil.

Belki de bunun yerine bir GPL oluşturmak istiyorsunuz çünkü bazı yeni fikirleriniz vardı, örneğin ilişkileri birinci sınıf vatandaşlar olarak temsil etmek veya bağlamı temsil etmek.

Son olarak, eğlenceli, havalı ve bu süreçte çok şey öğreneceğiniz için yeni bir dil oluşturmak isteyebilirsiniz.

Gerçek şu ki, JVM'yi hedeflerseniz, daha az çabayla kullanılabilir bir dil elde edebilirsiniz, bunun nedeni:

  • Sadece bayt kodu oluşturmanız gerekiyor ve kodunuz JVM'nin olduğu tüm platformlarda mevcut olacak.
  • JVM için mevcut olan tüm kitaplıklardan ve çerçevelerden yararlanabileceksiniz.

Bu nedenle, JVM'de bir dil geliştirmenin maliyeti büyük ölçüde azalır ve JVM dışında ekonomik olmayacak senaryolarda yeni diller oluşturmak mantıklı olabilir.

Kullanılabilir hale getirmek için neye ihtiyacınız var?

Dilinizi kullanmanız için mutlaka ihtiyacınız olan bazı araçlar vardır - bu araçlar arasında bir ayrıştırıcı ve bir derleyici (veya bir yorumlayıcı) vardır. Ancak bu yeterli değildir. Dilinizi pratikte gerçekten kullanılabilir kılmak için, muhtemelen mevcut araçlarla bütünleşen, alet zincirinin diğer birçok bileşenini sağlamanız gerekir.

İdeal olarak şunları yapabilmek istersiniz:

  • JVM için diğer dillerden derlenen kod referanslarını yönetin
  • Sözdizimi vurgulama, hata tanımlama ve otomatik tamamlama ile favori IDE'nizdeki kaynak dosyaları düzenleyin
  • Favori yapı sisteminizi kullanarak dosyaları derleyebilmek istiyorsunuz: maven, gradle veya diğerleri
  • Sürekli Entegrasyon çözümünüzün bir parçası olarak testler yazabilmek ve bunları çalıştırabilmek istiyorsunuz.

Bunu yapabilirseniz, dilinizi benimsemek çok daha kolay olacaktır.

Peki bunu nasıl başarabiliriz? Yazının geri kalanında, bunu mümkün kılmak için ihtiyaç duyduğumuz farklı parçaları inceleyeceğiz.

Ayrıştırma ve Derleme

Kaynak dosyalarınızı bir programa dönüştürmek için yapmanız gereken ilk şey, kodda yer alan bilgilerin Soyut-Sözdizimi-Ağacı (AST) temsilini elde ederek onları ayrıştırmaktır. Bu noktada kodu doğrulamanız gerekecek: sözdizimsel hatalar var mı? Anlamsal hatalar? Hepsini bulup kullanıcıya bildirmeniz gerekiyor. Her şey yolunda giderse, yine de sembolleri çözmeniz gerekir. Örneğin, “Liste” java.util.List veya java.awt.List anlamına mı geliyor? Aşırı yüklenmiş bir yöntemi çağırdığınızda, hangisini çağırıyorsunuz? Son olarak, programınız için bayt kodu oluşturmanız gerekir.

Bu nedenle, kaynak koddan derlenmiş bayt koduna kadar üç ana aşama vardır:

  1. AST Oluşturma
  2. AST'yi analiz etme ve dönüştürme
  3. AST'den bayt kodunun üretilmesi

Bu aşamaları ayrıntılı olarak görelim.

Bir AST oluşturmak: ayrıştırma bir tür çözülmüş problemdir. Piyasada birçok framework var ama ANTLR kullanmanızı öneririm. İyi bilinir, iyi korunur ve gramerleri belirlemeyi kolaylaştıran bazı özelliklere sahiptir (daha az özyinelemeli kuralları işler - bunu anlamanıza gerek yok ama anladığına şükredin!).

AST'yi analiz etmek ve dönüştürmek : bir tür sistemi yazmak, doğrulama ve sembol çözünürlüğü zor olabilir ve oldukça fazla çalışma gerektirebilir. Bu konu tek başına ayrı bir yazı gerektirecektir. Şimdilik bunun derleyicinizin çabanın çoğunu harcayacağınız kısmı olduğunu düşünün.

AST'den bayt kodu üretmek : bu son aşama aslında o kadar da zor değil. Önceki aşamada sembolleri çözmüş ve araziyi hazırlamış olmalısınız, böylece temel olarak dönüştürülmüş AST'nizin tek düğümlerini bir veya birkaç bayt kodu talimatına çevirebilirsiniz. Kontrol yapıları biraz ekstra çalışma gerektirebilir çünkü for-döngülerinizi, anahtarlarınızı, if'lerinizi ve benzerlerini bir dizi koşullu ve koşulsuz atlamada çevireceksiniz (evet, güzel dilinizin altında hala bir sürü goto olacaktır). JVM'nin dahili olarak nasıl çalıştığını öğrenmeniz gerekiyor, ancak gerçek uygulama o kadar da zor değil.

Diğer Dillerle Entegrasyon

Diliniz için dünya hakimiyetini elde ettiğinizde, tüm kodlar yalnızca dil kullanılarak yazılacaktır. Ancak bir ara adım olarak, diliniz muhtemelen diğer JVM dillerinde kullanılacaktır. Belki birileri daha büyük bir proje içinde kendi dilinizde birkaç sınıf veya küçük modüller yazmaya başlayacaktır. Birkaç JVM dilini karıştırabilmeyi beklemek mantıklıdır. Peki, dil araçlarınızı nasıl etkiler?

İki farklı senaryoyu göz önünde bulundurmanız gerekir:

  • Diliniz ve diğerleri ayrı ayrı derlenmiş modüllerde yaşıyor
  • Sizin diliniz ve diğerleri aynı modüllerde yaşar ve birlikte derlenir

İlk senaryoda, kodunuzun yalnızca diğer dillerde yazılmış derlenmiş kodu kullanması gerekir. Örneğin, aynı projedeki Guava veya modüller gibi bazı bağımlılıklar ayrı ayrı derlenebilir. Bu tür bir entegrasyon iki şey gerektirir: ilk olarak, diğer diller tarafından üretilen sınıf dosyalarını onlara sembolleri çözümlemek için yorumlayabilmeli ve bu sınıfları çağırmak için bayt kodunu oluşturabilmelisiniz. İkinci nokta, birinciye benzer: diğer modüller, derlendikten sonra kendi dilinizde yazılmış kodu yeniden kullanmak isteyebilir. Şimdi, normalde bu bir sorun değil çünkü Java çoğu sınıf dosyasıyla etkileşime girebilir. Ancak yine de JVM için geçerli olan ancak Java'dan çağrılamayan sınıf dosyaları yazmayı başarabilirsiniz (örneğin, Java'da geçerli olmayan tanımlayıcılar kullandığınız için).

İkinci senaryo daha karmaşıktır: Java kodunda tanımlanmış bir A sınıfınız ve kendi dilinizde yazılmış bir B sınıfınız olduğunu varsayalım. İki sınıfın birbirine atıfta bulunduğunu varsayalım (örneğin, A, B'yi genişletebilir ve B, A'yı aynı yöntem için bir parametre olarak kabul edebilir). Şimdi mesele şu ki, Java derleyicisi kodu kendi dilinizde işleyemez, bu yüzden ona B sınıfı için bir sınıf dosyası sağlamanız gerekir. Ancak B sınıfını derlemek için A sınıfına referanslar eklemeniz gerekir. O halde yapmanız gereken şudur: bir Java kaynak dosyası verilen, onu yorumlayabilen ve B sınıfınızı derlemek için kullanabileceğiniz bir model üretebilen bir tür kısmi Java derleyicisine sahip olmak. Bunun Java kodunu ayrıştırabilmenizi gerektirdiğini unutmayın (kullanarak JavaParser gibi bir şey) ve sembolleri çözün. Nereden başlayacağınız hakkında hiçbir fikriniz yoksa Java-symbol-solver'a bir göz atın.

Araçlar: Gradle, Maven, Test Çerçeveleri, CI

İyi haber şu ki, gradle veya maven için bir eklenti geliştirerek kendi dilinizde yazılmış bir modül kullandıklarını kullanıcı için tamamen şeffaf hale getirebilirsiniz. Derleme sistemine, programlama dilinizde dosyaları derlemesi talimatını verebilirsiniz. Kullanıcı mvn compile veya gradle merge çalıştırmaya devam edecek ve herhangi bir fark görmeyecektir.

Kötü haber şu ki Maven eklentileri yazmak kolay değil: belgeler çok zayıf, anlaşılır değil ve çoğunlukla güncel değil veya basitçe yanlış . Evet, kulağa rahatlatıcı gelmiyor. Henüz gradle eklentileri yazmadım ama çok daha kolay görünüyor.

Ayrıca derleme sistemi kullanılarak testlerin nasıl çalıştırılabileceğini de düşünmeniz gerektiğini unutmayın. Destekleyici testler için, birim testi için çok temel bir çerçeve düşünmeli ve bunu derleme sistemiyle entegre etmelisiniz, böylece maven testi çalıştırmak kendi dilinizde testler arar, derler ve çalıştırır ve çıktıyı kullanıcıya bildirir.

Benim tavsiyem mevcut örneklere bakmak: bunlardan biri Torino programlama dili için Maven eklentisi.

Bir kez uyguladığınızda, herkes kendi dilinizde yazılmış kaynak dosyaları kolayca derleyebilmeli ve bunu Travis gibi Sürekli Entegrasyon hizmetlerinde kullanabilmelidir.

IDE Eklentisi

Bir IDE eklentisi, kullanıcılarınız için en görünür araç olacak ve dilinizin algılanmasını büyük ölçüde etkileyecek bir şey olacaktır. İyi bir eklenti, akıllı otomatik tamamlama, bağlamsal hatalar ve önerilen yeniden düzenlemeleri sağlayarak kullanıcının dili öğrenmesine yardımcı olabilir.

Şimdi, en yaygın strateji bir IDE (tipik olarak Eclipse veya IntelliJ IDEA) seçmek ve bunun için özel bir eklenti geliştirmektir. Bu muhtemelen alet zincirinizin en karmaşık parçasıdır. Bu, birkaç nedenden dolayı böyledir: her şeyden önce, eklentinizi geliştirmek için harcayacağınız işi, bir IDE için diğerleri için makul bir şekilde yeniden kullanamazsınız. Eclipse ve IntelliJ eklentiniz tamamen ayrı olacak. İkinci nokta, IDE eklenti geliştirmenin çok yaygın olmayan bir şey olmasıdır, bu nedenle çok fazla belge yoktur ve topluluk küçüktür. Bu, kendiniz için bir şeyler bulmak için çok zaman harcamanız gerekeceği anlamına gelir. Eclipse ve IntelliJ IDEA için kişisel olarak eklentiler geliştirdim. Eclipse forumlarındaki sorularım aylarca veya yıllarca cevapsız kaldı. IntelliJ forumlarında daha şanslıydım ve bazen geliştiricilerden bir yanıt aldım. Ancak eklenti geliştiricilerinin kullanıcı tabanı daha küçüktür ve API çok Bizanslıdır. Acı çekmeye hazırlanın.

Tüm bunların bir alternatifi var ve o da Xtext kullanmak. Xtext, Eclipse, IntelliJ IDEA ve web için eklentiler geliştirmeye yönelik bir çerçevedir. Eclipse'de doğdu ve diğer platformları desteklemek için yakın zamanda genişletildi, bu yüzden bu konuda çok fazla deneyim yok ama dikkate alınmaya değer bir alternatif olabilir. Şunu açıklığa kavuşturmama izin verin: Çok iyi bir eklenti geliştirmenin tek yolu, onu her bir IDE'nin yerel API'sini kullanarak geliştirmektir. Bununla birlikte, Xtext ile, çabanın bir kısmı ile makul derecede iyi bir şeye sahip olabilirsiniz - sadece dilinizin sözdizimine verirsiniz ve sözdizimi hatalarını/tamamlamayı ücretsiz olarak alırsınız. Yine de, sembol çözünürlüğünü ve zor kısımlarını uygulamanız gerekiyor, ancak bu çok ilginç bir başlangıç ​​noktası; ancak, sabit bitler, Java sembollerini çözmek için platforma özel kitaplıklarla entegrasyondur, bu nedenle bu, tüm sorunlarınızı gerçekten çözmeyecektir.

Sonuçlar

Dilinize ilgi gösteren potansiyel kullanıcıları kaybetmenin birçok yolu vardır. Yeni bir dili benimsemek zorlu bir iştir çünkü onu öğrenmeyi ve geliştirme alışkanlıklarımızı uyarlamayı gerektirir. Yıpranmayı mümkün olduğunca azaltarak ve kullanıcılarınız tarafından zaten bilinen ekosistemden yararlanarak, kullanıcıların dilinizi öğrenmeden ve dilinize aşık olmadan vazgeçmelerini önleyebilirsiniz.

İdeal senaryoda, kullanıcınız kendi dilinizde yazılmış basit bir projeyi klonlayabilir ve herhangi bir fark görmeden standart araçları (Maven veya Gradle) kullanarak inşa edebilir. Eğer projeyi düzenlemek isterse, en sevdiği düzenleyicide açabilir ve eklenti ona hataları işaret etmeye ve akıllı tamamlamalar sağlamaya yardımcı olur. Bu, derleyicinizi nasıl çağıracağınızı ve not defteri kullanarak dosyaları nasıl düzenleyeceğinizi bulmaktan çok farklı bir senaryodur. Dilinizin etrafındaki ekosistem gerçekten fark yaratabilir ve günümüzde makul bir çabayla oluşturulabilir.

Benim tavsiyem, kendi dilinizde yaratıcı olun, ancak araçlarınızda değil. Bilinen standartları kullanarak, insanların dilinizi benimsemek için karşılaşacakları ilk zorlukları azaltın.

Mutlu dil tasarımı!


Toptal Mühendislik Blogunda Daha Fazla Okuma:

  • Sıfırdan Tercüman Yazmaya Nasıl Yaklaşılır?