欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

2018-01-19 Xtext试用: 快速实现简单领域专用语言(DSL)

程序员文章站 2022-06-19 10:36:56
环境搭建 使用的Eclipse版本: Oxygen.1a Release (4.7.1a) Build id: 20171005 1200, 通过添加 "Xtext Download" 上列出的Releases update site安装xtext IDE和xtext SDK. 之后打开Eclips ......

环境搭建

使用的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试用: 快速实现简单领域专用语言(DSL)

并且生成java beans正确(需要将数据类型名称由上面的"字符串"改为"string"):
2018-01-19 Xtext试用: 快速实现简单领域专用语言(DSL)

另外, 经测试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试用: 快速实现简单领域专用语言(DSL)

以上xtext项目源码在

测试dsl项目源码: program-in-chinese/xtext_tutorial_15_min_zh

初步小结

长处:

短处:

  • 最大问题是语法规则中标识符不能中文命名, 直接导致相关的代码生成器(generator)和验证器使用的多数api只能是英文(如上面的.name, .features).
  • eclipse版本或者插件冲突问题需要规避
  • 需要学习xtend语言, 虽然可能很像java

未尝试: 可否定制自动补全功能, 语法报错信息(比如下面)
2018-01-19 Xtext试用: 快速实现简单领域专用语言(DSL)

另外希望有机会继续尝试下一篇教程: five simple steps to your jvm language