38
©2014 Shintaro Hosoai Xtext Tutorial 細細 細細細 2022/01/17 SEA 細 細細細細細細細 西

Xtext practice

Embed Size (px)

DESCRIPTION

SAE

Citation preview

Page 1: Xtext practice

©2014 Shintaro Hosoai

Xtext Tutorial細合 晋太郎

2023/04/11 SEA 関西プロセス分科会

Page 2: Xtext practice

©2014 Shintaro Hosoai 2

Step0:

サンプルプロジェクトを実行してみよう

04/11/2023 SEA 関西プロセス分科会

Sample ProjectState Machine DSL

Page 3: Xtext practice

©2014 Shintaro Hosoai 3

Step0-1: Sample Project の作成• Eclipse を起動します• New > Example  →ダイアログ表示• Xtext Examples/Xtext State-Machine Example を選

択し Next• 次ページの設定は変えずに Finish

• Workspace に以下の二つのプロジェクトが作成されるorg.eclipse.xtext.example.fowlerdslorg.eclipse.xtext.example.fowlerdsl.ui

04/11/2023 SEA 関西プロセス分科会

Page 4: Xtext practice

©2014 Shintaro Hosoai 4

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 の拡張子

04/11/2023 SEA 関西プロセス分科会

Page 5: Xtext practice

©2014 Shintaro Hosoai 5

Step0-3: 言語環境の生成• org.eclipse.xtext.example.fowlerdsl を開き,

src/org.eclipse.xtext.example.fowlerdsl/  GenerateStatemachine.mwe2を右クリック > Run As > MWE2 Workflow• 言語定義に基づいて,言語モデル,エディタプ

ラグイン等が生成されます.

• ( Example では実はすでに環境生成されています)

04/11/2023 SEA 関西プロセス分科会

Page 6: Xtext practice

©2014 Shintaro Hosoai 6

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

04/11/2023 SEA 関西プロセス分科会

Page 7: Xtext practice

©2014 Shintaro Hosoai 7

Step0-5: DSL を書いてみる• 右図のような信号のステートマシンを書いてみましょう. DSL 構成は

以下の通りevent event 名  EventID ...endcommands command 名 CommadID ...end

state state 名 actions { command 名 } event 名 => 次 state 名end...

04/11/2023 SEA 関西プロセス分科会

DSL イメージ

blueentry/lightBlue

yellowentry/lightYellow

redentry/lightRed

toBlue

toYellow

toRed

EventID, CommandID は任意

Page 8: Xtext practice

©2014 Shintaro Hosoai

Step0-6: 記述例events toRed E001 toBlue E002 toYellow E003end

commands lightRed C001 lightYellow C002 lightBlue C003end

state blue actions { lightBlue } toYellow => yellowend

state yellow actions { lightYellow } toRed=>redend

state red actions { lightRed } toBlue => blueend

804/11/2023 SEA 関西プロセス分科会

Page 9: Xtext practice

©2014 Shintaro Hosoai

Step0-7 : 生成コードの確認と実行• src-gen フォルダ下に入力した DSL から Java

コードが生成されています.• src-gen フォルダを右クリック> Build Path >

Use as Source Folder

• 生成された Java コードを右クリック> Run As > Java Application

• コマンドラインからイベントを入力し,ステートマシンの動作を確認できます.

904/11/2023 SEA 関西プロセス分科会

Page 10: Xtext practice

©2014 Shintaro Hosoai 10

Step1 :

独自プロジェクトを作成してみよう

04/11/2023 SEA 関西プロセス分科会

プロジェクトの作成

Page 11: Xtext practice

©2014 Shintaro Hosoai 11

Step1-0 :どんな DSL?

• TDD するときに,クラスのひな形とテストクラス作るのめんどいよね!→ DSL で作ってみよう

04/11/2023 SEA 関西プロセス分科会

UnitDSL

MockClassMock

ClassMockClass

TestClassTest

ClassTestClass

クラス定義メソッド定義テスト定義

Page 12: Xtext practice

©2014 Shintaro Hosoai 12

Step1-1 : Project の作成• New > Project > Xtext Project• Dialog

project name : jp.sea.kansai.example.unitdsl☑Use default locationLanguage  Name : jp.sea.kansai.example.UnitDsl  Extensions : unitLayout □ Create SDK feature projectWorking sets □ Add Project to working sets

04/11/2023 SEA 関西プロセス分科会

今回は利用しない

任意

DSL のファイル拡張子(任意)

言語名, Project 名と合わせておくのが無難.

クラスになるので Camelで

プロジェクト名(任意)

Page 13: Xtext practice

©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

1304/11/2023 SEA 関西プロセス分科会

Page 14: Xtext practice

©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 問題が解決されたっぽい?

1404/11/2023 SEA 関西プロセス分科会

Page 15: Xtext practice

©2014 Shintaro Hosoai

Step1-4 : Greeting DSL を試す.• 再度,生成環境を実行• 新しく起動した Eclipse 上に新しく Java Project

を作成• DSL ファイルの作成: New > File ,適当な場所

に~ .unit ファイルを作成• 初回はダイアログが表示されるので

Yes ( Xtext Nature の追加)• コンテンツアシストやシンタックスカラーリン

グが有効か確認してみましょう.• 本プロジェクトは現状,コード生成は行われま

せん.

1504/11/2023 SEA 関西プロセス分科会

Page 16: Xtext practice

©2014 Shintaro Hosoai

Step1-5 : Xtext を書き換える• まずは,クラス構造を定義する部分を作る(型

を扱うとややこしいので,とりあえず以下のレベルで)

unit name { methodName

...

}

1604/11/2023 SEA 関西プロセス分科会

クラス名

メソッドは複数個指定

Unit :  “ unit” name=ID “{” methods+=Method* “}”;

Method:  name=ID;

Model:  units+=Unit*;

Page 17: Xtext practice

©2014 Shintaro Hosoai

Step1-6 : 再生成・実行・確認

1704/11/2023 SEA 関西プロセス分科会

• 言語定義を変更した場合は,再度 Generate* .mwe2 を実行して,言語環境を再生成する必要があります.• 再生成後,実行してみましょう.以下のように

Unit が記述できるようになっているはずです.• unit Hogehoge{• foo• bar• }

Page 18: Xtext practice

©2014 Shintaro Hosoai

Step1-7 : コード生成の定義(1)

1804/11/2023 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));   }  }

 次ページに続く

Page 19: Xtext practice

©2014 Shintaro Hosoai

Step1-7 : コード生成の定義(1)

1904/11/2023 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 フォルダをソースフォルダに指定すると,生成したコードがコンパイルされます

Page 20: Xtext practice

©2014 Shintaro Hosoai 20

Step2 :

言語定義,コードテンプレートの拡張, Type Reference

04/11/2023 SEA 関西プロセス分科会

プロジェクトの拡張

Page 21: Xtext practice

©2014 Shintaro Hosoai 21

Step2-1 : Xtext の拡張(1)• 前回作成した, Unit DSL を拡張していきましょ

う.• 型周りを実装してみましょう• unit className extends superClass {

  retType methodName(paramType param)}

04/11/2023 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 :は変更なし

引数がない場合は省略可にしてみました

Page 22: Xtext practice

©2014 Shintaro Hosoai

Step2-2 : Xtext の拡張(2)• Primitive も書けるようにしてみます.

2204/11/2023 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";

再生成・実行してみましょう

Page 23: Xtext practice

©2014 Shintaro Hosoai

Step2-3: テンプレートの拡張 (1)

2304/11/2023 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»'''

Page 24: Xtext practice

©2014 Shintaro Hosoai

Step2-3: テンプレートの拡張 (2)

• 型に応じて名前を返す補助メソッドです.• type=[Unit]|PredefTypes としているため

type は EObject ( EMF の Object )型になっています→• 通常このような場合,オーバーロードできませ

んが dispatch を指定することで,型に応じたメソッドが呼ばれます.

2404/11/2023 SEA 関西プロセス分科会

def dispatch getTypeName(Unit unit){ unit.name}def dispatch getTypeName(PredefTypes predef){ predef.type} EObject

Unit PredefTypes

Page 25: Xtext practice

©2014 Shintaro Hosoai 25

Step3 :

エディタにバリデーション機能をつけよう

04/11/2023 SEA 関西プロセス分科会

Validation

Page 26: Xtext practice

©2014 Shintaro Hosoai 2604/11/2023

Step3-1 : Validation

• エディタにバリデーション(入力規則チェック)を付けてみましょう↓

• Validation 機能は以下クラスで定義します. src/jp.sea.kansai.example.validation/UnitDslValidator.xtend

Page 27: Xtext practice

©2014 Shintaro Hosoai 27

Step3-2 : Validation の定義(1)

• @Check を付けたメソッドが自動的に呼ばれます.• 型ごとのチェックメソッドを列挙するだけでよ

い.04/11/2023 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)   }  }}

保存後,実行してみましょう

Page 28: Xtext practice

©2014 Shintaro Hosoai

Step3-2: Validation の定義(2)• Validator 内で使える主要なメソッド

info () :  情報warning () :  警告error () :  エラー

メソッドの使い方  info (メッセージ: String, 要素: EStructuralFeature )モデルで警告等を出す場合,モデルのどの要素なのかを指定します.DSL 名 Package というクラスにモデル構造の定数が定義されており,これを参照します.例えば, Unit の name属性の場合  UnitDslPackge::Literals.UNIT__NAMEとなります.

2804/11/2023 SEA 関西プロセス分科会

Page 29: Xtext practice

©2014 Shintaro Hosoai

Step3-Ex : Xtext のビルドエラー対策

• Xtext の言語定義に不具合があった際のエラーは,エラーメッセージを読んでも,どこに不具合があるのか分かり辛いです.• 言語定義は,内部的に Antlr という Java の Parser

ジェネレータのファイルに変換されます.• 生成された g ( Antlr )ファイルのエラー行の付近

を確認し, // Rule ~ 等を探して該当するルールを判別します.

•他に良い方法があれば教えてください^^;2904/11/2023 SEA 関西プロセス分科会

Page 30: Xtext practice

©2014 Shintaro Hosoai 04/11/2023 30

Step4 :

DSL に Java の要素を取り込むJVM統合

Page 31: Xtext practice

©2014 Shintaro Hosoai 3104/11/2023

Step4-1 : Java 要素の取り込み• Xtext では, Java のライブラリを利用するよう

な DSL も作成できます.

• Java 要素を用いるには,以下の作業が必要です.• 言語定義に Xbase を Mixin する• 言語定義を Jvm に適したものに変更する• クラスとして扱う要素を Xtext に伝える

Page 32: Xtext practice

©2014 Shintaro Hosoai

Step4-2 : Xtext の変更(1)

3204/11/2023 SEA 関西プロセス分科会

grammar jp.sea.kansai.example.UnitDsl with org.eclipse.xtext.xbase.Xbasegenerate 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;

Page 33: Xtext practice

©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 に変更します.

3304/11/2023 SEA 関西プロセス分科会

Page 34: Xtext practice

©2014 Shintaro Hosoai

Step4-Ex : 左再帰• この変更の過程で, Method 定義が左再帰になってし

まっているようです.( JvmTypeReference の中でMethod を参照しているのでしょうか・・)• 正攻法でいくのであれば,左再帰を除去するのです

が,,今回は時間の都合上(というか作者の能力上・・) Back Track を有効にします.生成時間が多少伸びるのと・・もしかしたら言語に少し悪影響があるかも.• GenerateUnitDsl.mwe2 を開き, backtrack を検索.コメ

ントを外すfragment = parser.antlr.XtextAntlrGeneratorFragment auto-inject {

options = {

backtrack = true

}

}3404/11/2023 SEA 関西プロセス分科会

Page 35: Xtext practice

©2014 Shintaro Hosoai

Step4-3 : Xtext にクラス要素を伝える• src/jp.sea.kansai.example.jvmmodel/

UnitDslJvmModelInferrer.xtendを開き以下のように変更

3504/11/2023 SEA 関西プロセス分科会

def dispatch void infer(Unit unit, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) { acceptor.accept(unit.toClass(unit.name))  }

infer を書き換え,型として扱いたい要素を

指定

Page 36: Xtext practice

©2014 Shintaro Hosoai

Step4-4 : Xtend の変更

3604/11/2023 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»'''

赤文字周辺が変更箇所.灰の文字背景色は意味はありません(なぜか消せませんでした..)

Page 37: Xtext practice

©2014 Shintaro Hosoai 37

Step5Xtext Project をエクスポートして,単独で動作させる

04/11/2023 SEA 関西プロセス分科会

Project の Export

Page 38: Xtext practice

©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 を選択する.~\eclipse\dropins\• エクスポート終了後, Eclipse を再起動すると,作

成した DSL エディタが利用できるようになる.• また, dropins に生成された jar ファイルを配布す

れば,他の Eclipse 上でも利用できるようになる( Xtext のインストールは必要かも・・) 3804/11/2023