在 Xtext Validator 中引用语法

Referencing Grammar in Xtext Validator

在 Xtext 验证器中,我想断言聚合不引用另一个聚合

有了这个简化的语法

grammar com.mimacom.mdd.ddd.MdDsl with org.eclipse.xtext.xbase.Xbase

generate mdDsl "http://www.mimacom.com/mdd/ddd/MdDsl"  

Domainmodel:
    elements+=Element*;

Element:
    Aggregate | ValueObject;

Aggregate:
    'aggregate' name=ValidID ('extends' superType=JvmTypeReference)? '{'
        properties+=Property*
    '}';

ValueObject:
    'valueObject' name=ValidID ('extends' superType=JvmTypeReference)? '{'
        properties+=Property*
    '}';

Property:
    name=ValidID ':' type=JvmTypeReference;

当我解析以下内容时,我希望能够找出 属性 是 valueObject 还是聚合

aggregate Address{
}
aggregate Person{
    p : Address
}

验证如下所示 我无法从 属性 中提取信息以找出答案 如果 属性 的类型是聚合

@Inject
IJvmModelAssociations assoc;

@Check
def aggregateDoesNotReferenceOtherAggregates(Aggregate aggregate) {
    var features = aggregate.features

    for(Feature f : features){
        println(f)
        var s = assoc.getSourceElements(f.type.type)
        var first = s.get(0)
        if(first instanceof Aggregate   ){
            warning('An aggregate is not allowed to reference another aggregate'
                , null
                , aggregate.eContainingFeature)
        }
    }
}

我在这里添加推断器:

class MdDslJvmModelInferrer extends AbstractModelInferrer {

@Inject extension JvmTypesBuilder
@Inject extension IQualifiedNameProvider

def dispatch void infer(Aggregate aggregate, IJvmDeclaredTypeAcceptor acceptor, boolean isPrelinkingPhase) {
    acceptor.accept(aggregate.toClass(aggregate.fullyQualifiedName)) [
        processAggregate(aggregate, it)
    ]
}

def dispatch void infer(ValueObject element, IJvmDeclaredTypeAcceptor acceptor, boolean isPrelinkingPhase) {
    acceptor.accept(element.toClass(element.fullyQualifiedName)) [
        processValueObject(element, it)
    ]
}

protected def void processAggregate(Aggregate aggregate, JvmGenericType it) {
    documentation = aggregate.documentation
    if (aggregate.superType !== null)
            superTypes += aggregate.superType.cloneWithProxies

    for (feature : aggregate.features) {
        switch feature {
            Property: {
                members += feature.toField(feature.name, feature.type)
                members += feature.toGetter(feature.name, feature.type)
                members += feature.toSetter(feature.name, feature.type)
            }
            Operation: {
                processOperation(it, feature)
            }
        }
    }
}

protected def void processValueObject(ValueObject element, JvmGenericType it) {
    documentation = element.documentation
    if (element.superType !== null)
            superTypes += element.superType.cloneWithProxies
    for (feature : element.features) {
        switch feature {
            Property: {
                members += feature.toField(feature.name, feature.type)
                members += feature.toGetter(feature.name, feature.type)
            }
            Operation: {
                processOperation(it, feature)
            }
        }
    }
}

protected def boolean processOperation(JvmGenericType it, Operation feature) {
    members += feature.toMethod(feature.name, feature.type) [
        documentation = feature.documentation
        for (p : feature.params) {
            parameters += p.toParameter(p.name, p.parameterType)
        }
        body = feature.body
    ]
}
}

我执行的测试给出了一个空源,看起来像这样

@ExtendWith(InjectionExtension)
@InjectWith(MdDslInjectorProvider)
class MdDslParsingTest {
    @Inject 
    extension CompilationTestHelper

    @Test
    def void aggregateDoesNotReferenceOtherAggregate() {
        val result = parseHelper.parse('''
            aggregate Address{
            }
            aggregate Person{
                a : Address
            }
        ''')

    validationHelper.assertWarning(result,result.eClass,"failed to find the problem")
    }
}

我无法重现这个

class MyDslValidator extends AbstractMyDslValidator {

    @Inject
    private IJvmModelAssociations assoc

    @Check
    def checkAggregateReference(Aggregate aggregate) {
        var properties = aggregate.properties

        for (f : properties) {
            System.err.println(f)
            System.err.println(assoc.getSourceElements(f.type.type))
        }
    }

}

给我

org.xtext.example.mydsl.myDsl.impl.PropertyImpl@15c4ae78 (name: p)
[org.xtext.example.mydsl.myDsl.impl.AggregateImpl@6952cae7 (name: Address)

符合预期