More Related Content
Similar to Xtext practice
Similar to Xtext practice (20)
More from Shintaro Hosoai
More from Shintaro Hosoai (10)
Xtext practice
- 3. ©2014 Shintaro Hosoai
Step0-1: Sample Projectの作成
• Eclipse を起動します
• New > Example →ダイアログ表示
• Xtext Examples/Xtext State-Machine Exampleを選
択しNext
• 次ページの設定は変えずにFinish
• Workspaceに以下の二つのプロジェクトが作成
される
org.eclipse.xtext.example.fowlerdsl
org.eclipse.xtext.example.fowlerdsl.ui
32014/3/31 SEA関西プロセス分科会
- 4. ©2014 Shintaro Hosoai
Step0-2: 言語定義の確認
• org.eclipse.xtext.example.fowlerdsl
src/org.eclipse.xtext.example.fowlerdsl/
Statemachine.xtext
• ステートマシンDSLの言語定義
• src/org.eclipse.xtext.example.fowlerdsl/
GenerateStatemachine.mwe2
• 言語環境生成のためのワークフローと各種設定が
入っています.
• ・fileExtensions = “statemachine”: DSLの拡張子
42014/3/31 SEA関西プロセス分科会
- 5. ©2014 Shintaro Hosoai
Step0-3: 言語環境の生成
• org.eclipse.xtext.example.fowlerdslを開き,
src/org.eclipse.xtext.example.fowlerdsl/
GenerateStatemachine.mwe2
を右クリック > Run As > MWE2 Workflow
• 言語定義に基づいて,言語モデル,エディタプ
ラグイン等が生成されます.
• (Example では実はすでに環境生成されていま
す)
52014/3/31 SEA関西プロセス分科会
- 6. ©2014 Shintaro Hosoai
Step0-4 : 作成したDSLプラグインの
実行
• org.eclipse.xtext.example.fowlerdslを右クリック >
Run As > Eclipse Application
• 新しく作成したPluginを含むEclipseが起動しま
す.
• 起動したEclipseのPackage Explorerで右クリック
>New > Java Project,適当なプロジェクト名を
設定しFinish
• 作成したプロジェクトのsrcフォルダを右ク
リック>New > File,適当な名前.statemachineと
して作成
初回はプロジェクトにXtextの機能を追加する
か聞かれるため,Yes 62014/3/31 SEA関西プロセス分科会
- 7. ©2014 Shintaro Hosoai
Step0-5: DSLを書いてみる
• 右図のような信号のステートマシンを書いてみましょう.DSL構
成は以下の通り
event
event名 EventID
...
end
commands
command名 CommadID
...
end
state state名
actions { command名 }
event名 => 次state名
end
...
72014/3/31 SEA関西プロセス分科会
DSLイメージ
blue
entry/lightBlue
yellow
entry/lightYellow
red
entry/lightRed
toBlue
toYellow
toRed
EventID, CommandIDは任意
- 8. ©2014 Shintaro Hosoai
Step0-6: 記述例
events
toRed E001
toBlue E002
toYellow E003
end
commands
lightRed C001
lightYellow C002
lightBlue C003
end
state blue
actions { lightBlue }
toYellow => yellow
end
state yellow
actions { lightYellow }
toRed=>red
end
state red
actions { lightRed }
toBlue => blue
end
82014/3/31 SEA関西プロセス分科会
- 9. ©2014 Shintaro Hosoai
Step0-7 : 生成コードの確認と実行
• src-genフォルダ下に入力したDSLからJavaコー
ドが生成されています.
• src-genフォルダを右クリック>Build Path >
Use as Source Folder
• 生成されたJavaコードを右クリック>Run As >
Java Application
• コマンドラインからイベントを入力し,ステー
トマシンの動作を確認できます.
92014/3/31 SEA関西プロセス分科会
- 11. ©2014 Shintaro Hosoai
Step1-0:どんなDSL?
• TDDするときに,クラスのひな形とテストクラ
ス作るのめんどいよね!→ DSLで作ってみよう
112014/3/31 SEA関西プロセス分科会
UnitDSL
Mock
Class
Mock
Class
Mock
Class
Test
Class
Test
Class
Test
Class
クラス定義
メソッド定義
テスト定義
- 12. ©2014 Shintaro Hosoai
Step1-1:Projectの作成
• New > Project > Xtext Project
• Dialog
project name : jp.sea.kansai.example.unitdsl
☑Use default location
Language
Name : jp.sea.kansai.example.UnitDsl
Extensions : unit
Layout
□Create SDK feature project
Working sets
□Add Project to working sets
122014/3/31 SEA関西プロセス分科会
今回は利用しない
任意
DSLのファイル拡張子
(任意)
言語名,Project名と合
わせておくのが無難.
クラスになるのでCamel
で
プロジェクト名(任
意)
- 13. ©2014 Shintaro Hosoai
Step1-2 : 言語環境の生成
• jp.sea.kansai.example.unitdslプロジェクト
src/jp.sea.kansai.example/GenerateUnitDsl.mwe2
を開き,内容を確認.
• 上記を右クリック > Run as > MWE2 Workflow
• 各種ファイルが生成される
• unitdslプロジェクト
• src-gen/
• xtend-gen/
• model
• unitdsl.tests/
• src-gen
• unitdsl.ui
• /src-gen
• /xtend-gen
132014/3/31 SEA関西プロセス分科会
- 14. ©2014 Shintaro Hosoai
Step1-3 : 生成環境の実行
• jp.sea.kansai.example.unitdslプロジェクトを右ク
リック > Run As > Eclipse Application
• 新しいEclipseが起動する.→一旦終了
• jp.sea.kansai.example.unitdslプロジェクトを右ク
リック > Run As > Run Configuration
• 左のツリーからEclipse Application/Launch
Runtime Eclipse(名称が異なる場合もあり)を
選択
• ArgumentsタブのVM argumentsに以下を追加
-XX:MaxPermSize=128m (64以上であれば十分)
XtextはかなりHeapを食います,実行時にメモ
リエラーが出る場合は,上記オプションをご確
認ください.(Java 8 ではHeap問題が解決され
たっぽい? 142014/3/31 SEA関西プロセス分科会
- 15. ©2014 Shintaro Hosoai
Step1-4 : Greeting DSLを試す.
• 再度,生成環境を実行
• 新しく起動したEclipse上に新しくJava Projectを
作成
• DSLファイルの作成:New > File,適当な場所に
~.unitファイルを作成
• 初回はダイアログが表示されるのでYes(Xtext
Natureの追加)
• コンテンツアシストやシンタックスカラーリン
グが有効か確認してみましょう.
• 本プロジェクトは現状,コード生成は行われま
せん.
152014/3/31 SEA関西プロセス分科会
- 16. ©2014 Shintaro Hosoai
Step1-5 : Xtextを書き換える
• まずは,クラス構造を定義する部分を作る(型
を扱うとややこしいので,とりあえず以下のレ
ベルで)
unit name {
methodName
...
}
162014/3/31 SEA関西プロセス分科会
クラス名
メソッドは複
数個指定
Unit :
“unit” name=ID “{”
methods+=Method*
“}”;
Method:
name=ID;
Model:
units+=Unit*;
- 17. ©2014 Shintaro Hosoai
Step1-6 : 再生成・実行・確認
172014/3/31 SEA関西プロセス分科会
• 言語定義を変更した場合は,再度Generate
*.mwe2を実行して,言語環境を再生成する必
要があります.
• 再生成後,実行してみましょう.以下のように
Unitが記述できるようになっているはずです.
• unit Hogehoge{
• foo
• bar
• }
- 18. ©2014 Shintaro Hosoai
Step1-7 : コード生成の定義(1)
182014/3/31 SEA関西プロセス分科会
• jp.sea.kansai.example.unitdslプロジェクト
/src/jp.sea.kansai.example.generator/
UnitDslGenerator.xtendを開く
class UnitDslGenerator implements IGenerator {
override void doGenerate(Resource resource, IFileSystemAccess fsa) {
for(unit : resource.allContents.filter(typeof(Unit)).toIterable){
fsa.generateFile(unit.name+".java", genClass(unit));
fsa.generateFile(unit.name+"Test.java", genTestClass(unit));
}
}
次ページに続く
- 19. ©2014 Shintaro Hosoai
Step1-7 : コード生成の定義(1)
192014/3/31 SEA関西プロセス分科会
def genClass(Unit unit)'''
public class «unit.name» {
«FOR method:unit.methods»«genMethod(method)»«ENDFOR»
}
'''
def genMethod(Method method)'''
void «method.name»(){}
'''
def genTestClass(Unit unit)'''
public class «unit.name»Test {
}
'''
}
再度,実行,確認してみてください.
(コードテンプレート定義の際には再生成は必要ありません.)
src-genフォルダの中に,DSLに応じたJavaとTestコードが生成されているはず.
src-genフォルダをソースフォルダに指定すると,生成したコードがコンパイルさ
- 21. ©2014 Shintaro Hosoai
Step2-1 : Xtextの拡張(1)
• 前回作成した,Unit DSLを拡張していきましょ
う.
• 型周りを実装してみましょう
• unit className extends superClass {
retType methodName(paramType param)
}
212014/3/31 SEA関西プロセス分科会
Unit:
"unit" name=ID ("extends" parent=[Unit])?"{"
methods+=Method*
"}";
Method:
retType=[Unit] name=ID
("("params+=Param (","params+=Param)*")")?;
Param:
paramType=[Unit] param=ID;
[ ]で型を囲むと,インスタ
ンスの参照が行えます.
カンマ区切りの要素を作る時は,こ
のような記述をします.
Model:は変更な
し
引数がない場合は省略可にしてみまし
た
- 22. ©2014 Shintaro Hosoai
Step2-2 : Xtextの拡張(2)
• Primitiveも書けるようにしてみます.
222014/3/31 SEA関西プロセス分科会
Unit:
"unit" name=ID ("extends" parent=[Unit])?"{"
methods+=Method*
"}";
Method:
retType=([Unit]|PredefTypes) name=ID
("("params+=Param (","params+=Param)*")")?;
Param:
paramType=([Unit]|PredefTypes) param=ID;
PredefTypes:
type="int"| type="String" | type="Void";
再生成・実行してみま
しょう
- 23. ©2014 Shintaro Hosoai
Step2-3: テンプレートの拡張(1)
232014/3/31 SEA関西プロセス分科会
def genClass(Unit unit)'''
public class «unit.name» «IF unit.parent!=null»extends
«unit.parent.name»«ENDIF»{
«FOR method:unit.methods»«genMethod(method)»«ENDFOR»
}
'''
def genMethod(Method method)'''
«getTypeName(method.retType)» «method.name»(«FOR
param:method.params SEPARATOR","»«genParam(param)»«ENDFOR»){
}
'''
def genParam(Param param)'''
«getTypeName(param.paramType)» «param.param»
'''
- 24. ©2014 Shintaro Hosoai
Step2-3: テンプレートの拡張(2)
• 型に応じて名前を返す補助メソッドです.
• type=[Unit]|PredefTypesとしているため
typeはEObject(EMFのObject)型
になっています→
• 通常このような場合,オーバーロードできませ
んがdispatchを指定することで,型に応じたメ
ソッドが呼ばれます.
242014/3/31 SEA関西プロセス分科会
def dispatch getTypeName(Unit unit){
unit.name
}
def dispatch getTypeName(PredefTypes predef){
predef.type
}
EObject
Unit
PredefT
ypes
- 26. ©2014 Shintaro Hosoai
Step3-1 : Validation
• エディタにバリデーション(入力規則チェッ
ク)を付けてみましょう↓
• Validation機能は以下クラスで定義します.
src/jp.sea.kansai.example.validation/
UnitDslValidator.xtend
262014/3/31
- 27. ©2014 Shintaro Hosoai
Step3-2 : Validationの定義(1)
• @Checkを付けたメソッドが自動的に呼ばれま
す.
• 型ごとのチェックメソッドを列挙するだけでよ
い.
272014/3/31 SEA関西プロセス分科会
class UnitDslValidator extends AbstractUnitDslValidator {
public static val INVALID_NAME = 'invalidName'
@Check
def checkGreetingStartsWithCapital(Unit unit) {
if (!Character.isUpperCase(unit.name.charAt(0))) {
warning(‘Name should start with a capital’,
UnitDslPackage::Literals.UNIT__NAME, INVALID_NAME)
}
}
}
保存後,実行してみましょう
- 28. ©2014 Shintaro Hosoai
Step3-2: Validationの定義(2)
• Validator内で使える主要なメソッド
info() : 情報
warning() : 警告
error() : エラー
メソッドの使い方
info (メッセージ:String, 要素:
EStructuralFeature)
モデルで警告等を出す場合,モデルのどの要素なの
かを指定します.
DSL名Packageというクラスにモデル構造の定数が定義
されており,これを参照します.
例えば,Unitのname属性の場合
UnitDslPackge::Literals.UNIT__NAME
となります.
282014/3/31 SEA関西プロセス分科会
- 29. ©2014 Shintaro Hosoai
Step3-Ex : Xtextのビルドエラー対策
• Xtextの言語定義に不具合があった際のエラー
は,エラーメッセージを読んでも,どこに不具
合があるのか分かり辛いです.
• 言語定義は,内部的にAntlrというJavaのParser
ジェネレータのファイルに変換されます.
• 生成されたg(Antlr)ファイルのエラー行の付
近を確認し,// Rule ~等を探して該当するルー
ルを判別します.
• 他に良い方法があれば教えてください^^;
292014/3/31 SEA関西プロセス分科会
- 31. ©2014 Shintaro Hosoai
Step4-1 : Java要素の取り込み
• Xtextでは,Javaのライブラリを利用するような
DSLも作成できます.
• Java要素を用いるには,以下の作業が必要です.
• 言語定義にXbaseをMixinする
• 言語定義をJvmに適したものに変更する
• クラスとして扱う要素をXtextに伝える
312014/3/31
- 32. ©2014 Shintaro Hosoai
Step4-2 : Xtextの変更(1)
322014/3/31 SEA関西プロセス分科会
grammar jp.sea.kansai.example.UnitDsl with org.eclipse.xtext.xbase.Xbase
generate unitDsl "http://www.sea.jp/kansai/example/UnitDsl"
Model:
units+=Unit*;
Unit:
"unit" name=ValidID ("extends" parent=JvmTypeReference)?"{"
methods+=Method*
"}";
Method:
retType=JvmTypeReference name=ValidID (‚(‛params+=FullJvmFormalParameter
(","params+=FullJvmFormalParameter )*")")?;
PredefTypes:
type="int"| type="String" | type="Void";
Value :
INT|STRING;
- 33. ©2014 Shintaro Hosoai
Step4-2 : Xtextの変更(2)
• ベース言語の変更
grammar jp.sea.kansai.example.UnitDsl
with org.eclipse.xtext.xbase.Xbase
ベースとなる言語をXbaseに変更します.
Xbaseは,Xtendのコア部のようなもので,Jvm統
合に必要な言語要素が定義されています.
• Referenceの変更
型を参照している箇所を,JvmTypeReferenceに
変更します.[Unit]等は削除します.
• Parameterの変更
FullJvmFormalParameterという便利そうな型が
あるので利用します
• IDの変更
IDの部分をValidIDに変更します.
332014/3/31 SEA関西プロセス分科会
- 34. ©2014 Shintaro Hosoai
Step4-Ex : 左再帰
• この変更の過程で,Method定義が左再帰になってし
まっているようです.(JvmTypeReferenceの中で
Methodを参照しているのでしょうか・・)
• 正攻法でいくのであれば,左再帰を除去するのです
が,,今回は時間の都合上(というか作者の能力
上・・)Back Trackを有効にします.生成時間が多少伸
びるのと・・もしかしたら言語に少し悪影響があるか
も.
• GenerateUnitDsl.mwe2を開き,backtrackを検索.コメン
トを外す
fragment = parser.antlr.XtextAntlrGeneratorFragment
auto-inject {
options = {
backtrack = true
}
342014/3/31 SEA関西プロセス分科会
- 35. ©2014 Shintaro Hosoai
Step4-3 : Xtextにクラス要素を伝える
• src/jp.sea.kansai.example.jvmmodel/
UnitDslJvmModelInferrer.xtend
を開き以下のように変更
352014/3/31 SEA関西プロセス分科会
def dispatch void infer(Unit unit,
IJvmDeclaredTypeAcceptor acceptor, boolean
isPreIndexingPhase) {
acceptor.accept(unit.toClass(unit.name))
}
inferを書き換え,型と
して扱いたい要素を指
定
- 36. ©2014 Shintaro Hosoai
Step4-4 : Xtendの変更
362014/3/31 SEA関西プロセス分科会
def genClass(Unit unit)'''
public class «unit.name» «IF unit.parent!=null»extends
«unit.parent.qualifiedName»«ENDIF»{
«FOR method:unit.methods»«genMethod(method)»«ENDFOR»
}
'''
def genMethod(Method method)'''
«method.retType.qualifiedName» «method.name»(«FOR
param:method.params SEPARATOR","»«genParam(param)»«ENDFOR»){
}
'''
def genParam(JvmFormalParameter param)'''
«param.parameterType.qualifiedName» «param.name»
''' 赤文字周辺が変更箇所.
灰の文字背景色は意味はありません(なぜか消せませんでした..
- 38. ©2014 Shintaro Hosoai
Step5-1: Xtext ProjectのPlugin化
• 作成した3つのプロジェクトを選択し右クリック>
Export
• jp.sea.kansai.xtext.unitdsl,jp.sea.kansai.xtext.unitdsl.test,
jp.sea.kansai.xtext.unitdsl.ui
• ダイアログから,以下を選択
Plugin Development/
Deployable plug-ins and fragments
• 次画面のDirectryでeclipseをインストールしたフォ
ルダのdropinsを選択する.
~eclipsedropins
• エクスポート終了後,Eclipseを再起動すると,作
成したDSLエディタが利用できるようになる.
• また,dropinsに生成されたjarファイルを配布すれ
ば,他のEclipse上でも利用できるようになる 382014/3/31