Base the STRINGValueConverter on the reusable new JavaStringConverter

This commit is contained in:
Sebastian Zarnekow 2018-10-31 18:55:46 +01:00
parent 09ee0502c4
commit fa00a330ac
2 changed files with 162 additions and 169 deletions

View file

@ -193,4 +193,62 @@ public class JavaStringConverter {
public char toHex(int i) {
return "0123456789ABCDEF".charAt(i & 0xF);
}
protected boolean isHexSequence(String in, int off, int chars) {
return doIsHexSequence(in, off, chars);
}
public static boolean doIsHexSequence(String in, int off, int chars) {
for (int i = off; i < in.length() && i < off + chars; i++) {
char c = in.charAt(i);
if (!isHex(c)) {
return false;
}
}
return true;
}
protected boolean isHexSequence(char[] in, int off, int chars) {
return doIsHexSequence(in, off, chars);
}
public static boolean doIsHexSequence(char[] in, int off, int chars) {
for (int i = off; i < in.length && i < off + chars; i++) {
char c = in[i];
if (!isHex(c)) {
return false;
}
}
return true;
}
protected static boolean isHex(char c) {
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
return true;
default:
return false;
}
}
}

View file

@ -10,6 +10,7 @@ package org.eclipse.xtext.conversion.impl;
import org.eclipse.xtext.conversion.ValueConverterException;
import org.eclipse.xtext.conversion.ValueConverterWithValueException;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.util.JavaStringConverter;
import org.eclipse.xtext.util.Strings;
/**
@ -46,43 +47,116 @@ public class STRINGValueConverter extends AbstractLexerBasedConverter<String> {
* @see Strings#convertFromJavaString(String, boolean)
*/
protected String convertFromString(String literal, INode node) throws ValueConverterWithValueException {
int length = literal.length();
StringBuilder result = new StringBuilder(length);
ErrorInfo errorInfo = new ErrorInfo();
Implementation converter = createConverter();
String result = converter.convertFromJavaString(literal);
if (converter.errorMessage != null) {
throw new ValueConverterWithValueException(converter.errorMessage, node, result.toString(), converter.errorIndex,
converter.errorLength, null);
}
return result;
}
/**
* @since 2.16
*/
protected Implementation createConverter() {
return new Implementation();
}
/**
* @since 2.16
*/
protected class Implementation extends JavaStringConverter {
String errorMessage = null;
int errorIndex = -1;
int errorLength = -1;
int nextIndex = 1;
while(nextIndex < length - 1) {
nextIndex = unescapeCharAndAppendTo(literal, nextIndex, result, errorInfo);
public String convertFromJavaString(String literal) {
int idx = literal.indexOf('\\');
if (idx < 0 && literal.length() > 1 && literal.charAt(0) == literal.charAt(literal.length() - 1)) {
return literal.substring(1, literal.length() - 1);
}
return convertFromJavaString(literal, true, 1, new StringBuilder(literal.length()));
}
if (nextIndex < length) {
if (nextIndex != length - 1) {
throw new IllegalStateException();
@Override
protected String convertFromJavaString(String string, boolean useUnicode, int index, StringBuilder result) {
int length = string.length();
while(index < length - 1) {
nextIndex = index = unescapeCharAndAppendTo(string, useUnicode, index, result);
}
char next = literal.charAt(nextIndex);
if (literal.charAt(0) != next) {
result.append(next);
if (errorInfo.errorMessage == null) {
if (next == '\\') {
errorInfo.errorMessage = getInvalidEscapeSequenceMessage();
errorInfo.errorIndex = nextIndex;
errorInfo.errorLength = 1;
} else {
errorInfo.errorMessage = getStringNotClosedMessage();
}
} else {
errorInfo.errorMessage = getStringNotClosedMessage();
errorInfo.errorIndex = -1;
errorInfo.errorLength = -1;
if (nextIndex < length) {
if (nextIndex != length - 1) {
throw new IllegalStateException();
}
char next = string.charAt(nextIndex);
if (string.charAt(0) != next) {
result.append(next);
if (errorMessage == null) {
if (next == '\\') {
errorMessage = getInvalidEscapeSequenceMessage();
errorIndex = nextIndex;
errorLength = 1;
} else {
errorMessage = getStringNotClosedMessage();
}
} else {
errorMessage = getStringNotClosedMessage();
errorIndex = -1;
errorLength = -1;
}
}
} else if (nextIndex == length) {
errorMessage = getStringNotClosedMessage();
}
} else if (nextIndex == length) {
errorInfo.errorMessage = getStringNotClosedMessage();
return result.toString();
}
if (errorInfo.errorMessage != null) {
throw new ValueConverterWithValueException(errorInfo.errorMessage, node, result.toString(), errorInfo.errorIndex,
errorInfo.errorLength, null);
@Override
protected boolean isHexSequence(char[] in, int off, int chars) {
// keep chance to use overridden methods by funneling it through STRINGValueConverter
return STRINGValueConverter.this.isHexSequence(in, off, chars);
}
return result.toString();
@Override
protected boolean isInvalidUnicodeEscapeSequence(String string, int index) {
return super.isInvalidUnicodeEscapeSequence(string, index) || !isHexSequence(string, index, 4);
}
@Override
protected int handleInvalidUnicodeEscapeSequnce(String string, int index, StringBuilder result) {
result.append('u');
errorMessage = "Invalid unicode";
errorIndex = index - 2;
errorLength = 2;
return index;
}
@Override
protected int doUnescapeCharAndAppendTo(String string, boolean useUnicode, int index, StringBuilder result) {
if (string.length() == index) {
if (errorMessage == null) {
errorMessage = getInvalidEscapeSequenceMessage();
errorIndex = index - 1;
errorLength = 1;
}
return index;
}
return super.doUnescapeCharAndAppendTo(string, useUnicode, index, result);
}
@Override
protected int handleUnknownEscapeSequence(String string, char c, boolean useUnicode, int index, StringBuilder result) {
if (errorMessage == null) {
errorMessage = getInvalidEscapeSequenceMessage();
errorIndex = index - 2;
errorLength = 2;
}
result.append(c);
return index;
}
}
/**
@ -99,150 +173,11 @@ public class STRINGValueConverter extends AbstractLexerBasedConverter<String> {
return "String literal is not properly closed";
}
private static class ErrorInfo {
String errorMessage = null;
int errorIndex = -1;
int errorLength = -1;
}
private int unescapeCharAndAppendTo(String string, int index, StringBuilder result, ErrorInfo errorInfo) {
char c = string.charAt(index++);
if (c == '\\') {
index = doUnescapeCharAndAppendTo(string, index, result, errorInfo);
} else {
result.append(c);
}
return index;
}
private int doUnescapeCharAndAppendTo(String string, int index, StringBuilder result, ErrorInfo errorInfo) {
if (string.length() == index) {
if (errorInfo.errorMessage == null) {
errorInfo.errorMessage = getInvalidEscapeSequenceMessage();
errorInfo.errorIndex = index - 1;
errorInfo.errorLength = 1;
}
return index;
}
char c = string.charAt(index++);
switch(c) {
case 'b':
c = '\b';
break;
case 't':
c = '\t';
break;
case 'n':
c = '\n';
break;
case 'f':
c = '\f';
break;
case 'r':
c = '\r';
break;
case '"':
case '\'':
case '\\':
break;
case 'u':
return unescapeUnicodeSequence(string, index, result, errorInfo);
default:
if (errorInfo.errorMessage == null) {
errorInfo.errorMessage = getInvalidEscapeSequenceMessage();
errorInfo.errorIndex = index - 2;
errorInfo.errorLength = 2;
}
}
result.append(c);
return index;
}
private int unescapeUnicodeSequence(String string, int index, StringBuilder result, ErrorInfo errorInfo) {
try {
if (index+4 > string.length() || !isHexSequence(string, index, 4)) {
result.append('u');
errorInfo.errorMessage = "Invalid unicode";
errorInfo.errorIndex = index - 2;
errorInfo.errorLength = 2;
return index;
}
result.append((char) Integer.parseInt(string.substring(index, index + 4), 16));
return index + 4;
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Illegal \\uxxxx encoding in " + string);
}
}
private boolean isHexSequence(String in, int off, int chars) {
for (int i = off; i < in.length() && i < off + chars; i++) {
char c = in.charAt(i);
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
continue;
default:
return false;
}
}
return true;
}
/**
* @since 2.7
*/
protected boolean isHexSequence(char[] in, int off, int chars) {
for (int i = off; i < in.length && i < off + chars; i++) {
char c = in[i];
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
continue;
default:
return false;
}
}
return true;
return Implementation.doIsHexSequence(in, off, chars);
}
}