Tuesday, 27 September 2016

Validating Siblings of different Type with same super Type in XText

Xtext provides various mechanism for validating the models. It as well provides some default implementation for recurring issues. One such implementation is NamesAreUniqueValidator, which validates the model names for uniqueness in the given scope. One can use this default validation by configuring the DSL workflow (*.mwe2) as shown below.

// Xtend-based API for validation
fragment = validation.ValidatorFragment auto-inject {
composedCheck = "org.eclipse.xtext.validation.ImportUriValidator"
composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator"
}

The above validator works great within any given scope. But the validator by default considers the super type as a context during validation. In the below example, Type is a super class of DataType, Entity, Enumeration

grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals

generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"

Domainmodel:
    (elements+=Type)*;

Type:
    DataType | Entity | Enumeration;

DataType:
    'datatype' name=ID;

Entity:
    'entity' name=ID ('extends' superType=[Entity])? '{'
    (features+=Feature)*
    '}';

Enumeration:
    'enum' name=ID '{'
    literals+=Literal* '}';

Literal:
    'literal' name=ID;

Feature:
    (many?='many')? name=ID ':' type=[Type];

Which means, we will not be able to create a Type with same name. Precisely, I cannot have a same name for Enumeration and Entity. The editor will be marked with red ink as shown below.


The above behavior is perfectly normal, but this can be changed to check Entity, Enumeration and DataType separately within a scope. NamesAreUniqueValidator uses a helper NamesAreUniqueValidationHelper, which indeed does this classification of types. By default the above helper returns a base class as a type for context. So using XText binding mechanism, one can bind the custom helper

1. Custom Helper Implementation

package org.xtext.example.mydsl.validation;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.xtext.validation.NamesAreUniqueValidationHelper;
import org.xtext.example.mydsl.myDsl.MyDslPackage;

public class CustomNamesAreUniqueValidationHelper extends NamesAreUniqueValidationHelper {

    @Override
    protected EClass getAssociatedClusterType(EClass eClass) {
        if (MyDslPackage.Literals.TYPE.isSuperTypeOf(eClass)) {
            // you can check for entity, enumeration ,separately as well
            return eClass;
        }
        return super.getAssociatedClusterType(eClass);
    }
}

2. Binding in RuntimeModule
Now bind the new Custom helper in your *RuntimeModule.java a shown below

public Class<? extends INamesAreUniqueValidationHelper> bindINamesAreUniqueValidationHelper(){
    return CustomNamesAreUniqueValidationHelper.class;

}

No comments:

Post a Comment