1. 程式人生 > >Xtext試用: 快速實現簡單領域專用語言(DSL)

Xtext試用: 快速實現簡單領域專用語言(DSL)

環境搭建

使用的Eclipse版本: Oxygen.1a Release (4.7.1a) Build id: 20171005-1200, 通過新增Xtext - Download上列出的Releases update site安裝xtext IDE和xtext SDK. 之後開啟Eclipse, 開啟任何檔案就報錯:

An error has occurred. See error log for more details.
loader constraint violation: loader (instance of org/eclipse/osgi/internal/loader/EquinoxClassLoader) previously initiated loading for a different type with name "org/aspectj/runtime/internal/AroundClosure"

為避免現有外掛和它的衝突, 新安裝了更新版Eclipse: Version: Oxygen.2 Release (4.7.2) Build id: 20171218-0600

官方教程原始碼試用

首先, 參考官方教程: 15 Minutes Tutorial

教程按部就班, 基本沒有問題. 唯一碰到的坑是最後將一個dsl檔案拆分成多個時, 發現需要將專案轉換為xtext project才能支援(Xtext cross-reference across all files in project)

接著的第二個教程: 15 Minutes Tutorial - Extended, 問題多了些.

"Unit Testing the Language"部分中的檔案在.tests專案的src/中, 只有個小坑. 下面的parser就是原來模板檔案中的parseHelper

    val model = parser.parse(
            "entity MyEntity {
                parent: MyEntity
            }")

"Creating Custom Validation Rules"部分中的checkFeatureNameIsUnique 初一執行後, 在同一Entity內兩個同名Feature沒有報錯, ==改為.equals()也無用. 細一看之後, 才發覺它是檢查父子Entity內是否有同名Feature. 比如在Comment中新增’author’的Feature, 如期報錯.

這裡感覺到xtend語言的特別, 發現它本身也是個JVM語言: Xtend - Modernized Java, 不過貌似遠沒有Kotlin的流行度(後發現本站的程式碼塊語言選項中竟然有xtend).

框架對中文的支援

首先, 嘗試生成中文關鍵詞的DSL. 預設ID只包含英文,數字,下劃線, 因此自定義IDENTIFIER,

grammar org.example.domainmodel.Domainmodel with org.eclipse.xtext.common.Terminals

generate domainmodel "http://www.example.org/domainmodel/Domainmodel"

import "http://www.eclipse.org/emf/2002/Ecore" as ecore

Domainmodel:
	(elements+=AbstractElement)*;

PackageDeclaration:
	'包' name=QualifiedName '{'
	(elements+=AbstractElement)*
	'}';

AbstractElement:
	PackageDeclaration | Type | Import;

QualifiedName:
	IDENTIFIER ('.' IDENTIFIER)*;

Import:
	'匯入' importedNamespace=QualifiedNameWithWildcard;

QualifiedNameWithWildcard:
	QualifiedName '.*'?;

Type:
	DataType | Entity;

DataType:
	'資料型別' name=IDENTIFIER;

Entity:
	'類' name=IDENTIFIER ('擴充套件' superType=[Entity|QualifiedName])? '{'
	(features+=Feature)*
	'}';

Feature:
	(many?='複數')? name=IDENTIFIER ':' type=[Type|QualifiedName];
	
terminal IDENTIFIER: '^'?('\u4E00'..'\u9FA5'|'\uF900'..'\uFA2D'|'a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'\u4E00'..'\u9FA5'|'\uF900'..'\uFA2D')*;

一個小問題. 由於IDENTIFIER開頭支援下劃線, Generate Xtext Artifacts時會警告如下, 但似乎不影響語言生成, 下劃線開頭支援也正確:

error(208): ../org.example.mydsl/src-gen/org/example/domainmodel/parser/antlr/internal/InternalDomainmodel.g:571:1: The following token definitions can never be matched because prior tokens match the same input: RULE_ID
error(208): ../org.example.mydsl.ide/src-gen/org/example/domainmodel/ide/contentassist/antlr/internal/InternalDomainmodel.g:1258:1: The following token definitions can never be matched because prior tokens match the same input: RULE_ID

另一個問題是, 語法規則中的規則名稱不能用中文命名(比如Feature改為’性狀’, PackageDeclaration改為’包宣告’等), 否則在Generate Xtext Artifacts生成報錯並中斷:

java.lang.RuntimeException: Problems running workflow org.xtext.example.mydsl.GenerateMyDsl: Problem parsing 'file:/Users/xuanwu/work/workspace-xtext/org.example.mydsl/../org.example.mydsl/src/org/xtext/example/mydsl/MyDsl.xtext':
XtextSyntaxDiagnostic: null:10 extraneous input '包' expecting ':'

經測試, DSL語言高亮在Eclipse中顯示正確:
2018-01-19-xtext高亮eclipse
並且生成Java Beans正確(需要將資料型別名稱由上面的"字串"改為"String"):
2018-01-19-xtext_beans
另外, 經測試xtend也支援中文命名(節選DomainmodelValidator如下), 但由於xtext語法檔案不支援中文識別符號, 影響有限:

@Check
    def void 檢驗子類無父類重名性狀(Feature f) {
        var 父類 = (f.eContainer as Entity).superType
        while (父類 !== null) {
            for (其他 : 父類.features) {
                if (f.name == 其他.name) {
                    error("子類性狀不能與父類中性狀重名",
                        DomainmodelPackage.Literals.FEATURE__NAME)
                    return
                }
            }
            父類 = 父類.getSuperType();
        }
    }

演示如下:
2018-01-19-xtext重新命名error
以上xtext專案原始碼在program-in-chinese/xtext_tutorial_15_min_zh

測試DSL專案原始碼: program-in-chinese/xtext_tutorial_15_min_zh

初步小結

長處:

  • 工具本身和基本文件質量尚可, 基本功能(原始碼分析, 新程式碼生成), 上手還算快. 應該至少可以適用於簡單DSL實驗.
  • 語法規則描述接近EBNF. 好像功能更多(equivalent BNF-grammar of grammar written in XText)

短處:

  • 最大問題是語法規則中識別符號不能中文命名, 直接導致相關的程式碼生成器(generator)和驗證器使用的多數API只能是英文(如上面的.name, .features).
  • Eclipse版本或者外掛衝突問題需要規避
  • 需要學習xtend語言, 雖然可能很像Java

未嘗試: 可否定製自動補全功能, 語法報錯資訊(比如下面)
2018-01-19-xtext語法error
另外希望有機會繼續嘗試下一篇教程: Five simple steps to your JVM language