Xtext:在DSL文件中使用生成的类,缺少类型的问题

Xtext: use generated classes in DSL file, problem of missing type

问题:我如何配置 Xtext 和 Xbase 以便在我的 DSL 文件(带有 DSL 扩展名“.myx”的文件)中使用 classJvmModelInferrer 尚未生成的文件?

这是语言语法:

grammar org.xtext.example.mydsl.MyX with org.eclipse.xtext.xbase.Xbase

generate myX "http://www.xtext.org/example/mydsl/MyX" 
import "http://www.eclipse.org/xtext/xbase/Xbase" as xbase

Model:
    expressions+=CommonExpression*;
    
CommonExpression: 
    Anime | AnimeResource
;

AnimeResource:
    'AnimeRes' name=ID '{'
    (args+=FullJvmFormalParameter)*
    '}'
;

Anime:
    'watch' name=ID body=XBlockExpression
;

这是我想要实现的 (test.myx):

AnimeRes Resource {
    
}


watch Watcher {
    val someStub = Resource.create()
}

所以 dsl 文件看起来像是为 Resource class 定义了一个静态方法。但实际上,必须有额外的参数应该传递给资源,在我的例子中它们纯粹是样板,这就是为什么我不想每次都将它们传递给“创建”。 我希望生成的文件看起来如何实现:

package test;

public class Model {
  private int id= 0;
  
  public static class Resource {
    private int id;
    public Resource(final int id) {
      this.id = id;
    }
  }
  
  public class ResourceCreator {
    public Resource create() {
      return new Resource(id /* the creator is inner non-static class */));
    }
  }
  
  public ResourceCreator Resource = new ResourceCreator();
}

那样我有点作弊。我有一个名称为 class 的变量,在客户端代码中,当他们实际上只是在使用名为 class 的构建器时,它们看起来像是使用静态方法。这是制作类似文件的 JvmModelInferrer:

import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer
import org.xtext.example.mydsl.myX.Model
import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor
import org.eclipse.xtext.naming.QualifiedName
import com.google.inject.Inject
import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder
import org.xtext.example.mydsl.myX.AnimeResource
import org.eclipse.xtext.common.types.JvmVisibility
import org.xtext.example.mydsl.myX.Anime

class MyXJvmModelInferrer extends AbstractModelInferrer {
        @Inject extension JvmTypesBuilder
    
        def dispatch void infer(Model element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
            acceptor.accept(element.toClass(QualifiedName.create("test", "Model"))) [
                for (expression : element.expressions) {
                    switch (expression ) {
                        AnimeResource: {
                            members += expression.toClass(expression.name) [
                                static = true
                                visibility = JvmVisibility.PUBLIC
                                val _members = members
                                expression.args.forEach [
                                    _members += expression.toField(name, parameterType) [
                                        static = false
                                        visibility = JvmVisibility.PUBLIC
                                    ]

                                ]
                                members += expression.toField("id", typeRef(int))

                                members += expression.toConstructor [
                                    val _parameters = parameters
                                    expression.args.forEach [
                                        _parameters += it.toParameter(name, parameterType)
                                    ]
                                    _parameters += expression.toParameter("id", typeRef(int))
                                    body = '''
                                        «FOR param : parameters»this.«param.name» = «param.name»;
                                        «ENDFOR»
                                    '''
                                ]
                            ]
                            members += expression.toField("id", typeRef(int))
                            
                            members += element.toClass(expression.name + "Creator") [
                                static = false
                                visibility = JvmVisibility.PUBLIC
                                members += element.toMethod("create", typeRef(expression.name)) [
                                    val parameters = parameters
                                    expression.args.forEach [
                                        parameters += it.toParameter(name, parameterType)
                                    ]
                                    body = '''
                                        return new «expression.name»(«FOR param : parameters»«IF parameters.indexOf(param) < parameters.size - 1», «ENDIF»«ENDFOR»id);
                                    '''
                                ]
                            ]
                            members += expression.toField(expression.name, typeRef(expression.name + "Creator")) [
                                visibility = JvmVisibility.PUBLIC
                                initializer = '''
                                    new «expression.name + "Creator"»()
                                '''
                            ]
                        }
                       Anime: {
                            members  += expression.toMethod(expression.name, typeRef(void)) [
                                body = expression.body
                            ]
                       }
                    }
                }
            ]
        }
}

我使用这种方法遇到的问题:

所以似乎有些链接失败了,但我不明白我应该做什么来解决这个问题,我应该覆盖哪些绑定以及如何覆盖。

如有任何帮助,我们将不胜感激。

更新。使用可编译的 ModelInferrer 更新了描述(抱歉)。当我尝试使用 watch 块的 XBlockExpression 为模型 class 内部的方法生成 Java 代码时,就会出现问题。所以如果我有这样的 DSL 文件:

AnimeRes Resource {
    
}

watch Watcher {
    val some = Resource.create()
}

并且还在 Inferrer 中使用 Anime 分支,出现了所描述的问题。 如果我有相同的文件并且不使用动漫分支(这样注释掉):

//                     Anime: {
//                          members  += expression.toMethod(expression.name, typeRef(void)) [
//                              body = expression.body
//                          ]
//                     }

那就没问题了,但我需要生成那个方法。

您需要为内部类型使用专有名称

members += element.toClass(expression.name + "Creator") [
    static = false
    visibility = JvmVisibility.PUBLIC
    members += element.toMethod("create", typeRef("test.Model$"+expression.name)) [
        val parameters = parameters
        expression.args.forEach [
            parameters += it.toParameter(name, parameterType)
        ]
        body = '''
            return new «expression.name»(«FOR param : parameters»«IF parameters.indexOf(param) < parameters.size - 1», «ENDIF»«ENDFOR»id);
        '''
    ]
]
members += expression.toField(expression.name, typeRef("test.Model$"+expression.name + "Creator")) [
    visibility = JvmVisibility.PUBLIC
    initializer = '''
        new «expression.name + "Creator"»()
    '''
]