mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-15 16:28:56 +00:00
Base the STRINGValueConverter on the reusable new JavaStringConverter
This commit is contained in:
parent
09ee0502c4
commit
fa00a330ac
2 changed files with 162 additions and 169 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue