Грамматически ограниченное наследование JVMModelInferrer с Xtext и XBase

Следующая каноническая грамматика сущностей XBase (из «Реализации предметно-ориентированных языков с помощью Xtext и Xtend» Беттини) позволяет сущностям расширять любой класс Java. Как видно из строки комментария, я хотел бы грамматически заставить сущности только наследовать от сущностей.

grammar org.example.xbase.entities.Entities with org.eclipse.xtext.xbase.Xbase

generate entities "http://www.example.org/xbase/entities/Entities"

Model:
    importSection=XImportSection?
    entities+=Entity*;

Entity:
    'entity' name=ID ('extends' superType=JvmParameterizedTypeReference)? '{'
//  'entity' name=ID ('extends' superType=[Entity|QualifiedName])? '{'
        attributes += Attribute*
        constructors+=Constructor*
        operations += Operation*
    '}';

Attribute:
    'attr' (type=JvmTypeReference)? name=ID ('=' initexpression=XExpression)? ';';

Operation:
    'op' (type=JvmTypeReference)? name=ID 
    '(' (params+=FullJvmFormalParameter (',' params+=FullJvmFormalParameter)*)? ')' 
        body=XBlockExpression;

Constructor:    'new'  
    '(' (params+=FullJvmFormalParameter (',' params+=FullJvmFormalParameter)*)? ')' 
        body=XBlockExpression;

Вот работающий JVMModelInferrer для приведенной выше модели, опять же, где закомментированная строка (и дополнительный метод) отражают мое намерение.

package org.example.xbase.entities.jvmmodel

import com.google.inject.Inject
import org.eclipse.xtext.common.types.JvmTypeReference
import org.eclipse.xtext.naming.IQualifiedNameProvider
import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer
import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor
import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder
import org.example.xbase.entities.entities.Entity

class EntitiesJvmModelInferrer extends AbstractModelInferrer {

    @Inject extension JvmTypesBuilder
    @Inject extension IQualifiedNameProvider

    def dispatch void infer(Entity entity, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
        acceptor.accept(entity.toClass("entities." + entity.name)) [
            documentation = entity.documentation
            if (entity.superType !== null) {
                superTypes += entity.superType.cloneWithProxies
                //superTypes += entity.superType.jvmTypeReference.cloneWithProxies
            }

            entity.attributes.forEach [ a |
                val type = a.type ?: a.initexpression?.inferredType
                members += a.toField(a.name, type) [
                    documentation = a.documentation
                    if (a.initexpression != null)
                        initializer = a.initexpression
                ]
                members += a.toGetter(a.name, type)
                members += a.toSetter(a.name, type)
            ]
            entity.operations.forEach [ op |
                members += op.toMethod(op.name, op.type ?: inferredType) [
                    documentation = op.documentation
                    for (p : op.params) {
                        parameters += p.toParameter(p.name, p.parameterType)
                    }
                    body = op.body
                ]
            ]
            entity.constructors.forEach [ con |
                members += entity.toConstructor [
                    for (p : con.params) {
                        parameters += p.toParameter(p.name, p.parameterType)
                    }
                    body = con.body
                ]
            ]
        ]
    }

    def JvmTypeReference getJvmTypeReference(Entity e) {
        e.toClass(e.fullyQualifiedName).typeRef
    }

}

Следующий простой экземпляр отлично анализирует и делает выводы (с комментариями на месте).

entity A {
    attr String y;

    new(String y) {
        this.y=y        
    }

}    

entity B extends A {
    new() {
        super("Hello World!")
    }
} 

Если, однако, я раскомментирую (и прокомментирую в соответствующей строке выше) и грамматику, и механизм вывода (и регенерирую), приведенный выше экземпляр больше не будет анализироваться. Сообщение "Метод super(String) не определен".

Я понимаю, как оставить наследование «свободным» и ограничить использование валидаторов и т. д., но предпочел бы строго ввести это в модель.

Я не знаю, как это решить, так как я не уверен, где что-то ломается, учитывая роль XBase и JvmModelInferrer. Указатель (или ссылка) будет достаточно.

[... Я могу реализовать все проблемы с областью действия для не-xbase-версии этой грамматики...]


person fundagain    schedule 17.10.2018    source источник
comment
это не сработает. лучше оставить грамматику как есть, отфильтровать предложения и ввести проверку   -  person Christian Dietrich    schedule 18.10.2018
comment
в качестве альтернативы, если вы можете угадать имя ссылки (например, из модели узла), вы можете использовать "qualified.Name.Of.Entity".typeRef для супертипа   -  person Christian Dietrich    schedule 18.10.2018
comment
Разве это не совсем то, что я делаю с моим вспомогательным методом getJvmTypeReference(Entity e)? Результирующее квалифицированное имя правильное, но super(String) не виден из B.   -  person fundagain    schedule 18.10.2018
comment
Не в том, что вы написали выше   -  person Christian Dietrich    schedule 18.10.2018
comment
Большое спасибо. Я понимаю, что вы имеете в виду, и это работает. Необходимая строка (в данном случае) — superTypes += (entities.+entity.superType.name).typeRef(). Ответьте, пожалуйста.   -  person fundagain    schedule 18.10.2018


Ответы (1)


это не сработает. вы либо должны оставить грамматику как есть и настроить поставщика предложения и проверку. или вы должны использовать "f.q.n.o.y.Entity".typeRef. Вы можете использовать NodeModelUtils для чтения FQN или попробовать что-то вроде ("entities."+entity.superType.name).typeRef

person Christian Dietrich    schedule 18.10.2018