Xtext – DSL Framework, Bölüm 2

İlk bölümde elimden geldiÄŸince, Xtext framework’unun ne olduÄŸunu, ne için Xtext framework’unu kullanmakta olduÄŸumu, kurulumunun nasıl yapılacağını anlatmaya çalıştım. Bu bölümde ise, ilk bölümde yapmış olduÄŸum örnekten devam ederek baÅŸka ne ÅŸekilde oluÅŸturduÄŸunuz dili test edebileceÄŸinizi anlatmaya çalışacağım.

Previously on Xtext

Öncelikle Xtext projemizi oluşturmuştuk. Projemizi oluşturduğumuzda bizim için 3 farklı projenin oluşturulacağından bahsetmiştik. Bu projeler:

  1. org.xtext.bhdrkn.fouroperation, dilin özelliklerini ve nasıl işleyeceğini bu proje altında belirledik.
  2. org.xtext.bhdrkn.fouroperation.generator, ilk dilimizi bu klasörün altına .java dosyaları oluşturarak işledik. Şimdi ise yine bu klasörün altında Xpand ve Xtend dillerini kullanarak dilimizin dosyasını nasıl işleyeceğimize bakacağız.
  3. org.xtext.bhdrkn.fouroperation.ui

Sonra, tam sayılar üzerinde dört işlemi gerçekleştirebilecek bir dili nasıl oluşturacağımıza bakmıştık. İlk örneğimiz olduğundan olabildiğince sade tutup sadece iki sayı üzerinden bu dört işlemin nasıl yapılacağını incelemiştik. Dilimizin dosya uzantısını .op olarak belirlemiş ve örneklerimizde bhdrkn.op dosyasını kullanmıştık. Şimdide yine bu oluşturduğumuz dilin kurallarını destekleyen bhdrkn.op dosyasından yardım alarak devam edeceğiz.

bhdrkn.op / Example.op


operation bhdrkn {
 8 + 4
 14 - 2
 3 * 4
 24 / 2
}

Xpand ve Xtend

Öncelikle Xpand ve Xtend’in neler olduÄŸuna bakalım. Xpand ve Xtend, Xtext framework’ü ile birlikte gelen iki ayrı dil. Biz bunları oluÅŸturduÄŸumuz dili yorumlamak için kullanıyoruz. Aslında temelde ilk bölümde java ile yaptığımız iÅŸi bu bölümde Xpand ve Xtend ile yapacağız. Basit olması açısından, hazırda oluÅŸmuÅŸ olan 2. projeyi yani generator ile biten projeyi kullanacağız.Åžu adımları takip edeceÄŸiz:

  1. Öncelikle oluşturduğumuz dilde bir dosya yazacağız. Oluşturduğumuz dilde doğru bir şekilde yazdığımızdan emin olduktan sonra bu dosyayı kullanacağımızı belirteceğiz.
  2. .mwe2 uzantılı bir generator dosyasında kullanacağımız dosyayı ve bu dosyayı nerden, hangi tip class kullanarak okuyacağımızı belirteceğiz.
  3. Dosya okunduktan sorna ne şekilde çalışacağını söyleyecek fonksiyonları yazacağız. Bunun için Xpand dilini kullanacağız.
  4. Xpand ile yazılmış fonksiyonların çalışırken kullanacağı ve/ve ya classlara eklemek istediğimiz fonksiyonları yazacağız. Bunun için ise Xtend dilini kullanacağız.
  5. Sonra oluşturduğumuz kodu generate edip sonuçlarımızı göreceğiz.

Dosyamız zaten hazırda oluşturulmuş olduğundan (bhdrkn.op), sadece dosyanın içeriğini generator porjesinin altında src/model/Example.op dosyasının içerisine kopyalayın.

Generator Dosyasının Olusturulması

Yine generator projesinin altında src/workflow klasörünün altındaki FouroperationGenerator.mwe2 dosyayı açalım ve içeriğini aşağıdaki gibi değiştirelim.

FouroperationGenerator.mwe2


module workflow.FouroperationGenerator

import org.eclipse.emf.mwe.utils.*

var targetDir = "src-gen"
var fileEncoding = "UTF-8"
var modelPath = "src/model"

Workflow {

component = org.eclipse.xtext.mwe.Reader {
// lookup all resources on the classpath
// useJavaClassPath = true

// or define search scope explicitly
path = modelPath

// this class will be generated by the xtext generator
register = org.xtext.bhdrkn.FouroperationStandaloneSetup {}
load = {
slot = "operation" //greetings to operation
type = "Operation" //Greeting to Operation
}
}

component = org.eclipse.xpand2.Generator {
expand = "templates::Template::main FOREACH operation" // greetings to operation
outlet = {
path = targetDir
}
fileEncoding = fileEncoding
}
}

OlabildiÄŸince yaptığım deÄŸiÅŸiklikleri belirttim. Genel olarak oluÅŸturduÄŸumuz dosya yüklenirken hangi konumdan baÅŸlanıldığını(operation) ve baÅŸlanılan konumun hangi class’a karşılık(Operation) geldiÄŸini belirtiyoruz. Dosya içerisinde karşılaşılan her belirttiÄŸimiz class(Operation) için, hangi fonksiyonun çağırılacağını(templates paketi altında Template dosyası içinde main fonksiyonu) belirtiyoruz. Fonksiyonu ise az sonra Xpand ile yazacağız.

Xpand ile Fonksiyonun Olusturulması

Proje oluşurken yine bizim için bir Xpand dosyası oluşturuyor. Bu dosyayı generator projesinin altında src/templates klasörü içinde bulabilirsiniz. Template.xpt dosyasını açıp içeriğini aşağıdaki gibi değiştiriyoruz.

Template.xpt

«IMPORT org::xtext::bhdrkn::fouroperation»

«EXTENSION templates::Extensions»

«DEFINE main FOR Operation»
«EXPAND statement FOREACH this.statements»
«ENDDEFINE»

«DEFINE statement FOR Statement»
«EXPAND expression FOR this.expression»
«ENDDEFINE»

«DEFINE expression FOR Expression»
«FILE "bhdrkn" + this.eClass().name + ".txt"»
«IF this.eClass().name == "Addition"»
«((Addition)this).calculate()»
«ELSEIF this.eClass().name == "Minus"»
«((Minus)this).calculate()»
«ELSEIF this.eClass().name == "Multi"»
«((Multi)this).calculate()»
«ELSEIF this.eClass().name == "Div"»
«((Div)this).calculate()»
«ENDIF»
«ENDFILE»
«ENDDEFINE»

İlk başta oluşturduğumuz dilimizi içeren projeyi import ediyoruz. Ardından hangi Xtend dosyalarını kullanacağımızı belirtiyoruz. Sonra ise main fonksiyonumuzu yazuyoruz. Main fonksiyonumuz, Statement listesi şeklindeki statements değişkeninin içindeki her Statement için statement isminde başka bir fonksiyona dallanıyor.

“statement” fonksiyonu ise sahip olduÄŸu Expression türündeki expression deÄŸiÅŸkeni için baÅŸka bir fonksiyon çağırıyor. “expression” ismindeki bu fonksiyon ise hangi türden olduÄŸunu belirleyip ona göre dışarıda tanımlı baÅŸka bir fonksiyon çağırıyor. Bu fonksiyonsa ilgili deÄŸerleri hesaplayıp bize bir string döndürüyor. Bizde ‘”bhdrkn”+classAdı.txt‘ isimli bir dosyaya bu deÄŸerleri yazacağız. Dört farklı class kullanacağımız için, generetor projemizin altında src-gen klasörünün altında dört farklı dosya oluÅŸacak.

İlk başta harici foksiyon çağrıları ve başktaki Xtend eklenti kısmı hata verebilir. Birazdan Xtend kısmını yazınca hatalar ortadan kalkacaktır. Eğer import kısmında ya da başka kısımlarda hata ile karşılaşıyorsanız proje ve paket isimlerini doğru verdiğinizden emin olun.İlk bölüme bakıp karşılaştırabilirsiniz.

Xtend ile Harici Fonksiyonların Yazılması

Biz class deÄŸilde txt dosyası türettiÄŸimiz için, sadece harici fonksiyonlar yazacağız. Fakat kullanırken sizde göreceksiniz, bu yazdığımız harici fonksiyonlar, dilimizi oluÅŸtururken oluÅŸan class’larla bütünleÅŸecek. Åžimdi generator projesinin altında src/templates klasörünün içindeki Extensions.ext dosyasını açıyoruz ve içeriÄŸini aÅŸağıdaki gibi yapıyoruz.

Extensions.ext


import org::xtext::bhdrkn::fouroperation;

String calculate(Addition this) :
"Result is " + (this.left.toInteger() + this.right.toInteger()).toString();

String calculate(Minus this) :
"Result is " + (this.left.toInteger() - this.right.toInteger()).toString();

String calculate(Multi this) :
"Result is " + (this.left.toInteger() * this.right.toInteger()).toString();

String calculate(Div this) :
"Result is " + (this.left.toInteger() / this.right.toInteger()).toString();

Burda ise yine önce birinci projemizi ekliyoruz. Ardından ise dilimizi ilk oluÅŸturduÄŸumuzda oluÅŸan class’lar için calculate fonksiyonu yazıyoruz. Bu fonksiyon iÅŸlemi hesaplayıp bize string halinde döndürüyor. Yukarıdaki Xpand’de yazılmış Template.xpt dosyası içinde ise farklı dosyalar içerisine sonuçları yazıyoruz.

Kodun Generate Edilmesi

Buraya kadar gelmiÅŸ ve hiç bir dosyamızdan hata almıyorsak artık kodumuzu generate edebiliriz. Yapacağımız ÅŸey dilimizi ilk oluÅŸtururken yaptığımızla aynı. OluÅŸturduÄŸumuz, genereator projesi içerisindeki src/workflow klasörü altındaki FouroperationGenerator.mwe2 isimli dosyayı seçiyoruz ve MWE2 Workflow ÅŸeklinde çalıştırıyoruz. EÄŸer herÅŸey düzgün giderse Console’da son satır DONE ile bitiyor.

Herşey doğru gittiyse generator projesi içerisindeki src-gen/ klasörünün altında yeni oluşmuş dört farklı .txt dosyası göreceksiniz. Yaptığımız işlemlerin sonucu aynı olduğundan hepsinin içinde şu sonucu göreceksiniz:

Result: 12

Son

Umarım biraz daha yardımcı olabilmişimdir. Bundan sonra benim merak ettiğim fakat, bitime ödevimin kapsamına şimdilik girmeyen otomatik generate etme kısmı var. Sizinde gördüğünüz üzere biz elle generate ediyoruz. Fakat kendi dilimizi yazdıktan sonra, yazdığımız dosyayı çalıştırabilmeli ve sonuçları görebilmeliyiz.

Dört farklı dosya oluÅŸturma ile ilgili olarakta ÅŸunu söyleyebilirim. Xpand yaz dediÄŸiniz her dosyaya sıfırdan baÅŸlıyor. Yani yenisini oluÅŸturuyor. Xpand’in java dosyaları üretmek için kullanıldığını düşünürsek bu gayet mantıklı bir yaklaşım. Fakat bu yakÅŸalım bizim dört farklı dosyaya ihtiyaç duymamıza neden oluyor. Hatta eÄŸer ilk oluÅŸturduÄŸumuz örnek dil dosyamızda (bhdrkn.op) aynı iÅŸlemi birden fazla kullanırsak, sadece son olan iÅŸlemin sonucunu görebileceÄŸiz. Sadece örnek olarak deÄŸerlendirdiÄŸim için bir sorun çıkaracağını düşünmüyorum.

Birde tavsiyede bulunmak istiyorum. EÄŸer blog’lardan, forum’lardan ya da herhangibir tutorial’dan biÅŸeyler öğrenmeye çalışıyorsanız, lütfen önce sizin kullandığınız sürümde, örneÄŸin çalıştığından emin olun. Sonra kodu anlamaya çalışın. Xtext ile bir çok örnek gördüm ve çoÄŸu 0.7 versiyonu içindi. Önce anlamaya çalıştığımdan baya bir enerji ve zaman kaybettim. Siz siz olun önce çalıştığına emin olun.

Kaynaklar

Bu projeyi oluştururken şu kaynaklardan faydalandım.

Son olarak benim kullandığım Xtext 1.0.1 sürümü.

GitHub Adresi

İlk iki bölümde anlattğım kısımların birleştirilmiş haline aşağıdaki GitHub adresinden erişebilirsiniz.

https://github.com/bhdrkn/Xtext-Examples

End Of Line