blob: a226b95155e40205cf1f37263d21719fad431492 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2019 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.xtext.base.services;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal;
import org.eclipse.ocl.pivot.utilities.StringUtil;
import org.eclipse.xtext.AbstractRule;
import org.eclipse.xtext.Grammar;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.Keyword;
import org.eclipse.xtext.ParserRule;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.conversion.IValueConverter;
import org.eclipse.xtext.conversion.ValueConverter;
import org.eclipse.xtext.conversion.ValueConverterException;
import org.eclipse.xtext.conversion.impl.AbstractDeclarativeValueConverterService;
import org.eclipse.xtext.conversion.impl.AbstractNullSafeConverter;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.util.Strings;
public class BaseValueConverterService extends AbstractDeclarativeValueConverterService
{
//
// The seemingly redundant Identifier as well as ID converters are needed. During serialization
// the exact rule-specific converter is used.
//
protected static abstract class AbstractIDConverter extends AbstractNullSafeConverter<String>
{
@Override
protected String internalToValue(String string, INode node) {
int length = string.length();
if (string.startsWith("_'") && (length >= 3) && string.endsWith("'")) {
return StringUtil.convertFromOCLString(string.substring(2, length-1));
}
else if (string.startsWith("'") && (length >= 2) && string.endsWith("'")) {
return string.substring(1, length-1);
}
else if (string.startsWith("\"") && (length >= 2) && string.endsWith("\"")) {
return string.substring(1, length-1);
}
else {
return string;
}
}
}
protected static class BinaryOperatorNameConverter implements IValueConverter<String>
{
private final Set<String> navigationOperatorNameKeywords;
protected static Set<String> computeKeywords(Grammar grammar) {
Set<String> keywords = getAllKeywords(grammar, "NavigationOperatorName", false);
return keywords;
}
public BinaryOperatorNameConverter(Grammar grammar) {
navigationOperatorNameKeywords = computeKeywords(grammar);
// printKeywords("NavigationOperatorName", navigationOperatorNameKeywords);
}
@Override
public String toValue(String string, INode node) {
return string.trim();
}
@Override
public String toString(String value) {
if (navigationOperatorNameKeywords.contains(value)) {
return value.toString();
}
else {
return " " + value.toString() + " ";
}
}
}
protected static class DoubleQuotedStringConverter extends AbstractNullSafeConverter<String>
{
@Override
protected String internalToValue(String string, INode node) {
try {
String result = string.substring(1, string.length() - 1);
assert result != null;
return StringUtil.convertFromOCLString(result);
} catch(IllegalArgumentException e) {
throw new ValueConverterException(e.getMessage(), node, e);
}
}
@Override
protected String internalToString(String value) {
return '"' + StringUtil.convertToOCLString(value) + '"';
}
}
protected static class EscapedIDConverter extends AbstractIDConverter
{
@Override
protected String internalToString(String value) { // Never called
return value;
}
}
protected static class IDConverter extends AbstractIDConverter
{
private final Set<String> allKeywords;
public IDConverter(Grammar grammar) {
allKeywords = GrammarUtil.getAllKeywords(grammar);
}
@Override
protected String internalToString(String value) {
if (allKeywords.contains(value)) {
return escapeIdentifier(value);
}
else if (!PivotUtilInternal.isValidIdentifier(value)) {
return escapeIdentifier(value);
}
else {
return value;
}
}
}
protected static class MultiLineSingleQuotedStringConverter extends AbstractNullSafeConverter<String>
{
@Override
protected String internalToValue(String string, INode node) {
try {
String result = string.substring(2, string.length() - 2);
assert result != null;
return StringUtil.convertFromOCLString(result);
} catch(IllegalArgumentException e) {
throw new ValueConverterException(e.getMessage(), node, e);
}
}
@Override
protected String internalToString(String value) {
return "'" + StringUtil.convertToOCLString(value) + "'";
}
}
protected static class NameConverter extends AbstractIDConverter
{
private final Set<String> nameKeywords;
protected static Set<String> computeKeywords(Grammar grammar) {
Set<String> keywords = new HashSet<String>(GrammarUtil.getAllKeywords(grammar));
keywords.removeAll(getAllKeywords(grammar, "UnrestrictedName", true));
keywords.removeAll(getAllKeywords(grammar, "EssentialOCLReservedKeyword", true));
keywords.removeAll(getAllKeywords(grammar, "RestrictedKeywords", true));
keywords.removeAll(getAllKeywords(grammar, "CollectionTypeIdentifier", true));
keywords.removeAll(getAllKeywords(grammar, "PrimitiveTypeIdentifier", true));
return keywords;
}
public NameConverter(Grammar grammar) {
nameKeywords = computeKeywords(grammar);
// printKeywords("Name", nameKeywords);
}
@Override
protected String internalToString(String value) {
if (nameKeywords.contains(value)) {
return escapeIdentifier(value);
}
else if (!PivotUtilInternal.isValidIdentifier(value)) {
return escapeIdentifier(value);
}
else {
return value;
}
}
}
protected static class NumberConverter implements IValueConverter<Number>
{
@Override
public Number toValue(String string, INode node) {
if (Strings.isEmpty(string))
throw new ValueConverterException("Couldn't convert empty string to number", node, null);
try {
if (string.contains(".") || string.contains("e") || string.contains("e")) {
return new BigDecimal(string);
}
else {
return new BigInteger(string);
}
} catch (NumberFormatException e) {
throw new ValueConverterException("Couldn't convert '"+string+"' to number", node, e);
}
}
@Override
public String toString(Number value) {
return value.toString();
}
}
protected static class SimpleIDConverter extends AbstractNullSafeConverter<String>
{
@Override
protected String internalToValue(String string, INode node) {
return string;
}
@Override
protected String internalToString(String value) { // Never called
return value;
}
}
protected static class SingleQuotedStringConverter extends AbstractNullSafeConverter<String>
{
@Override
protected String internalToValue(String string, INode node) {
try {
String result = string.substring(1, string.length() - 1);
assert result != null;
return StringUtil.convertFromOCLString(result);
} catch(IllegalArgumentException e) {
throw new ValueConverterException(e.getMessage(), node, e);
}
}
@Override
protected String internalToString(String value) {
return "'" + StringUtil.convertToOCLString(value) + "'";
}
}
protected static class UnquotedStringConverter extends AbstractNullSafeConverter<String>
{
@Override
protected String internalToValue(String string, INode node) {
try {
String result = string.substring(1, string.length() - 1);
assert result != null;
return StringUtil.convertFromOCLString(result);
} catch(IllegalArgumentException e) {
throw new ValueConverterException(e.getMessage(), node, e);
}
}
@Override
protected String internalToString(String value) {
value = value.replace("\r", "");
int lastComment = value.lastIndexOf("--");
if (lastComment >= 0) {
int lastNewLine = value.lastIndexOf("\n");
if (lastNewLine < lastComment) {
value = value + "\n"; // Avoid the trailing ';' getting added within the comment
}
}
// if ((value.length() > 0) && (value.charAt(0) == '\n')) {
// value = " " + value;
// }
return value;
}
}
protected static class UnreservedNameConverter extends AbstractIDConverter
{
private final Set<String> reservedKeywords;
protected static Set<String> computeReservedKeywords(Grammar grammar) {
Set<String> keywords = new HashSet<String>(GrammarUtil.getAllKeywords(grammar));
// printKeywords("All", keywords);
Set<String> unreservedNames = getAllKeywords(grammar, "UnreservedName", true);
// printKeywords("Unreserved", unreservedNames);
keywords.removeAll(unreservedNames);
return keywords;
}
public UnreservedNameConverter(Grammar grammar) {
reservedKeywords = computeReservedKeywords(grammar);
// printKeywords("Reserved", reservedKeywords);
}
@Override
protected String internalToString(String value) {
if (reservedKeywords.contains(value)) {
return escapeIdentifier(value);
}
else if (!PivotUtilInternal.isValidIdentifier(value)) {
return escapeIdentifier(value);
}
else {
return value;
}
}
}
protected static class UnrestrictedNameConverter extends AbstractIDConverter
{
private final Set<String> restrictedKeywords;
protected static Set<String> computeRestrictedKeywords(Grammar grammar) {
Set<String> keywords = new HashSet<String>(GrammarUtil.getAllKeywords(grammar));
Set<String> unrestrictedNames = getAllKeywords(grammar, "UnrestrictedName", true);
// printKeywords("Unrestricted", unrestrictedNames);
keywords.removeAll(unrestrictedNames);
return keywords;
}
public UnrestrictedNameConverter(Grammar grammar) {
restrictedKeywords = computeRestrictedKeywords(grammar);
// printKeywords("Restricted", restrictedKeywords);
}
@Override
protected String internalToString(String value) {
if (restrictedKeywords.contains(value)) {
return escapeIdentifier(value);
}
else if (!PivotUtilInternal.isValidIdentifier(value)) {
return escapeIdentifier(value);
}
else {
return value;
}
}
}
protected static class UpperConverter extends AbstractNullSafeConverter<Integer>
{
@Override
public Integer internalToValue(String string, INode node) {
if (Strings.isEmpty(string))
throw new ValueConverterException("Couldn't convert empty string to integer", node, null);
try {
if ("*".equals(string)) {
return Integer.valueOf(-1);
}
return Integer.valueOf(string);
} catch (NumberFormatException e) {
throw new ValueConverterException("Couldn't convert '"+string+"' to integer", node, e);
}
}
@Override
public String internalToString(Integer value) {
return value >= 0 ? value.toString() : "*";
}
}
public static String escapeIdentifier(String value) {
return "_'" + StringUtil.convertToOCLString(value) + "'";
}
public static Set<String> getAllKeywords(Grammar g, String name, boolean validIdentifiersOnly) {
Set<String> kws = new HashSet<String>();
List<ParserRule> rules = GrammarUtil.allParserRules(g);
for (ParserRule parserRule : rules) {
if (parserRule.getName().equals(name)) {
getAllKeywords(kws, parserRule, validIdentifiersOnly);
}
}
return kws;
}
private static void getAllKeywords(Set<String> kws, AbstractRule parserRule, boolean validIdentifiersOnly) {
for (TreeIterator<EObject> tit = parserRule.eAllContents(); tit.hasNext(); ) {
Object ele = tit.next();
if (ele instanceof Keyword) {
String value = ((Keyword)ele).getValue();
if (!validIdentifiersOnly || PivotUtilInternal.isValidIdentifier(value)) {
kws.add(value);
}
}
else if (ele instanceof RuleCall) {
getAllKeywords(kws, ((RuleCall)ele).getRule(), validIdentifiersOnly);
}
}
}
// private static void printKeywords(String prefix, Collection<String> keywords) {
// List<String> list = new ArrayList<String>(keywords);
// Collections.sort(list);
// System.out.println(prefix + ": " + StringUtils.splice(list, ", "));
// }
private BinaryOperatorNameConverter binaryOperatorNameConverter = null; // not static - grammar-dependent
private static DoubleQuotedStringConverter doubleQuotedStringConverter = null;
private static EscapedIDConverter escapedIDConverter = null;
private IDConverter idConverter = null; // not static - grammar-dependent
private static MultiLineSingleQuotedStringConverter multiLineSingleQuotedStringConverter = null;
private NameConverter nameConverter = null; // not static - grammar-dependent
private static NumberConverter numberConverter = null;
private static SimpleIDConverter simpleIDConverter = null;
private static SingleQuotedStringConverter singleQuotedStringConverter = null;
private static UnquotedStringConverter unquotedStringConverter = null;
private UnreservedNameConverter unreservedNameConverter = null; // not static - grammar-dependent
private UnrestrictedNameConverter unrestrictedNameConverter = null; // not static - grammar-dependent
private static UpperConverter upperConverter = null;
private static SingleQuotedStringConverter uriConverter = null;
@ValueConverter(rule = "BinaryOperatorName")
public IValueConverter<String> BinaryOperatorName() {
if (binaryOperatorNameConverter == null) {
binaryOperatorNameConverter = new BinaryOperatorNameConverter(getGrammar());
}
return binaryOperatorNameConverter;
}
@ValueConverter(rule = "DOUBLE_QUOTED_STRING")
public IValueConverter<String> DOUBLE_QUOTED_STRING() {
if (doubleQuotedStringConverter == null) {
doubleQuotedStringConverter = new DoubleQuotedStringConverter();
}
return doubleQuotedStringConverter;
}
@ValueConverter(rule = "ESCAPED_ID")
public IValueConverter<String> ESCAPED_ID() {
if (escapedIDConverter == null) {
escapedIDConverter = new EscapedIDConverter();
}
return escapedIDConverter;
}
@ValueConverter(rule = "ID")
public IValueConverter<String> ID() {
if (idConverter == null) {
idConverter = new IDConverter(getGrammar());
}
return idConverter;
}
@ValueConverter(rule = "Identifier")
public IValueConverter<String> Identifier() {
return ID();
}
@ValueConverter(rule = "ML_SINGLE_QUOTED_STRING")
public IValueConverter<String> ML_SINGLE_QUOTED_STRING() {
if (multiLineSingleQuotedStringConverter == null) {
multiLineSingleQuotedStringConverter = new MultiLineSingleQuotedStringConverter();
}
return multiLineSingleQuotedStringConverter;
}
@ValueConverter(rule = "Name")
public IValueConverter<String> Name() {
// return ID();
if (nameConverter == null) {
nameConverter = new NameConverter(getGrammar());
}
return nameConverter;
}
@ValueConverter(rule = "NUMBER_LITERAL")
public IValueConverter<Number> NUMBER_LITERAL() {
if (numberConverter == null) {
numberConverter = new NumberConverter();
}
return numberConverter;
}
@ValueConverter(rule = "SIMPLE_ID")
public IValueConverter<String> SIMPLE_ID() {
if (simpleIDConverter == null) {
simpleIDConverter = new SimpleIDConverter();
}
return simpleIDConverter;
}
@ValueConverter(rule = "SINGLE_QUOTED_STRING")
public IValueConverter<String> SINGLE_QUOTED_STRING() {
if (singleQuotedStringConverter == null) {
singleQuotedStringConverter = new SingleQuotedStringConverter();
}
return singleQuotedStringConverter;
}
@ValueConverter(rule = "StringLiteral")
public IValueConverter<String> StringLiteral() {
return SINGLE_QUOTED_STRING();
}
@ValueConverter(rule = "UNQUOTED_STRING")
public IValueConverter<String> UNQUOTED_STRING() {
if (unquotedStringConverter == null) {
unquotedStringConverter = new UnquotedStringConverter();
}
return unquotedStringConverter;
}
@ValueConverter(rule = "URI")
public IValueConverter<String> URI() {
if (uriConverter == null) {
uriConverter = new SingleQuotedStringConverter();
}
return uriConverter;
}
@ValueConverter(rule = "UnreservedName")
public IValueConverter<String> UnreservedName() {
if (unreservedNameConverter == null) {
unreservedNameConverter = new UnreservedNameConverter(getGrammar());
}
return unreservedNameConverter;
}
@ValueConverter(rule = "UnrestrictedName")
public IValueConverter<String> UnrestrictedName() {
if (unrestrictedNameConverter == null) {
unrestrictedNameConverter = new UnrestrictedNameConverter(getGrammar());
}
return unrestrictedNameConverter;
}
@ValueConverter(rule = "UPPER")
public IValueConverter<Integer> UPPER() {
if (upperConverter == null) {
upperConverter = new UpperConverter();
}
return upperConverter;
}
}