引用另一个DSl及其模型

时间:2017-01-31 20:57:23

标签: xtext

由于讨论了一个工作示例已创建并添加到https://github.com/Johanvdberg/mcrl2.xtext,请参阅test.multiname。*和test.reflang。* eclipse项目。

Multiname 由语法

定义
grammar test.multiname.dsl.MultiNameDsl with org.eclipse.xtext.common.Terminals

generate multiNameDsl "http://www.multiname.test/dsl/MultiNameDsl"

Model:
    modules+=Module+;

Module:
    'begin module' name=ID
    vars+=Vars*
    funcs+=Funcs*
    'end_module';

VarName:
    name=ID;

FuncName:
    name=ID;

Name:
    VarName | FuncName;

Funcs:
    'func' left=FuncName (bracket?='(' ')')? '=' right=[Name] ';';

Vars:
    'var' VarName ';';

具有此语法的文件将类似于

begin module test1
var t1v1;
var t1v2;
end_module

begin module test2
var t2v1;
var t2v2;
end_module

将引用上述语言的语言语法 RefLang

语法test.reflang.dsl.RefDsl与org.eclipse.xtext.common.Terminals

generate refDsl "http://www.reflang.test/dsl/RefDsl"
import "http://www.multiname.test/dsl/MultiNameDsl" as multi

Model:
    ref_from=Import
    refs=DataRef;

Import:
    'import' imports=[multi::Module];

DataRef:
    'ref_vars' data+=[multi::VarName|FQN] (',' data+=[multi::VarName|FQN])*;

FQN:
    ID ("." ID)*;

并且具有上述语法的文件如下所示:

import test2
ref_vars test2.t2v1, test1.t1v1

希望行为是ref_vars只能来自import指定的模块,上面的文件是test2而var test1.t1v1不正确。< / p>

RefLang 的范围提供者是:

override getScope(EObject context, EReference reference) {
    if (context instanceof DataRef) {
        if (reference == RefDslPackage.Literals.DATA_REF__DATA) {
            val rootElement = EcoreUtil2.getRootContainer(context)
            return super.getScope(context, reference);
        }
    }
    return super.getScope(context, reference);
}

但我无法使用rootElement访问 multiname 语言中定义的模型元素test2以及 RefLang 中的引用。所有属性rootElement.ref_from.imports.{vars, funcs}均为null

注意问题有所改变,而且工作正常,这些更改是基于对旧问题的评论而做出的。

旧问题 我有两个语法AB,其中语法B引用语法A中的元素:

Model:
    import_model=Import
    flows=FlowData;

Import :
    'import' importURI=STRING ';';


FlowData:
    'flows' data+=[A::Flow|FQN] (',' data+=[A::Flow|FQN])* ';';

FQN: ID ("." ID)*;

importURI定义使用语法A的文件,并包含Flow开头引用的定义。

使用https://christiandietrich.wordpress.com/2011/10/15/xtext-calling-the-generator-from-a-context-menu/中的上下文菜单可以访问语法模型B。如何在同一个处理程序中访问importURI指定的文件模型?

更新1

添加与导入相关的MWE2文件:

fragment = scoping.ImportNamespacesScopingFragment2 auto-inject {}
referencedResource="platform:/resource/.../A.genmodel"

在语法文件中

import "http://www..../A" as A

添加语法B的dsl项目plugin.xml与语法A的dsl项目的依赖关系。还分别增加了ide和ui项目对ide和ui的依赖性。

需要访问完整的语法模型A。语法A定义一个系统和语法B定义数据在系统中的位置,并且需要转换两个模型的并集。

每种语法模型A可能存在多个配置(模型)。

1 个答案:

答案 0 :(得分:1)

你似乎是一个真正讨厌语法作业的人

Funcs:
'func' left=FuncName (bracket?='(' ')')? '=' right=[Name] ';';

Vars:
'var' varName=VarName ';';

这里是适用于我的scopeprovider

class MyDslScopeProvider extends AbstractMyDslScopeProvider {

    override getScope(EObject context, EReference reference) {
        if (context instanceof DataRef) {
            if (reference == MyDslPackage.Literals.DATA_REF__DATA) {
                val rootElement = EcoreUtil2.getContainerOfType(context, Model)
                val names = <Name>newArrayList
                val importedModule = rootElement?.ref_from?.imports
                if (importedModule !== null) {
                    for (v : importedModule.vars.map[varName]) {
                        names += v
                    }
                    for (f : importedModule.funcs.map[left]) {
                        names += f
                    }
                }
                // this is the unqualified variant
                // return Scopes.scopeFor(names)
                // this is the unqualified variant
                return Scopes.scopeFor(names, [QualifiedName.create(importedModule.name, it.name)], IScope.NULLSCOPE)
            }
        }
        return super.getScope(context, reference);
    }

}

此外,关键字中空格的使用是代码气味,可能会导致意外行为

你应该只考虑引用的简单相同 (在范围界定 - 请参阅我的评论 - 以及语法ref=[XXX|ID]