Xtext practice

1,105 views

Published on

SAE

Published in: Engineering
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,105
On SlideShare
0
From Embeds
0
Number of Embeds
45
Actions
Shares
0
Downloads
10
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Xtext practice

  1. 1. ©2014 Shintaro Hosoai Xtext Tutorial 細合 晋太郎 2014/3/31 SEA関西プロセス分科会
  2. 2. ©2014 Shintaro Hosoai Step0: サンプルプロジェクトを実行してみよう 2014/3/31 SEA関西プロセス分科会 2 Sample Project State Machine DSL
  3. 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. 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. 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. 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. 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. 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. 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関西プロセス分科会
  10. 10. ©2014 Shintaro Hosoai Step1 : 独自プロジェクトを作成してみよう 2014/3/31 SEA関西プロセス分科会 10 プロジェクトの作成
  11. 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. 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. 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. 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. 15. ©2014 Shintaro Hosoai Step1-4 : Greeting DSLを試す. • 再度,生成環境を実行 • 新しく起動したEclipse上に新しくJava Projectを 作成 • DSLファイルの作成:New > File,適当な場所に ~.unitファイルを作成 • 初回はダイアログが表示されるのでYes(Xtext Natureの追加) • コンテンツアシストやシンタックスカラーリン グが有効か確認してみましょう. • 本プロジェクトは現状,コード生成は行われま せん. 152014/3/31 SEA関西プロセス分科会
  16. 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. 17. ©2014 Shintaro Hosoai Step1-6 : 再生成・実行・確認 172014/3/31 SEA関西プロセス分科会 • 言語定義を変更した場合は,再度Generate *.mwe2を実行して,言語環境を再生成する必 要があります. • 再生成後,実行してみましょう.以下のように Unitが記述できるようになっているはずです. • unit Hogehoge{ • foo • bar • }
  18. 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. 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フォルダをソースフォルダに指定すると,生成したコードがコンパイルさ
  20. 20. ©2014 Shintaro Hosoai Step2 : 言語定義,コードテンプレートの拡張,Type Reference 2014/3/31 SEA関西プロセス分科会 20 プロジェクトの拡張
  21. 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. 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. 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. 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
  25. 25. ©2014 Shintaro Hosoai Step3 : エディタにバリデーション機能をつけよう 2014/3/31 SEA関西プロセス分科会 25 Validation
  26. 26. ©2014 Shintaro Hosoai Step3-1 : Validation • エディタにバリデーション(入力規則チェッ ク)を付けてみましょう↓ • Validation機能は以下クラスで定義します. src/jp.sea.kansai.example.validation/ UnitDslValidator.xtend 262014/3/31
  27. 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. 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. 29. ©2014 Shintaro Hosoai Step3-Ex : Xtextのビルドエラー対策 • Xtextの言語定義に不具合があった際のエラー は,エラーメッセージを読んでも,どこに不具 合があるのか分かり辛いです. • 言語定義は,内部的にAntlrというJavaのParser ジェネレータのファイルに変換されます. • 生成されたg(Antlr)ファイルのエラー行の付 近を確認し,// Rule ~等を探して該当するルー ルを判別します. • 他に良い方法があれば教えてください^^; 292014/3/31 SEA関西プロセス分科会
  30. 30. ©2014 Shintaro Hosoai Step4 : DSLにJavaの要素を取り込む 2014/3/31 30 JVM統合
  31. 31. ©2014 Shintaro Hosoai Step4-1 : Java要素の取り込み • Xtextでは,Javaのライブラリを利用するような DSLも作成できます. • Java要素を用いるには,以下の作業が必要です. • 言語定義にXbaseをMixinする • 言語定義をJvmに適したものに変更する • クラスとして扱う要素をXtextに伝える 312014/3/31
  32. 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. 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. 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. 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. 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» ''' 赤文字周辺が変更箇所. 灰の文字背景色は意味はありません(なぜか消せませんでした..
  37. 37. ©2014 Shintaro Hosoai Step5 Xtext Projectをエクスポートして,単独で動作させる 2014/3/31 SEA関西プロセス分科会 37 ProjectのExport
  38. 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

×