mirror of
https://github.com/plexusorg/toml4j.git
synced 2024-12-28 19:24:15 +00:00
Streamlined array and inline table converters to re-use other converters
[ci skip]
This commit is contained in:
parent
ddb061b9f9
commit
d1d7145a03
11 changed files with 263 additions and 206 deletions
|
@ -19,7 +19,7 @@ class ArrayConverter implements ValueConverter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object convert(String s) {
|
public Object convert(String s) {
|
||||||
AtomicInteger sharedIndex = new AtomicInteger(1);
|
AtomicInteger sharedIndex = new AtomicInteger();
|
||||||
Object converted = convert(s, sharedIndex);
|
Object converted = convert(s, sharedIndex);
|
||||||
|
|
||||||
char[] chars = s.toCharArray();
|
char[] chars = s.toCharArray();
|
||||||
|
@ -39,119 +39,56 @@ class ArrayConverter implements ValueConverter {
|
||||||
return converted;
|
return converted;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object convert(String s, AtomicInteger sharedIndex) {
|
@Override
|
||||||
|
public Object convert(String s, AtomicInteger index) {
|
||||||
char[] chars = s.toCharArray();
|
char[] chars = s.toCharArray();
|
||||||
List<Object> arrayItems = new ArrayList<Object>();
|
List<Object> arrayItems = new ArrayList<Object>();
|
||||||
boolean terminated = false;
|
boolean terminated = false;
|
||||||
StringType stringType = StringType.NONE;
|
|
||||||
StringBuilder current = new StringBuilder();
|
|
||||||
|
|
||||||
for (; sharedIndex.get() < chars.length; sharedIndex.incrementAndGet()) {
|
for (int i = index.incrementAndGet(); i < chars.length; i = index.incrementAndGet()) {
|
||||||
int i = sharedIndex.get();
|
|
||||||
char c = chars[sharedIndex.get()];
|
|
||||||
|
|
||||||
if (stringType == StringType.NONE) {
|
char c = chars[i];
|
||||||
if (c == ',') {
|
|
||||||
if (current.toString().trim().length() > 0) {
|
|
||||||
arrayItems.add(current.toString());
|
|
||||||
}
|
|
||||||
current = new StringBuilder();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '[') {
|
if (Character.isWhitespace(c)) {
|
||||||
sharedIndex.incrementAndGet();
|
continue;
|
||||||
arrayItems.add(convert(s, sharedIndex));
|
}
|
||||||
continue;
|
if (c == ',') {
|
||||||
}
|
continue;
|
||||||
|
|
||||||
if (c == ']') {
|
|
||||||
terminated = true;
|
|
||||||
if (current.toString().trim().length() > 0) {
|
|
||||||
arrayItems.add(current.toString());
|
|
||||||
}
|
|
||||||
current = new StringBuilder();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c == '"' && chars[i - 1] != '\\' && !stringType.accepts(c)) {
|
if (c == '[') {
|
||||||
if (chars.length > i + 2 && chars[i + 1] == c && chars[i + 2] == c) {
|
arrayItems.add(convert(s, index));
|
||||||
stringType = stringType.flip(StringType.MULTILINE);
|
continue;
|
||||||
} else {
|
|
||||||
stringType = stringType.flip(StringType.BASIC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '\'' && !stringType.accepts(c)) {
|
|
||||||
if (chars.length > i + 2 && chars[i + 1] == c && chars[i + 2] == c) {
|
|
||||||
stringType = stringType.flip(StringType.MULTILINE_LITERAL);
|
|
||||||
} else {
|
|
||||||
stringType = stringType.flip(StringType.LITERAL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
current.append(c);
|
if (c == ']') {
|
||||||
|
terminated = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
arrayItems.add(VALUE_CONVERTERS.convert(s, index));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!terminated) {
|
if (!terminated) {
|
||||||
return INVALID;
|
return INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
return convertList(arrayItems);
|
for (Object arrayItem : arrayItems) {
|
||||||
}
|
if (arrayItem == INVALID) {
|
||||||
|
return INVALID;
|
||||||
private Object convertList(List<Object> tokens) {
|
}
|
||||||
ArrayList<Object> nestedList = new ArrayList<Object>();
|
|
||||||
|
if (!isHomogenousArray(arrayItem, arrayItems)) {
|
||||||
for (Object token : tokens) {
|
return INVALID;
|
||||||
if (token instanceof String) {
|
|
||||||
Object converted = VALUE_CONVERTERS.convert(((String) token).trim());
|
|
||||||
if (converted == INVALID) {
|
|
||||||
return INVALID;
|
|
||||||
}
|
|
||||||
if (isHomogenousArray(converted, nestedList)) {
|
|
||||||
nestedList.add(converted);
|
|
||||||
} else {
|
|
||||||
return INVALID;
|
|
||||||
}
|
|
||||||
} else if (token instanceof List) {
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
List<Object> convertedList = (List<Object>) token;
|
|
||||||
if (isHomogenousArray(convertedList, nestedList)) {
|
|
||||||
nestedList.add(convertedList);
|
|
||||||
} else {
|
|
||||||
return INVALID;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nestedList;
|
return arrayItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isHomogenousArray(Object o, List<?> values) {
|
private boolean isHomogenousArray(Object o, List<?> values) {
|
||||||
return values.isEmpty() || values.get(0).getClass().isAssignableFrom(o.getClass()) || o.getClass().isAssignableFrom(values.get(0).getClass());
|
return values.isEmpty() || values.get(0).getClass().isAssignableFrom(o.getClass()) || o.getClass().isAssignableFrom(values.get(0).getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static enum StringType {
|
|
||||||
NONE, BASIC, LITERAL, MULTILINE, MULTILINE_LITERAL;
|
|
||||||
|
|
||||||
StringType flip(StringType to) {
|
|
||||||
return this == NONE ? to : NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean accepts(char c) {
|
|
||||||
if (this == BASIC || this == MULTILINE) {
|
|
||||||
return c != '"';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this == LITERAL || this == MULTILINE_LITERAL) {
|
|
||||||
return c != '\'';
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ArrayConverter() {}
|
private ArrayConverter() {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package com.moandjiezana.toml;
|
package com.moandjiezana.toml;
|
||||||
|
|
||||||
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
|
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
|
||||||
|
import static com.moandjiezana.toml.ValueConverterUtils.isComment;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
|
||||||
class BooleanConverter implements ValueConverter {
|
class BooleanConverter implements ValueConverter {
|
||||||
|
@ -14,13 +17,24 @@ class BooleanConverter implements ValueConverter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object convert(String s) {
|
public Object convert(String s) {
|
||||||
|
AtomicInteger index = new AtomicInteger();
|
||||||
|
Object converted = convert(s, index);
|
||||||
|
|
||||||
|
if (!isComment(s.substring(index.incrementAndGet()))) {
|
||||||
|
return INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return converted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object convert(String s, AtomicInteger index) {
|
||||||
|
s = s.substring(index.get());
|
||||||
Boolean b = s.startsWith("true") ? Boolean.TRUE : Boolean.FALSE;
|
Boolean b = s.startsWith("true") ? Boolean.TRUE : Boolean.FALSE;
|
||||||
|
|
||||||
int endIndex = b == Boolean.TRUE ? 4 : 5;
|
int endIndex = b == Boolean.TRUE ? 4 : 5;
|
||||||
|
|
||||||
if (!ValueConverterUtils.isComment(s.substring(endIndex))) {
|
index.addAndGet(endIndex - 1);
|
||||||
return INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package com.moandjiezana.toml;
|
package com.moandjiezana.toml;
|
||||||
|
|
||||||
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
|
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
|
||||||
|
import static com.moandjiezana.toml.ValueConverterUtils.isComment;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@ -15,13 +17,18 @@ class DateConverter implements ValueConverter {
|
||||||
public boolean canConvert(String s) {
|
public boolean canConvert(String s) {
|
||||||
Matcher matcher = DATE_REGEX.matcher(s);
|
Matcher matcher = DATE_REGEX.matcher(s);
|
||||||
|
|
||||||
return matcher.matches() && ValueConverterUtils.isComment(matcher.group(4));
|
return matcher.matches();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object convert(String s) {
|
public Object convert(String s) {
|
||||||
Matcher matcher = DATE_REGEX.matcher(s);
|
Matcher matcher = DATE_REGEX.matcher(s);
|
||||||
matcher.matches();
|
matcher.matches();
|
||||||
|
|
||||||
|
if (!isComment(matcher.group(4))) {
|
||||||
|
return INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
s = matcher.group(1);
|
s = matcher.group(1);
|
||||||
String zone = matcher.group(3);
|
String zone = matcher.group(3);
|
||||||
String fractionalSeconds = matcher.group(2);
|
String fractionalSeconds = matcher.group(2);
|
||||||
|
@ -36,6 +43,7 @@ class DateConverter implements ValueConverter {
|
||||||
} else if (zone.contains(":")) {
|
} else if (zone.contains(":")) {
|
||||||
s += zone.replace(":", "");
|
s += zone.replace(":", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
|
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
|
||||||
dateFormat.setLenient(false);
|
dateFormat.setLenient(false);
|
||||||
|
@ -44,6 +52,37 @@ class DateConverter implements ValueConverter {
|
||||||
return INVALID;
|
return INVALID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object convert(String original, AtomicInteger index) {
|
||||||
|
String s = original.substring(index.get());
|
||||||
|
Matcher matcher = DATE_REGEX.matcher(s);
|
||||||
|
matcher.matches();
|
||||||
|
String dateString = matcher.group(1);
|
||||||
|
String zone = matcher.group(3);
|
||||||
|
String fractionalSeconds = matcher.group(2);
|
||||||
|
String format = "yyyy-MM-dd'T'HH:mm:ss";
|
||||||
|
if (fractionalSeconds != null && !fractionalSeconds.isEmpty()) {
|
||||||
|
format += ".SSS";
|
||||||
|
dateString += fractionalSeconds;
|
||||||
|
}
|
||||||
|
format += "Z";
|
||||||
|
if ("Z".equals(zone)) {
|
||||||
|
dateString += "+0000";
|
||||||
|
} else if (zone.contains(":")) {
|
||||||
|
dateString += zone.replace(":", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
index.addAndGet(matcher.end(3) - 1);
|
||||||
|
|
||||||
|
try {
|
||||||
|
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
|
||||||
|
dateFormat.setLenient(false);
|
||||||
|
return dateFormat.parse(dateString);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private DateConverter() {}
|
private DateConverter() {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,55 +17,45 @@ class InlineTableConverter implements ValueConverter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object convert(String s) {
|
public Object convert(String s) {
|
||||||
AtomicInteger sharedIndex = new AtomicInteger(1);
|
AtomicInteger index = new AtomicInteger();
|
||||||
Object converted = convert(s, sharedIndex);
|
Object converted = convert(s, index);
|
||||||
char[] chars = s.toCharArray();
|
|
||||||
|
|
||||||
for (; sharedIndex.get() < s.length(); sharedIndex.incrementAndGet()) {
|
String substring = s.substring(index.incrementAndGet());
|
||||||
char c = chars[sharedIndex.get()];
|
if (converted == INVALID || !ValueConverterUtils.isComment(substring)) {
|
||||||
if (Character.isWhitespace(c)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '#') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return INVALID;
|
return INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
return converted;
|
return converted;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object convert(String s, AtomicInteger sharedIndex) {
|
@Override
|
||||||
|
public Object convert(String s, AtomicInteger sharedIndex) {
|
||||||
char[] chars = s.toCharArray();
|
char[] chars = s.toCharArray();
|
||||||
boolean inKey = true;
|
boolean inKey = true;
|
||||||
boolean inValue = false;
|
boolean inValue = false;
|
||||||
boolean quoted = false;
|
boolean quoted = false;
|
||||||
boolean terminated = false;
|
boolean terminated = false;
|
||||||
StringBuilder currentKey = new StringBuilder();
|
StringBuilder currentKey = new StringBuilder();
|
||||||
StringBuilder current = new StringBuilder();
|
|
||||||
HashMap<String, Object> results = new HashMap<String, Object>();
|
HashMap<String, Object> results = new HashMap<String, Object>();
|
||||||
|
|
||||||
for (; sharedIndex.get() < chars.length; sharedIndex.incrementAndGet()) {
|
for (int i = sharedIndex.incrementAndGet(); sharedIndex.get() < chars.length; i = sharedIndex.incrementAndGet()) {
|
||||||
int i = sharedIndex.get();
|
|
||||||
char c = chars[i];
|
char c = chars[i];
|
||||||
|
|
||||||
if (c == '"') {
|
if (c == '"' && inKey) {
|
||||||
quoted = !quoted;
|
quoted = !quoted;
|
||||||
(inValue ? current : currentKey).append(c);
|
currentKey.append(c);
|
||||||
} else if (quoted) {
|
} else if (quoted) {
|
||||||
(inKey ? currentKey : current).append(c);
|
currentKey.append(c);
|
||||||
} else if (c == '[' && inValue) {
|
} else if (inValue && !Character.isWhitespace(c)) {
|
||||||
sharedIndex.incrementAndGet();
|
Object converted = CONVERTERS.convert(s, sharedIndex);
|
||||||
Object converted = ArrayConverter.ARRAY_PARSER.convert(s, sharedIndex);
|
|
||||||
|
|
||||||
if (converted == INVALID) {
|
if (converted == INVALID) {
|
||||||
return INVALID;
|
return INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
results.put(currentKey.toString().trim(), converted);
|
results.put(currentKey.toString().trim(), converted);
|
||||||
i = sharedIndex.get();
|
currentKey = new StringBuilder();
|
||||||
continue;
|
inValue = false;
|
||||||
} else if (c == '{') {
|
} else if (c == '{') {
|
||||||
sharedIndex.incrementAndGet();
|
sharedIndex.incrementAndGet();
|
||||||
Object converted = convert(s, sharedIndex);
|
Object converted = convert(s, sharedIndex);
|
||||||
|
@ -79,43 +69,18 @@ class InlineTableConverter implements ValueConverter {
|
||||||
inKey = true;
|
inKey = true;
|
||||||
inValue = false;
|
inValue = false;
|
||||||
currentKey = new StringBuilder();
|
currentKey = new StringBuilder();
|
||||||
current = new StringBuilder();
|
|
||||||
} else if (c == ',') {
|
} else if (c == ',') {
|
||||||
if (!current.toString().trim().isEmpty()) {
|
|
||||||
Object converted = CONVERTERS.convert(current.toString().trim());
|
|
||||||
|
|
||||||
if (converted == INVALID) {
|
|
||||||
return INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
results.put(currentKey.toString().trim(), converted);
|
|
||||||
}
|
|
||||||
|
|
||||||
inKey = true;
|
inKey = true;
|
||||||
inValue = false;
|
inValue = false;
|
||||||
currentKey = new StringBuilder();
|
currentKey = new StringBuilder();
|
||||||
current = new StringBuilder();
|
|
||||||
} else if (c == '=') {
|
} else if (c == '=') {
|
||||||
inKey = false;
|
inKey = false;
|
||||||
inValue = true;
|
inValue = true;
|
||||||
} else if (c == '}') {
|
} else if (c == '}') {
|
||||||
terminated = true;
|
terminated = true;
|
||||||
|
|
||||||
String trimmed = current.toString().trim();
|
|
||||||
if (!trimmed.isEmpty()) {
|
|
||||||
Object converted = CONVERTERS.convert(trimmed);
|
|
||||||
|
|
||||||
if (converted == INVALID) {
|
|
||||||
return INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
results.put(currentKey.toString().trim(), converted);
|
|
||||||
}
|
|
||||||
|
|
||||||
sharedIndex.incrementAndGet();
|
|
||||||
break;
|
break;
|
||||||
} else {
|
} else if (inKey) {
|
||||||
(inKey ? currentKey : current).append(c);
|
currentKey.append(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package com.moandjiezana.toml;
|
package com.moandjiezana.toml;
|
||||||
|
|
||||||
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
|
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
|
||||||
|
import static com.moandjiezana.toml.ValueConverterUtils.isComment;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
|
||||||
class LiteralStringConverter implements ValueConverter {
|
class LiteralStringConverter implements ValueConverter {
|
||||||
|
@ -14,31 +17,38 @@ class LiteralStringConverter implements ValueConverter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object convert(String s) {
|
public Object convert(String s) {
|
||||||
char[] chars = s.toCharArray();
|
AtomicInteger index = new AtomicInteger();
|
||||||
int endIndex = -1;
|
Object converted = convert(s, index);
|
||||||
|
|
||||||
for (int i = 1; i < chars.length; i++) {
|
if (converted == INVALID || !isComment(s.substring(index.incrementAndGet()))) {
|
||||||
char c = chars[i];
|
|
||||||
|
|
||||||
if (c == '\'') {
|
|
||||||
endIndex = i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (endIndex > -1 && c == '#') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (endIndex > -1 && !Character.isWhitespace(c)) {
|
|
||||||
return INVALID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (endIndex == -1) {
|
|
||||||
return INVALID;
|
return INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.substring(1, endIndex);
|
return converted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object convert(String s, AtomicInteger index) {
|
||||||
|
char[] chars = s.toCharArray();
|
||||||
|
boolean terminated = false;
|
||||||
|
int startIndex = index.incrementAndGet();
|
||||||
|
|
||||||
|
for (int i = index.get(); i < chars.length; i = index.incrementAndGet()) {
|
||||||
|
char c = chars[i];
|
||||||
|
|
||||||
|
if (c == '\'') {
|
||||||
|
terminated = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!terminated) {
|
||||||
|
return INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
String substring = s.substring(startIndex, index.get());
|
||||||
|
|
||||||
|
return substring;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LiteralStringConverter() {}
|
private LiteralStringConverter() {}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package com.moandjiezana.toml;
|
package com.moandjiezana.toml;
|
||||||
|
|
||||||
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
|
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
|
||||||
|
import static com.moandjiezana.toml.ValueConverterUtils.isComment;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
class MultilineLiteralStringConverter implements ValueConverter {
|
class MultilineLiteralStringConverter implements ValueConverter {
|
||||||
|
|
||||||
|
@ -13,28 +16,33 @@ class MultilineLiteralStringConverter implements ValueConverter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object convert(String s) {
|
public Object convert(String s) {
|
||||||
|
AtomicInteger index = new AtomicInteger();
|
||||||
|
Object converted = convert(s, index);
|
||||||
|
|
||||||
|
if (converted == INVALID || !isComment(s.substring(index.incrementAndGet()))) {
|
||||||
|
return INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return converted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object convert(String s, AtomicInteger index) {
|
||||||
char[] chars = s.toCharArray();
|
char[] chars = s.toCharArray();
|
||||||
|
int startIndex = index.addAndGet(3);
|
||||||
int endIndex = -1;
|
int endIndex = -1;
|
||||||
|
|
||||||
for (int i = 3; i < chars.length; i++) {
|
for (int i = startIndex; i < chars.length; i = index.incrementAndGet()) {
|
||||||
char c = chars[i];
|
char c = chars[i];
|
||||||
|
|
||||||
if (c == '\'' && chars.length > i + 2 && chars[i + 1] == '\'' && chars[i + 2] == '\'') {
|
if (c == '\'' && chars.length > i + 2 && chars[i + 1] == '\'' && chars[i + 2] == '\'') {
|
||||||
endIndex = i;
|
endIndex = i;
|
||||||
i += 2;
|
index.addAndGet(2);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (endIndex > -1 && c == '#') {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endIndex > -1 && !Character.isWhitespace(c)) {
|
|
||||||
return INVALID;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.substring(3, endIndex);
|
return s.substring(startIndex, endIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MultilineLiteralStringConverter() {}
|
private MultilineLiteralStringConverter() {}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
package com.moandjiezana.toml;
|
package com.moandjiezana.toml;
|
||||||
|
|
||||||
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
|
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
|
||||||
|
import static com.moandjiezana.toml.ValueConverterUtils.isComment;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
class MultilineStringConverter implements ValueConverter {
|
class MultilineStringConverter implements ValueConverter {
|
||||||
|
|
||||||
static final MultilineStringConverter MULTILINE_STRING_PARSER = new MultilineStringConverter();
|
static final MultilineStringConverter MULTILINE_STRING_PARSER = new MultilineStringConverter();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -13,22 +16,45 @@ class MultilineStringConverter implements ValueConverter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object convert(String s) {
|
public Object convert(String s) {
|
||||||
int terminator = s.indexOf("\"\"\"", 3);
|
AtomicInteger index = new AtomicInteger();
|
||||||
|
Object converted = convert(s, index);
|
||||||
if (terminator == -1) {
|
|
||||||
|
if (converted == INVALID || !isComment(s.substring(index.incrementAndGet()))) {
|
||||||
return INVALID;
|
return INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ValueConverterUtils.isComment(s.substring(terminator + 3))) {
|
return converted;
|
||||||
return INVALID;
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
s = s.substring(2, terminator + 1);
|
public Object convert(String s, AtomicInteger index) {
|
||||||
s = s.replaceAll("\\\\\\s+", "");
|
char[] chars = s.toCharArray();
|
||||||
|
int startIndex = index.addAndGet(3);
|
||||||
return StringConverter.STRING_PARSER.convert(s);
|
int endIndex = -1;
|
||||||
|
|
||||||
|
for (int i = startIndex; i < chars.length; i = index.incrementAndGet()) {
|
||||||
|
char c = chars[i];
|
||||||
|
|
||||||
|
if (c == '"' && chars.length > i + 2 && chars[i + 1] == '"' && chars[i + 2] == '"') {
|
||||||
|
endIndex = i;
|
||||||
|
index.addAndGet(2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endIndex == -1) {
|
||||||
|
return INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = s.substring(startIndex, endIndex);
|
||||||
|
s = s.replaceAll("\\\\\\s+", "");
|
||||||
|
s = StringConverter.STRING_PARSER.replaceUnicodeCharacters(s);
|
||||||
|
s = StringConverter.STRING_PARSER.replaceSpecialCharacters(s);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MultilineStringConverter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private MultilineStringConverter() {}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package com.moandjiezana.toml;
|
package com.moandjiezana.toml;
|
||||||
|
|
||||||
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
|
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
|
||||||
|
import static com.moandjiezana.toml.ValueConverterUtils.isComment;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
class NumberConverter implements ValueConverter {
|
class NumberConverter implements ValueConverter {
|
||||||
static final NumberConverter NUMBER_PARSER = new NumberConverter();
|
static final NumberConverter NUMBER_PARSER = new NumberConverter();
|
||||||
|
@ -14,20 +17,33 @@ class NumberConverter implements ValueConverter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object convert(String s) {
|
public Object convert(String s) {
|
||||||
|
AtomicInteger index = new AtomicInteger();
|
||||||
|
Object converted = convert(s, index);
|
||||||
|
|
||||||
|
if (converted == INVALID || (s.length() > index.get() + 1 && !isComment(s.substring(index.incrementAndGet())))) {
|
||||||
|
return INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return converted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object convert(String s, AtomicInteger index) {
|
||||||
char[] chars = s.toCharArray();
|
char[] chars = s.toCharArray();
|
||||||
boolean whitespace = false;
|
|
||||||
boolean signable = true;
|
boolean signable = true;
|
||||||
boolean dottable = false;
|
boolean dottable = false;
|
||||||
boolean exponentable = false;
|
boolean exponentable = false;
|
||||||
|
boolean terminatable = false;
|
||||||
String type = "";
|
String type = "";
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
for (int i = 0; i < chars.length; i++) {
|
for (int i = index.get(); i < chars.length; i = index.incrementAndGet()) {
|
||||||
char c = chars[i];
|
char c = chars[i];
|
||||||
|
|
||||||
if (Character.isDigit(c)) {
|
if (Character.isDigit(c)) {
|
||||||
sb.append(c);
|
sb.append(c);
|
||||||
signable = false;
|
signable = false;
|
||||||
|
terminatable = true;
|
||||||
if (type.isEmpty()) {
|
if (type.isEmpty()) {
|
||||||
type = "integer";
|
type = "integer";
|
||||||
dottable = true;
|
dottable = true;
|
||||||
|
@ -35,26 +51,28 @@ class NumberConverter implements ValueConverter {
|
||||||
exponentable = !type.equals("exponent");
|
exponentable = !type.equals("exponent");
|
||||||
} else if ((c == '+' || c == '-') && signable && chars.length > i + 1) {
|
} else if ((c == '+' || c == '-') && signable && chars.length > i + 1) {
|
||||||
signable = false;
|
signable = false;
|
||||||
|
terminatable = false;
|
||||||
if (c == '-') {
|
if (c == '-') {
|
||||||
sb.append('-');
|
sb.append('-');
|
||||||
}
|
}
|
||||||
} else if (c == '.' && dottable && chars.length > i + 1) {
|
} else if (c == '.' && dottable && chars.length > i + 1) {
|
||||||
sb.append('.');
|
sb.append('.');
|
||||||
type = "float";
|
type = "float";
|
||||||
|
terminatable = false;
|
||||||
dottable = false;
|
dottable = false;
|
||||||
exponentable = false;
|
exponentable = false;
|
||||||
} else if ((c == 'E' || c == 'e') && exponentable && chars.length > i + 1) {
|
} else if ((c == 'E' || c == 'e') && exponentable && chars.length > i + 1) {
|
||||||
sb.append('E');
|
sb.append('E');
|
||||||
type = "exponent";
|
type = "exponent";
|
||||||
|
terminatable = false;
|
||||||
signable = true;
|
signable = true;
|
||||||
dottable = false;
|
dottable = false;
|
||||||
exponentable = false;
|
exponentable = false;
|
||||||
} else if (Character.isWhitespace(c)) {
|
|
||||||
whitespace = true;
|
|
||||||
} else if (whitespace && c == '#') {
|
|
||||||
break;
|
|
||||||
} else {
|
} else {
|
||||||
type = "";
|
if (!terminatable) {
|
||||||
|
type = "";
|
||||||
|
}
|
||||||
|
index.decrementAndGet();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.moandjiezana.toml;
|
||||||
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
|
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
|
||||||
import static com.moandjiezana.toml.ValueConverterUtils.isComment;
|
import static com.moandjiezana.toml.ValueConverterUtils.isComment;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@ -18,22 +19,35 @@ class StringConverter implements ValueConverter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object convert(String value) {
|
public Object convert(String value) {
|
||||||
int stringTerminator = -1;
|
AtomicInteger index = new AtomicInteger();
|
||||||
|
Object converted = convert(value, index);
|
||||||
|
|
||||||
|
if (converted == INVALID || !isComment(value.substring(index.incrementAndGet()))) {
|
||||||
|
return INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return converted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object convert(String value, AtomicInteger sharedIndex) {
|
||||||
|
int startIndex = sharedIndex.incrementAndGet();
|
||||||
|
int endIndex = -1;
|
||||||
char[] chars = value.toCharArray();
|
char[] chars = value.toCharArray();
|
||||||
|
|
||||||
for (int i = 1; i < chars.length; i++) {
|
for (int i = sharedIndex.get(); i < chars.length; i = sharedIndex.incrementAndGet()) {
|
||||||
char ch = chars[i];
|
char ch = chars[i];
|
||||||
if (ch == '"' && chars[i - 1] != '\\') {
|
if (ch == '"' && chars[i - 1] != '\\') {
|
||||||
stringTerminator = i;
|
endIndex = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stringTerminator == -1 || !isComment(value.substring(stringTerminator + 1))) {
|
if (endIndex == -1) {
|
||||||
return INVALID;
|
return INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
value = value.substring(1, stringTerminator);
|
value = value.substring(startIndex, endIndex);
|
||||||
value = replaceUnicodeCharacters(value);
|
value = replaceUnicodeCharacters(value);
|
||||||
value = replaceSpecialCharacters(value);
|
value = replaceSpecialCharacters(value);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package com.moandjiezana.toml;
|
package com.moandjiezana.toml;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
interface ValueConverter {
|
interface ValueConverter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,6 +11,16 @@ interface ValueConverter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param s must already have been validated by {@link #canConvert(String)}
|
* @param s must already have been validated by {@link #canConvert(String)}
|
||||||
|
* @return a value or {@link ValueConverterUtils#INVALID}
|
||||||
*/
|
*/
|
||||||
Object convert(String s);
|
Object convert(String s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Partial validation. Stops after type terminator, rather than at EOI.
|
||||||
|
*
|
||||||
|
* @param s must already have been validated by {@link #canConvert(String)}
|
||||||
|
* @param index where to start in s
|
||||||
|
* @return a value or {@link ValueConverterUtils#INVALID}
|
||||||
|
*/
|
||||||
|
Object convert(String s, AtomicInteger index);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,13 +11,15 @@ import static com.moandjiezana.toml.NumberConverter.NUMBER_PARSER;
|
||||||
import static com.moandjiezana.toml.StringConverter.STRING_PARSER;
|
import static com.moandjiezana.toml.StringConverter.STRING_PARSER;
|
||||||
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
|
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
class ValueConverters {
|
class ValueConverters {
|
||||||
|
|
||||||
private static final ValueConverter[] PARSERS = {
|
private static final ValueConverter[] PARSERS = {
|
||||||
MULTILINE_STRING_PARSER, MULTILINE_LITERAL_STRING_CONVERTER, LITERAL_STRING_PARSER, STRING_PARSER, DATE_PARSER, NUMBER_PARSER, BOOLEAN_PARSER, ARRAY_PARSER, INLINE_TABLE_PARSER
|
MULTILINE_STRING_PARSER, MULTILINE_LITERAL_STRING_CONVERTER, LITERAL_STRING_PARSER, STRING_PARSER, DATE_PARSER, NUMBER_PARSER, BOOLEAN_PARSER, ARRAY_PARSER, INLINE_TABLE_PARSER
|
||||||
};
|
};
|
||||||
|
|
||||||
public Object convert(String value) {
|
Object convert(String value) {
|
||||||
for (ValueConverter valueParser : PARSERS) {
|
for (ValueConverter valueParser : PARSERS) {
|
||||||
if (valueParser.canConvert(value)) {
|
if (valueParser.canConvert(value)) {
|
||||||
return valueParser.convert(value);
|
return valueParser.convert(value);
|
||||||
|
@ -26,4 +28,16 @@ class ValueConverters {
|
||||||
|
|
||||||
return INVALID;
|
return INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Object convert(String value, AtomicInteger index) {
|
||||||
|
String substring = value.substring(index.get());
|
||||||
|
for (ValueConverter valueParser : PARSERS) {
|
||||||
|
if (valueParser.canConvert(substring)) {
|
||||||
|
return valueParser.convert(value, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return INVALID;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue