XText 对非 DSL 资源的交叉引用 [英] XText cross-reference to an non-DSL resource

查看:21
本文介绍了XText 对非 DSL 资源的交叉引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑这个最小的 Xtext 语法.

Please consider this minimal Xtext grammar.

Model:
  "As a" stackeholder=Stakeholder "I want" want=Want;

Stakeholder:
  'client' | 'developer' | 'manager';

Want:
  'everything' | 'cookies' | 'fame';

现在我需要做的是将利益相关者的定义(让我们忘记want)到SOME外部数据源.这个外部数据源"可能是一个 CSV 文件,可能是一个数据库,也可能是一个网络服务.但我不太可能是一些 Xtext 文件或带有 EMF 模型.但我仍然想交叉引用它,就像您可以交叉引用 DSL 中的 Java 类型一样.

Now what I need to do, is to move the definition of stakeholders (let's forget about want) to SOME external data source. This "external data source" might be a CSV file, might be a DB or maybe a web service. But I it is highly unlikely to be some Xtext file or to come with an EMF model. But still I want to cross-reference it just like you can cross-reference java types in your DSL.

除了手动解析和缓存(为了性能)等问题:这甚至可行吗?

Issues like manual parsing and caching (for performance sake) aside: is this even doable?

我已经深入研究了范围和资源提供者的主题,但我发现的所有内容都要求外部源至少是另一个 DSL 的一部分.

I've dug a little into the topic of scopes and resource providers but everything I found required the external source to be part of at least another DSL.

我很乐意为需要完成的工作提供一个粗略的大纲.

I'd be very happy about a rough outline what would be needed to be done.

推荐答案

抱歉,我花了这么长时间才回复.我尝试了基督徒的建议,不是很满意,然后优先级转移了.现在我将再次解决这个问题,为了给其他人记录(并让我清醒),我将写下我到目前为止所做的事情,因为它不是那么简单,需要大量的实验.

Sorry it took me so long to respond. I tried Christians suggestion, was not very satisfied and than priorities shifted. Now I'll have another go at the problem and in order to document for others (and to clear my head) I'll write down what I did so far since it was not all that straight forward and required a fair amount of experimentation.

我不会发布完整的课程,而只会发布相关部分.如果您需要,请随时询问更多详细信息.

I will not post full classes but only the relevant parts. Feel free to ask for more detail if you need it.

我的语法定义现在看起来像这样:

My Syntax-Definition now looks like this:

Model:
  stakeholders+=StakeholderDecl*
  requirements+=Requirement*;

Requirement:
  'As a' stakeholder=[Stakeholder] 'I want' want=('everything' | 'cookies' | 'results')
;

StakeholderDecl returns Stakeholder :
  'Stakeholder' Stakeholder
;

Stakeholder:
  name=ID
;

请注意,以下所有内容都需要在 .ui 包中完成.

Let it be noted that everything below needed to to be done in the .ui package.

首先我创建了StakeholdersProvider.xtend:

class StakeholdersProvider extends AbstractResourceDescription {

  // this is the dummy for an "external source". Just raw data.
  val nameList = newArrayList( "buddy", "boss" )

  val cache = nameList.map[it.toDescription]

  private val uri = org.eclipse.emf.common.util.URI.createPlatformResourceURI("neverland", true)

  def public List<IEObjectDescription> loadAdditionalStakeholders() {
        cache
  }

  def private IEObjectDescription toDescription(String name) {

    ExternalFactoryImpl.init()
    val ExternalFactory factory = new ExternalFactoryImpl()

    val Stakeholder obj = factory.createStakeholder as StakeholderImpl
    obj.setName(name)


    new StakeholderDescription(name, obj, uri)
  }

. . .

  override getURI() {
    uri
  }

  def public boolean isProvided( EObject object ) {
    if( object.eClass.classifierID != ExternalPackageImpl.STAKEHOLDER ) {
        false
    }
    else {
        val stakeholder = object as Stakeholder
        nameList.exists[it == stakeholder.name]
    }
  }

}

注意提供者也是一个资源描述,它的uri当然是无稽之谈.

note that the provider is also a resourceDescription and its uri of course is nonsense.

通过这个提供者,我写了一个 ScopeWrapper.xtend :

With this provider I wrote a ScopeWrapper.xtend :

class ScopeWrapper implements IScope {

  private var IScope scope;
  private var StakeholdersProvider provider

  new( IScope scopeParam, StakeholdersProvider providerParam ) {
    scope=scopeParam
    provider = providerParam
  }

  override getAllElements() {
    val elements = scope.allElements.toList

    val ret = provider.loadAdditionalStakeholders()
    ret.addAll(elements)

    ret
  }

  override getSingleElement(QualifiedName name) {
      allElements.filter[it.name == name].head
  }

. . . 

}

ResourceDescriptionWrapper.xtend

class ResourceDescriptionsWrapper implements IResourceDescriptions {

  private StakeholdersProvider provider;
  private IResourceDescriptions descriptions;

  new(IResourceDescriptions descriptionsParam, StakeholdersProvider providerParam) {
    descriptions = descriptionsParam
    provider = providerParam
  }

  override getAllResourceDescriptions() {
    val resources = descriptions.allResourceDescriptions.toList
    resources.add(provider)
    resources
  }

  override getResourceDescription(URI uri) {
    if( uri == provider.URI ) provider
    else descriptions.getResourceDescription(uri)
  }
  override getExportedObjects() {
    val descriptions = descriptions.exportedObjects.toList

    descriptions.addAll(provider.exportedObjects)

    descriptions

  }

  . . . some overrides for getExportedObjects-functions

}

所有这些都连接在一起 MyGlobalScopeProvider.xtend

all of this is wired together MyGlobalScopeProvider.xtend

class MyGlobalScopeProvider extends TypesAwareDefaultGlobalScopeProvider {

  val provider = new StakeholdersProvider()

  override getScope(Resource context, EReference reference, Predicate<IEObjectDescription> filter) {
    val scope = super.getScope(context, reference, filter)
    return new ScopeWrapper(scope, provider)
  }

  override public IResourceDescriptions getResourceDescriptions(Resource resource) {
    val superDescr = super.getResourceDescriptions(resource)
    return new ResourceDescriptionsWrapper(superDescr, provider)
  }

}

在 MyDslUiModule.java 中注册

which is registered in MyDslUiModule.java

public Class<? extends IGlobalScopeProvider> bindIGlobalScopeProvider() {
    return MyGlobalScopeProvider.class;
}

到目前为止一切顺利.我现在得到 bossbuddy 作为利益相关者的建议.但是,当我使用这 2 个中的一个时,我在编辑器中收到错误,抱怨悬空引用和控制台中的错误日志,即利益相关者 无法导出,因为目标不包含在资源中.确定这两个可能是相关的我试图修复错误日志,创建 MyresourceDescriptionStrategy.xtend

So far so good. I now get boss and buddy suggested as stakeholders. However when I use one of those 2 I get an error in the editor complaining about a dangling reference and an error logging in the console that a stakeholder cannot be exported as the target is not contained in a resource. Figuring those 2 might are related I tried to fix the error logging, created MyresourceDescriptionStrategy.xtend

class MyResourcesDescriptionStrategy extends DefaultResourceDescriptionStrategy {

  val provider = new StakeholdersProvider()

  override isResolvedAndExternal(EObject from, EObject to) {
    if (provider.isProvided(to)) {
        // The object is a stakeholder that was originally provided by
        // our StakeholdersProvider. So we mark it as resolved.
        true
    } else {
        super.isResolvedAndExternal(from, to)
    }
  }
}

并将其连接到 UiModule 中:

and also wire it in the UiModule:

public Class<? extends IDefaultResourceDescriptionStrategy> bindDefaultResourceDescriptionStrategy() {
    return MyResourcesDescriptionStrategy.class;
}

这修复了日志错误,但悬空引用"问题仍然存在.我为此搜索了解决方案,大多数突出的结果 表明,首先定义 IResourceServiceProvider 本来是解决我的问题的最佳方法.我会花更多的时间在当前的方法上,而不是使用 ResourceProvider 进行尝试.

This fixes the logging error but the "dangling reference" problem remains. I searched for solutions for this and the most prominent result suggests that defining a IResourceServiceProvider would have been the best way to solve my problem in the first place. I'll spend a bit more time on the current approach and than try it with a ResourceProvider.

我解决了悬空引用"问题.StakeholdersProvider.xtend 中的 loadAdditionalStakeholders() 函数现在看起来像这样:

I got the "dangling reference" problem fixed. The loadAdditionalStakeholders() function in StakeholdersProvider.xtend now looks like this:

override loadAdditionalStakeholders() {

    val injector = Guice.createInjector(new ExternalRuntimeModule());
    val rs = injector.getInstance(ResourceSet)
    val resource = rs.createResource(uri)
    nameList.map[it.toDescription(resource)]
}

def private IEObjectDescription toDescription(String name, Resource resource) {

    ExternalFactoryImpl.init()
    val ExternalFactory factory = new ExternalFactoryImpl()

    val Stakeholder obj = factory.createStakeholder as StakeholderImpl

    obj.setName(name)
    // not sure why or how but when adding the obj to the resource, the
    // the resource will be set in obj . . . thus no more dangling ref
    resource.contents += obj


    new StakeholderDescription(name, obj, uri)
} 

这篇关于XText 对非 DSL 资源的交叉引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆