Как получить тело метода JvmModelInferrer из XExpression и добавить шаблонный код

Как в JvmModelInferrer при построении тела метода или конструктора вставить оба XExpression из грамматики

body = op.body

и дополнительный "стандартный" код, например

body = [
    append(
    '''
        System.out.println("BOILERPLATE");
    '''
    )
]

Я могу достичь любого, но не обоих.

В качестве минимального рабочего примера рассмотрим следующую каноническую грамматику Xbase:

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)? '{'
        attributes += Attribute*
        operations += Operation*
    '}';

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

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

и JvmModelInferrer,

package org.example.xbase.entities.jvmmodel

import com.google.inject.Inject
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

    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
            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 = [
//                  append(
//                  '''
//                      System.out.println("BOILERPLATE");
//                  '''
//                  )
//              ]
                body = op.body
                ]
            ]
        ]
    }
}

Как следует из комментариев, я хотел бы вставить «шаблонный» код в тело метода перед самим XExpression. Хотя я могу вставить шаблон или выражение, я не могу понять, как сделать и то, и другое.


person fundagain    schedule 10.10.2018    source источник


Ответы (1)


это не работает. единственное, что вы можете сделать, это вывести два метода

methodWithBoilerplate() {
    //pre
    methodwithoutboilerplate
    //post
}
methodwithoutboilerplate() {
    usercode goes here
}
  • для первого использования body = '''code here'''
  • для второго использования body = exp.body
person Christian Dietrich    schedule 10.10.2018
comment
Спасибо за ответ. Этот подход был моей работой, но я хотел посмотреть, нет ли более чистого решения. Разве нет естественного пути через XExpression API? Объедините выражения, а затем установите тело? (Конечно смотрел.) - person fundagain; 10.10.2018
comment
Как я уже сказал: нет хорошего способа сделать это программно. - person Christian Dietrich; 10.10.2018