【问题标题】:Get declarations from an external source in Xtext在 Xtext 中从外部源获取声明
【发布时间】:2014-11-10 21:07:42
【问题描述】:

我的语法如下:

Model: declarations += Declaration* statements += Statement*;
Declaration: 'Declare' name=ID;
Statement: 'Execute' what=[Declaration];

有了它,我可以编写简单的脚本,例如:

Declare step_forward
Declare turn_right
Declare turn_left

Execute step_forward
Execute turn_left
Execute step_forward

现在我希望 java 程序提供所有声明,以便脚本只包含 Execute 语句。我读到了IGlobalScopeProvider,这似乎是适合这项工作的工具,但我不知道如何将我的数据添加到其中,以及如何让 Xtext 使用它。

那么,我如何从语法外部提供声明?

更新

我的目标有点不清楚,所以我试着让它更具体。我想将声明保留为简单的 java 对象,例如:

List<Move> declarations = Arrays.asList(
    new Move("step_forward"),
    new Move("turn_right"),
    new Move("turn_left"));

脚本应该是:

Execute step_forward
Execute turn_left
Execute step_forward

【问题讨论】:

    标签: xtext


    【解决方案1】:

    我不太确定您要的是什么。经过思考,我可以得出以下可能的问题:

    1.) 您想将脚本拆分为两个文件。文件 a 将仅包含您的声明,而文件 b 将仅包含声明。但是任何 'what' 属性都会引用 File a 的声明。

    这适用于您的语法。

    2.) 您有任何 Java 源代码提供了定义的类,例如“声明接口”,并且您希望“什么”属性引用此接口或实现此接口的类。

    更新答案您应该在您的语言中使用 Xbase。在那里,您可以使用 Xtypes 规则“JvmTypeReference”定义您的“what”属性对任何 Java 类型的引用。您必须在语法中进行的修改并不难,我认为它可能看起来像这样:

    // Grammar now inherits from the Xbase grammar 
    // instead of the common terminals grammar
    grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.xbase.Xbase
    
    generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"
    
    Model:
        declarator=Declarator?
        statements+=Statement*;
    
    Declarator:
        'Declare' name=ID;
    
    Statement:
        'Execute' what=JvmTypeReference;
    

    您可以通过使用它们的限定名称对它们进行寻址来引用任何 Java 类型(Java API、任何链接的 API、用户定义的类型)。它看起来像这样: Referring to JVM types look like this in an Xtext language. (Screenshot)

    您还可以验证引用的 JVM 类型是否有效,例如实现了一个所需的接口,我将在模型中使用一个可选的声明符来定义它。 Referenced JVM type is checked whether it is a valid type. (Screenshot)

    使用 Xbase 很容易为这个模型元素推断 Java 接口。使用生成的存根 '...mydsl.MyDslJvmModelInferrer':

    class MyDslJvmModelInferrer extends AbstractModelInferrer {
    
        @Inject extension JvmTypesBuilder
        @Inject extension TypeReferences
        def dispatch void infer(Model element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
            acceptor.accept(
                element.declaration.toInterface('declarator.' + element.declaration.name) [
                    members += it.toMethod("execute", TypesFactory.eINSTANCE.createJvmVoid.createTypeRef)[]
                ])
        }
    }
    

    它派生一个接口,单独命名,只有一个方法'execute()'。

    然后,像这样实现静态检查,您应该使用生成的存根 '...mydsl.validation.MyDslValidator' 在我的示例中它非常快速和肮脏,但您应该了解它:

    class MyDslValidator extends AbstractMyDslValidator {
    
        @Check
        def checkReferredType(Statement s) {
            val declarator = (s.eContainer as Model).declaration.name
            for (st : (s.what.type as JvmDeclaredType).superTypes) {
                if (st.qualifiedName.equals('declarator.' + declarator)) {
                    return
                }
            }
            (s.what.simpleName + " doesn't implement the declarator interface " + declarator).
                warning(MyDslPackage.eINSTANCE.statement_What)
        }
    }
    

    (我使用首选的 Xtend 编程语言来实现静态检查!)静态检查确定给定的 JvmTypeReference(它是您项目中的 Java 类)是否实现了声明的接口。否则,它会在您的 dsl 文档中引入警告。

    希望这能回答你的问题。

    下一次更新:你的想法不会那么好用!你可以简单地用 Xtend 编写一个模板而不使用 Xbase,但我无法想象如何以一种好的方式使用它。问题是,我假设您不会生成孔类“移动”和孔执行过程。我玩了一点尝试生成可用的代码,似乎很hacky!尽管如此,这是我的解决方案:

    Xtext 使用“void doGenerate”方法为您生成了存根“...mydsl.generator.MyDslGenerator”。您必须填写此方法。我的想法如下:首先,您生成一个带有两个泛型参数 T 和 U 的抽象和泛型 Executor 类。然后我的 executor 类有一个返回值 T 的抽象方法“executeMoves()”。如果这应该是无效的,请使用非原始的“无效”类。它包含您的 List,但属于通用类型 u,它被定义为 Move 类的子类。

    Move 类也将生成,但只有一个用于存储字符串的字段。然后它必须被导出。我的“MyDslGenerator”看起来像这样:

    class MyDslGenerator implements IGenerator {
        static var cnt = 0
        override void doGenerate(Resource resource, IFileSystemAccess fsa) {
            cnt = 0
            resource.allContents.filter(typeof(Model)).forEach [ m |
                fsa.generateFile('mydsl/execution/Move.java', generateMove)
                fsa.generateFile('mydsl/execution/Executor' + cnt++ + '.java', m.generateExecutor)
            ]
        }
    
        def generateMove() '''
            package mydsl.execution;
            public class Move {
                protected String s;
                public Move(String s) {
                    this.s = s;
                }
            }
        '''
    
        def generateExecutor(Model m) '''
            package mydsl.execution;
            import java.util.List;
            import java.util.Arrays;
            /**
             * The class Executor is abstract because the execution has to implemented somewhere else.
             * The class Executor is generic because one does not know if the execution has a return
             * value. If it has no return value, use the not primitive type 'Void':
             * public class MyExecutor extends Executor_i<Void> {...}
             */
            public abstract class Executor«cnt - 1»<T, U extends Move> {
                @SuppressWarnings("unchecked")
                private List<U> declarations = Arrays.<U>asList(
                    «FOR Statement s : m.statements»
                        (U) new Move("«s.what.name»")«IF !m.statements.get(m.statements.size - 1).equals(s)»,«ENDIF»
                    «ENDFOR»
                );
                /**
                 * This method return list of moves.
                 */
                public List<U> getMoves() {
                    return declarations;
                }
                /**
                 * The executor class has to be extended and the extending class has to implement this
                 * method.
                 */
                public abstract T executeMoves();
            }'''
    }
    

    【讨论】:

    • 非常感谢您的详细回答;但正如你提到的,我的问题不清楚。刚刚更新了问题。我的语言与 Java/JVM 无关。那么使用Xbase有意义吗?
    • 如果你只想从执行语句中生成一个简单的列表,你不需要Xbase。如果您想引用 JVMTypes 或者您需要一些语言中的表达式,通常会使用 Xbase。看答案如何创建你想要的Java代码,我已经更新了。
    猜你喜欢
    • 2017-10-31
    • 2023-03-22
    • 2020-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多