Value converters are registered to convert the parsed text into a certain data type instance and vice versa. The primary hook is called IValueConverterService and the concrete implementation can be registered via the runtime Guice module. To do so override the corresponding binding in your runtime module like shown in this example:
@Override
public Class<? extends IValueConverterService> bindIValueConverterService() {
return MySpecialValueConverterService.class;
}
The most simple way to register additional value converters is to make use of
AbstractDeclarativeValueConverterService, which allows to
declaratively register an
IValueConverter
via an annotated method.
The implementation for the default token grammar looks like
public class DefaultTerminalConverters
extends AbstractDeclarativeValueConverterService {
(..)
@ValueConverter(rule = "ID")
public IValueConverter<String> ID() {
return new AbstractNullSafeConverter<String>() {
@Override
protected String internalToValue(String string, AbstractNode node) {
return string.startsWith("^") ? string.substring(1) : string;
}
@Override
protected String internalToString(String value) {
if (GrammarUtil.getAllKeywords(getGrammar()).contains(value)) {
return "^" + value;
}
return value;
}
};
}
... some other value converter
}
If you use the common terminals grammar
org.eclipse.xtext.common.Terminals
you should subclass
DefaultTerminalConverters
and override or add additional value converters by adding the respective methods.
Imagine, you would want to add a rule BIG_DECIMAL creating BigDecimals, it would look like this one:
@ValueConverter(rule = "BIG_DECIMAL")
public IValueConverter<BigDecimal> BIG_DECIMAL() {
return new AbstractToStringConverter<BigDecimal>() {
@Override
protected BigDecimal internalToValue(String string, AbstractNode node) {
return BigDecimal.valueOf(string);
}
};
}