xtext入門
DESCRIPTION
第56回SEA関西プロセス分科会で用いた講義資料です. DSL開発支援環境であるXtextについて解説しています. ここでは,Xtextの裏側の仕組みをメインに取り扱っています.TRANSCRIPT
©2014 Shintaro Hosoai
Xtext 入門細合 晋太郎
2014/3/29 SEA 関西プロセス分科会
©2014 Shintaro Hosoai 2
DSL(Domain Specific Language)とは• 特定用途に限定した,独自言語• 一般的に他言語にマッピングして用いられる事が多い• 特定用途にしか利用できないが,抽象度が高く,より要件に近い表現ができる.
2014/3/29 SEA 関西プロセス分科会
AssemblerC
Java
DSL
汎用性
抽象度
©2014 Shintaro Hosoai 3
DSL のメリット• 生産性の向上• ドメイン分析• 特定のモデルしか書けない• プログラミングの知識があまりなくても書ける• ドメインを明確にする
• プログラミングというプログラマの暗黙知を形式知に• とはいえ,変換ルール,コードテンプレートは結局暗黙的になっちゃいますが・・.
2014/3/29 SEA 関西プロセス分科会
©2014 Shintaro Hosoai 4
DSL の分類
• 今回の Xtext は External Textual DSL を生成するためのフレームワークです.• Xtext は Java との親和性が高いので, Internal DSLに近い感覚で利用できます.
2014/3/29 SEA 関西プロセス分科会
Internal言語内 External独自処理系Textualテキスト形式 Rake(Ruby) Make ,
SQLGraphical図形式 Visual Studio? UML, SysML,
Matlab
©2014 Shintaro Hosoai 5
DSL 環境の構造
2014/3/29 SEA 関西プロセス分科会
DSL 定義
DSL
コード
テンプレートDSLエディタ
DSLパーサコードジェネレータ
DSLメタモデルモデル
©2014 Shintaro Hosoai 6
DSL の作り方• ドメイン知識が必要となるため,新規開発にはあまり向かない• 既存資産からパターンを抽出し,ドメインモデルと変換規則を作成する
2014/3/29 SEA 関西プロセス分科会
ドメイン固有のパターンの抽出 既存資産
DSL 定義 テンプレート
©2014 Shintaro Hosoai 7
Xtext
2014/3/29 SEA 関西プロセス分科会
©2014 Shintaro Hosoai
Xtext とは• Itemis 社のオープンソースプロジェクト
Eclipse の DSL 開発支援環境• 言語定義を元に Eclipse 上で動作する DSL エディタ, DSL パーサ,言語モデル,コードジェネレータ等を生成する• http://www.eclipse.org/Xtext/index.html
82014/3/29 SEA 関西プロセス分科会
©2014 Shintaro Hosoai 9
Xtext
2014/3/29 SEA 関西プロセス分科会
DSL 定義
DSL
コード
テンプレートDSLエディタ
DSLパーサコードジェネレータ
DSLメタモデルモデル
©2014 Shintaro Hosoai
Xtext 機能紹介
102014/3/29 SEA 関西プロセス分科会
Syntax Coloring Content Assist Validation and
Quick Fixes
Advanced Java
Integration
Integration with other
Eclipse tools
More IDE Features
©2014 Shintaro Hosoai 11
Xtext 構成
2014/3/29 SEA 関西プロセス分科会
EMFMDD 基盤
Xtend2Java を生成する軽量言語
MWE2モデルワークフローエンジン
XtextDSL 言語定義
©2014 Shintaro Hosoai 12
Xtext 構成
2014/3/29 SEA 関西プロセス分科会
Xtend2Java を生成する軽量言語
MWE2モデルワークフローエンジン
XtextDSL 言語定義
EMFMDD 基盤
©2014 Shintaro Hosoai 13
EMF ( Eclipse Modeling Framework)• Eclipse のモデリングフレームワーク• OMG の MDA に基づいた実装• 多くのモデリング技術の基盤となっている• MDA とは
2014/3/29 SEA 関西プロセス分科会
M3: メタメタモデルM2: メタモデルM1: モデルM0: インスタンス
メタモデルを定義するための,一番大本となるモデルMOF(Meta Object Facility)
モデルを定義するモデル, UML や SysML, その他 OMG の各種モデルがこのレベルで定義されているメタモデルで定義された記法に沿って記述されたモデル.UML に当てはめるなら,実際に描かれたクラス図などモデルに基づいた実体. UML であれば実装されたコードなど
この MOF が EMF で ecore として実装されている.ecore を基盤とすることで, MDA の多くの技術が利用可能に
©2014 Shintaro Hosoai 14
Eclipse Modeling Projects
2014/3/29 SEA 関西プロセス分科会
EMF
モデル入力( DSL )TextualXtext
GraphicalGMF
Graphiti
モデル変換ATLQVTQVTd
http://projects.eclipse.org/list-of-projects
コード生成Acceleo
JET2Xpand
その他EMF Diff
EMF QueryAMW
MoDiscoUML2
PapyrusOCL
SiriusSphinx
VIATRA2Requirement
BPMN2Epsilon
Ecore ToolsTexo ...
©2014 Shintaro Hosoai 15
Xtext の EMF• 主に言語のメタモデル生成.このメタモデル・メタモデル実装( Java )をベースに各種プラグインが形成される
2014/3/29 SEA 関西プロセス分科会
言語定義( .xtext )言語メタモデル( .ecore )
言語メタモデル実装( .java )
Xtext の生成プラグイン
©2014 Shintaro Hosoai 16
Xtext 構成
2014/3/29 SEA 関西プロセス分科会
EMFMDD 基盤
MWE2モデルワークフローエンジン
XtextDSL 言語定義
Xtend2Java を生成する軽量言語
©2014 Shintaro Hosoai 17
Xtend2• Xtext で作られた Java を生成する LL• Java のかゆい所に手が届く,とても便利な言語• 書いたそばから生成→コンパイルまで行ってくれるので, Java とシームレスに利用可能• Xtext でも様々な用途で用いられている• 主要機能• 動的型付け(ただしコンパイル時に型決定なので安心)• ラムダ式,拡張関数,拡張 Switch• テンプレート記述• → マニュアル参照
2014/3/29 SEA 関西プロセス分科会
©2014 Shintaro Hosoai 18
コードテンプレート
2014/3/29 SEA 関西プロセス分科会
def toJavaCode(Statemachine sm) ''' import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader;
public class «sm.eResource.className» {
public static void main(String[] args) { new «sm.eResource.className»().run(); } «FOR c : sm.commands» «c.declareCommand» «ENDFOR» protected void run() { boolean executeActions = true; String currentState = "«sm.states.head?.name»"; String lastEvent = null; while (true) {
テンプレート
public class signal { public static void main(String[] args) { new signal().run(); } protected void doLightBlue() { System.out.println("Executing command } protected void doLightYellow() { System.out.println("Executing command } protected void doLightRed() { System.out.println("Executing command }protected void run() {
生成コード
©2014 Shintaro Hosoai 19
Xtext 構成
2014/3/29 SEA 関西プロセス分科会
EMFMDD 基盤
Xtend2Java を生成する軽量言語
XtextDSL 言語定義
MWE2モデルワークフローエンジン
©2014 Shintaro Hosoai 20
MWE2• ワークフローエンジン.これも Xtext で書かれてます.• モデル駆動開発の主要な作業(ワーク)をワークフローの形で記述できる• 例えば• DSL ファイルの読み込み,パース,モデル変換,コード生成など• Xtext の言語生成を行う際もこの MWE2 のスクリプトを起動して言語環境の生成を行う.
2014/3/29 SEA 関西プロセス分科会
©2014 Shintaro Hosoai 21
MWE2 例
2014/3/29 SEA 関西プロセス分科会
Workflow { bean = StandaloneSetup { ... } component = DirectoryCleaner { directory = "${runtimeProject}/src-gen" } component = Generator { pathRtProject = runtimeProject pathUiProject = "${runtimeProject}.ui" pathTestProject = "${runtimeProject}.tests" projectNameRt = projectName projectNameUi = "${projectName}.ui" encoding = encoding language = auto-inject { uri = grammarURI fragment = grammarAccess.GrammarAccessFragment auto-inject {} ...
フロー例Standalone
Setup
DirectoryCleaner
Generator
©2014 Shintaro Hosoai 22
Xtext 構成
2014/3/29 SEA 関西プロセス分科会
EMFMDD 基盤
Xtend2Java を生成する軽量言語
MWE2モデルワークフローエンジン
XtextDSL 言語定義
©2014 Shintaro Hosoai 23
Xtext• 言語定義と言語環境の生成.エディタの生成• 言語定義言語の Xtext 自体もまた Xtext で作られている• Xtext は拡張 BNF 風の言語定義言語• 再帰下降型構文解析• EMF のモデルへ変換する字句解析器,構文解析器が自動生成される
2014/3/29 SEA 関西プロセス分科会
©2014 Shintaro Hosoai
Xtext 構造grammar org.eclipse.xtext.example.fowlerdsl.Statemachine with org.eclipse.xtext.common.Terminals
generate statemachine "http://www.eclipse.org/xtext/example/fowlerdsl/Statemachine"
Statemachine : {Statemachine} ('events' events+=Event+ 'end')? ('resetEvents' resetEvents+=[Event]+ 'end')? ('commands' commands+=Command+ 'end')? states+=State*;
terminal MYID:'A''0'..'9';
言語名宣言と言語Mixin
言語モデル宣言Parser Rule/言語構造定義
lexis/語彙定義
初めのうちは,上二つは自動生成ままで利用するのがよい
Event: name=ID; ...
2014/3/29 SEA 関西プロセス分科会 24
©2014 Shintaro Hosoai
Parser RulesState: 'state' name=ID ('actions' '{' actions+=[Command]+ '}')? transitions+=Transition* 'end';
state myState actions { myCommand1 myCommand2 } event2 => myState2 event3 => myState3end
Transition: event=[Event] '=>' state=[State];
DSL 定義
DSL 例
2014/3/29 SEA 関西プロセス分科会 25
©2014 Shintaro Hosoai
Parser RulesState: 'state' name=ID ('actions' '{' actions+=[Command]+ '}')? transitions+=Transition* 'end';
state myState actions { myCommand1 myCommand2 } event2 => myState2 event3 => myState3end
Transition: event=[Event] '=>' state=[State];
DSL 定義
DSL 例
定義名:~‘;’までが一つのルールとなる.この定義名のモデルが生成される( Returns を指定しない場合)
: State
: Transition: Transition
: Commandactions
transitions
: Command
2014/3/29 SEA 関西プロセス分科会 26
©2014 Shintaro Hosoai
Parser RulesState: 'state' name=ID ('actions' '{' actions+=[Command]+ '}')? transitions+=Transition* 'end';
state myState actions { myCommand1 myCommand2 } event2 => myState2 event3 => myState3end
Transition: event=[Event] '=>' state=[State];
DSL 定義
DSL 例
’’で区切った部分は語彙として定義される
2014/3/29 SEA 関西プロセス分科会 27
©2014 Shintaro Hosoai
Parser RulesState: 'state' name=ID ('actions' '{' actions+=[Command]+ '}')? transitions+=Transition* 'end';
state myState actions { myCommand1 myCommand2 } event2 => myState2 event3 => myState3end
Transition: event=[Event] '=>' state=[State];
DSL 定義
DSL 例
変数は,属性として生成される.割り当てに応じて = :単体, += : Listとして生成State
name : IDactions : List<Command>
transitions:List<Transition>Transition
event : Eventstate : State
2014/3/29 SEA 関西プロセス分科会 28
©2014 Shintaro Hosoai
Parser RulesState: 'state' name=ID ('actions' '{' actions+=[Command]+ '}')? transitions+=Transition* 'end';
state myState actions { myCommand1 myCommand2 } event2 => myState2 event3 => myState3end
Transition: event=[Event] '=>' state=[State];
DSL 定義
DSL 例[] で指定した要素は name によりでインスタンスを参照する.このため参照される Rule には name=IDを持つ必要がある.例では State,Event,Command は参照可Transition は name=ID を持たないので,参照出来ない.
割り当てに用いることが出来るのは,・ Terminal Rule ( ex: ID )・ Parser Rule ( ex: Transition )・ Parser Rule の実体への参照( ex: [Command] )
2014/3/29 SEA 関西プロセス分科会 29
©2014 Shintaro Hosoai
Parser RulesState: 'state' name=ID ('actions' '{' actions+=[Command]+ '}')? transitions+=Transition* 'end';
state myState actions { myCommand1 myCommand2 } event2 => myState2 event3 => myState3end
Transition: event=[Event] '=>' state=[State];
DSL 定義
DSL 例
繰り返し指定*:0以上+:1以上?:0 or1():グループ化
actions 句はあってもなくてもよい. action は空白区切りで1以上繰り返し指定可能transition 句は 0 回以上なので,なくてもよい1以上の繰り返し指定を行う場合は+= で割り当てる.
2014/3/29 SEA 関西プロセス分科会 30
©2014 Shintaro Hosoai 31
まとめ
2014/3/29 SEA 関西プロセス分科会
DSL 定義
DSL
コード
テンプレートDSLエディタ
DSLパーサコードジェネレータ
DSLメタモデルモデル
XtendEMFXtext
MWE2
©2014 Shintaro Hosoai
Xtext Project Sample
2014/3/29 SEA 関西プロセス分科会 32
©2014 Shintaro Hosoai 33
DSL エディタ生成までの流れ
2014/3/29 SEA 関西プロセス分科会
New Xtext ProjectWizard
①ひな形プロジェクト群の生成
*.tests*.ui *.sdk
Xtext Project
②言語定義の追加
言語定義言語生成ワークフロー
©2014 Shintaro Hosoai 34
生成されるプロジェクト• projectname言語定義とランタイムコンポーネント( Parser,
Lexer, Linker, validation )• projectname.testsユニットテスト用プロジェクト• projectname.uiエディタ機能の拡張用プロジェクト(コンテンツアシスト,ラベル,アウトライン,クイックフィックス)• projectname.sdk
Xtext以外の拡張を行う際のひな形2014/3/29 SEA 関西プロセス分科会
©2014 Shintaro Hosoai 35
プロジェクト詳細• ProjectName• src : ユーザが定義するソース群
• * : 言語定義• *.formatting : コードフォーマット• *.generator : コード生成定義• *.jvmmodel : Java連携• *.scoping : 言語要素のスコープコントロール• *.validation : バリデーション機能
• src-gen : ワークフローや ecore から自動生成されるコード群• xtend-gen : Xtend から自動生成されるコード群• model : 言語定義から生成される ecore• その他 : plugin.xml 等
2014/3/29 SEA 関西プロセス分科会
最初の内はこの二つから触るのがよい
©2014 Shintaro Hosoai
grammar org.eclipse.xtext.example.fowlerdsl.Statemachine with org.eclipse.xtext.common.Terminalsgenerate statemachine "http://www.eclipse.org/xtext/example/fowlerdsl/Statemachine"
Statemachine : {Statemachine} ('events' events+=Event+ 'end')? ('resetEvents' resetEvents+=[Event]+ 'end')? ('commands' commands+=Command+ 'end')? states+=State*;
Event: name=ID;
Command: name=ID;
State: 'state' name=ID ('actions' '{' actions+=[Command]+ '}')? transitions+=Transition* 'end';
Transition: event=[Event] '=>' state=[State];
First Example(1) : Xtext
Statemachine
Event Command State
Transition
events commands states
event statetransitions
actions
*** *
*
11
New > Example, Xtext Examples > Xtext Statemachine Example
362014/3/29 SEA 関西プロセス分科会
©2014 Shintaro Hosoai
DSL をパースして生成されるモデル
DSL イメージFirst Example(2) : DSLevents toBlue toYellow toRedend
commands lightBlue lightYellow lightRedend
state blue actions { lightBlue } toYellow=>yellowendstate yellow actions { lightRed } toRed=>redendstate red actions { lightRed } toBlue=>blueend
blueentry/lightBlue
yellowentry/lightYellow
redentry/lightRed
toBlue
toYellow
toRed
toBlue:EventtoYellow:Event
toRed:Event
lightBlue:CommandlightYellow:Command
lightRed:Command
blue:Stateyellow:State
red:StatetoBlue->blue:TransitiontoYellow->yellow:Transition
toRed->red:Transition
:Statemachine
→ のようなステートマシンをDSL として入力
Xtext によるパース
2014/3/29 SEA 関西プロセス分科会 37
©2014 Shintaro Hosoai
First Example(3) : Code Generate
DSL をパースして生成されるモデルtoBlue:Event
toYellow:Even
t
toRed:Event
lightBlue:Comman
d
lightYellow:Comma
nd
lightRed:Command
blue:State
yellow:Stat
e
red:Stat
e
toBlue->blue:Transition
toYellow-
>yellow:Transitio
n
2014/3/29 SEA 関西プロセス分科会 38
生成モデルdef toJavaCode(Statemachine sm) ''' import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader;
public class «sm.eResource.className» {
public static void main(String[] args) { new «sm.eResource.className»().run(); } «FOR c : sm.commands» «c.declareCommand» «ENDFOR» protected void run() { boolean executeActions = true; String currentState = "«sm.states.head?.name»"; String lastEvent = null; while (true) {
テンプレートpublic class signal { public static void main(String[] args) { new signal().run(); } protected void doLightBlue() { System.out.println("Executing command } protected void doLightYellow() { System.out.println("Executing command } protected void doLightRed() { System.out.println("Executing command }protected void run() {
生成コード