mirror of
https://github.com/plexusorg/toml4j.git
synced 2025-02-11 11:40:27 +00:00
Simplified TomlParser
This commit is contained in:
parent
d1d7145a03
commit
3e2d9fad37
11 changed files with 263 additions and 225 deletions
|
@ -1,6 +1,7 @@
|
||||||
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.ValueConverters.CONVERTERS;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -10,8 +11,6 @@ class ArrayConverter implements ValueConverter {
|
||||||
|
|
||||||
static final ArrayConverter ARRAY_PARSER = new ArrayConverter();
|
static final ArrayConverter ARRAY_PARSER = new ArrayConverter();
|
||||||
|
|
||||||
private static final ValueConverters VALUE_CONVERTERS = new ValueConverters();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canConvert(String s) {
|
public boolean canConvert(String s) {
|
||||||
return s.startsWith("[");
|
return s.startsWith("[");
|
||||||
|
@ -41,36 +40,35 @@ class ArrayConverter implements ValueConverter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object convert(String s, AtomicInteger index) {
|
public Object convert(String s, AtomicInteger index) {
|
||||||
|
int startIndex = index.get();
|
||||||
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;
|
||||||
|
boolean inComment = false;
|
||||||
|
|
||||||
for (int i = index.incrementAndGet(); i < chars.length; i = index.incrementAndGet()) {
|
for (int i = index.incrementAndGet(); i < chars.length; i = index.incrementAndGet()) {
|
||||||
|
|
||||||
char c = chars[i];
|
char c = chars[i];
|
||||||
|
|
||||||
if (Character.isWhitespace(c)) {
|
if (c == '#' && !inComment) {
|
||||||
|
inComment = true;
|
||||||
|
} else if (c == '\n') {
|
||||||
|
inComment = false;
|
||||||
|
} else if (inComment || Character.isWhitespace(c) || c == ',') {
|
||||||
continue;
|
continue;
|
||||||
}
|
} else if (c == '[') {
|
||||||
if (c == ',') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '[') {
|
|
||||||
arrayItems.add(convert(s, index));
|
arrayItems.add(convert(s, index));
|
||||||
continue;
|
continue;
|
||||||
}
|
} else if (c == ']') {
|
||||||
|
|
||||||
if (c == ']') {
|
|
||||||
terminated = true;
|
terminated = true;
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
arrayItems.add(CONVERTERS.convert(s, index));
|
||||||
}
|
}
|
||||||
|
|
||||||
arrayItems.add(VALUE_CONVERTERS.convert(s, index));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!terminated) {
|
if (!terminated) {
|
||||||
return INVALID;
|
return ValueConverterUtils.unterminated(s.substring(startIndex, s.length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Object arrayItem : arrayItems) {
|
for (Object arrayItem : arrayItems) {
|
||||||
|
|
|
@ -15,9 +15,25 @@ class DateConverter implements ValueConverter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canConvert(String s) {
|
public boolean canConvert(String s) {
|
||||||
Matcher matcher = DATE_REGEX.matcher(s);
|
if (s.length() < 5) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return matcher.matches();
|
char[] chars = s.toCharArray();
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
char c = chars[i];
|
||||||
|
|
||||||
|
if (i < 4) {
|
||||||
|
if (!Character.isDigit(c)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (c != '-') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -55,9 +71,25 @@ class DateConverter implements ValueConverter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object convert(String original, AtomicInteger index) {
|
public Object convert(String original, AtomicInteger index) {
|
||||||
String s = original.substring(index.get());
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
for (int i = index.get(); i < original.length(); i = index.incrementAndGet()) {
|
||||||
|
char c = original.charAt(i);
|
||||||
|
if (Character.isDigit(c) || c == '-' || c == ':' || c == '.' || c == 'T' || c == 'Z') {
|
||||||
|
sb.append(c);
|
||||||
|
} else {
|
||||||
|
index.decrementAndGet();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String s = sb.toString();
|
||||||
Matcher matcher = DATE_REGEX.matcher(s);
|
Matcher matcher = DATE_REGEX.matcher(s);
|
||||||
matcher.matches();
|
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
return INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
String dateString = matcher.group(1);
|
String dateString = matcher.group(1);
|
||||||
String zone = matcher.group(3);
|
String zone = matcher.group(3);
|
||||||
String fractionalSeconds = matcher.group(2);
|
String fractionalSeconds = matcher.group(2);
|
||||||
|
@ -73,8 +105,6 @@ class DateConverter implements ValueConverter {
|
||||||
dateString += zone.replace(":", "");
|
dateString += zone.replace(":", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
index.addAndGet(matcher.end(3) - 1);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
|
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
|
||||||
dateFormat.setLenient(false);
|
dateFormat.setLenient(false);
|
||||||
|
|
60
src/main/java/com/moandjiezana/toml/Identifier.java
Normal file
60
src/main/java/com/moandjiezana/toml/Identifier.java
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
package com.moandjiezana.toml;
|
||||||
|
|
||||||
|
class Identifier {
|
||||||
|
|
||||||
|
static final Identifier INVALID = new Identifier("");
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final Type type;
|
||||||
|
|
||||||
|
Identifier(String name) {
|
||||||
|
this.name = name;
|
||||||
|
if (name.startsWith("[[")) {
|
||||||
|
this.type = Type.TABLE_ARRAY;
|
||||||
|
} else if (name.startsWith("[")) {
|
||||||
|
this.type = Type.TABLE;
|
||||||
|
} else {
|
||||||
|
this.type = Type.KEY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean acceptsNext(char c) {
|
||||||
|
if (isKey()) {
|
||||||
|
return c == '=';
|
||||||
|
}
|
||||||
|
|
||||||
|
return c == '\n' || c == '#';
|
||||||
|
}
|
||||||
|
|
||||||
|
String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isKey() {
|
||||||
|
return type == Type.KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isTable() {
|
||||||
|
return type == Type.TABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isTableArray() {
|
||||||
|
return type == Type.TABLE_ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isValid() {
|
||||||
|
if (isKey()) {
|
||||||
|
return Keys.getKey(name) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTable()) {
|
||||||
|
return Keys.getTableName(name) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Keys.getTableArrayName(name) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static enum Type {
|
||||||
|
KEY, TABLE, TABLE_ARRAY;
|
||||||
|
}
|
||||||
|
}
|
33
src/main/java/com/moandjiezana/toml/IdentifierConverter.java
Normal file
33
src/main/java/com/moandjiezana/toml/IdentifierConverter.java
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package com.moandjiezana.toml;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
class IdentifierConverter {
|
||||||
|
|
||||||
|
static final IdentifierConverter IDENTIFIER_CONVERTER = new IdentifierConverter();
|
||||||
|
|
||||||
|
Identifier convert(char[] chars, AtomicInteger index) {
|
||||||
|
boolean quoted = false;
|
||||||
|
StringBuilder name = new StringBuilder();
|
||||||
|
Identifier identifier = null;
|
||||||
|
|
||||||
|
for (int i = index.get(); i < chars.length; i = index.incrementAndGet()) {
|
||||||
|
char c = chars[i];
|
||||||
|
if (c == '"' && (i == 0 || chars[i - 1] != '\\')) {
|
||||||
|
quoted = !quoted;
|
||||||
|
name.append('"');
|
||||||
|
} else if (c == '\n' || (!quoted && (c == '#' || c == '='))) {
|
||||||
|
return new Identifier(name.toString().trim());
|
||||||
|
} else if (i == chars.length - 1 && identifier == null) {
|
||||||
|
name.append(c);
|
||||||
|
return new Identifier(name.toString().trim());
|
||||||
|
} else {
|
||||||
|
name.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return identifier != null ? identifier : Identifier.INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IdentifierConverter() {}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
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.ValueConverters.CONVERTERS;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
@ -8,7 +9,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
class InlineTableConverter implements ValueConverter {
|
class InlineTableConverter implements ValueConverter {
|
||||||
|
|
||||||
static final InlineTableConverter INLINE_TABLE_PARSER = new InlineTableConverter();
|
static final InlineTableConverter INLINE_TABLE_PARSER = new InlineTableConverter();
|
||||||
private static final ValueConverters CONVERTERS = new ValueConverters();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canConvert(String s) {
|
public boolean canConvert(String s) {
|
||||||
|
|
|
@ -29,9 +29,14 @@ class MultilineLiteralStringConverter implements ValueConverter {
|
||||||
@Override
|
@Override
|
||||||
public Object convert(String s, AtomicInteger index) {
|
public Object convert(String s, AtomicInteger index) {
|
||||||
char[] chars = s.toCharArray();
|
char[] chars = s.toCharArray();
|
||||||
|
int originalStartIndex = index.get();
|
||||||
int startIndex = index.addAndGet(3);
|
int startIndex = index.addAndGet(3);
|
||||||
int endIndex = -1;
|
int endIndex = -1;
|
||||||
|
|
||||||
|
if (chars[startIndex] == '\n') {
|
||||||
|
startIndex = index.incrementAndGet();
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = startIndex; i < chars.length; i = index.incrementAndGet()) {
|
for (int i = startIndex; i < chars.length; i = index.incrementAndGet()) {
|
||||||
char c = chars[i];
|
char c = chars[i];
|
||||||
|
|
||||||
|
@ -42,6 +47,10 @@ class MultilineLiteralStringConverter implements ValueConverter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (endIndex == -1) {
|
||||||
|
return ValueConverterUtils.unterminated(s.substring(originalStartIndex, s.length()));
|
||||||
|
}
|
||||||
|
|
||||||
return s.substring(startIndex, endIndex);
|
return s.substring(startIndex, endIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,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 static com.moandjiezana.toml.ValueConverterUtils.unterminated;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
@ -29,9 +30,14 @@ class MultilineStringConverter implements ValueConverter {
|
||||||
@Override
|
@Override
|
||||||
public Object convert(String s, AtomicInteger index) {
|
public Object convert(String s, AtomicInteger index) {
|
||||||
char[] chars = s.toCharArray();
|
char[] chars = s.toCharArray();
|
||||||
|
int originalStartIndex = index.get();
|
||||||
int startIndex = index.addAndGet(3);
|
int startIndex = index.addAndGet(3);
|
||||||
int endIndex = -1;
|
int endIndex = -1;
|
||||||
|
|
||||||
|
if (chars[startIndex] == '\n') {
|
||||||
|
startIndex = index.incrementAndGet();
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = startIndex; i < chars.length; i = index.incrementAndGet()) {
|
for (int i = startIndex; i < chars.length; i = index.incrementAndGet()) {
|
||||||
char c = chars[i];
|
char c = chars[i];
|
||||||
|
|
||||||
|
@ -43,7 +49,7 @@ class MultilineStringConverter implements ValueConverter {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endIndex == -1) {
|
if (endIndex == -1) {
|
||||||
return INVALID;
|
return unterminated(s.substring(originalStartIndex, s.length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
s = s.substring(startIndex, endIndex);
|
s = s.substring(startIndex, endIndex);
|
||||||
|
|
|
@ -50,6 +50,33 @@ class Results {
|
||||||
.append('\n');
|
.append('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void invalidIdentifier(Identifier identifier, int line) {
|
||||||
|
if (identifier.isKey()) {
|
||||||
|
invalidKey(identifier.getName(), line);
|
||||||
|
} else if (identifier.isTable()) {
|
||||||
|
invalidTable(identifier.getName(), line);
|
||||||
|
} else if (identifier.isTableArray()) {
|
||||||
|
invalidTableArray(identifier.getName(), line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void invalidTextAfterIdentifier(Identifier identifier, char text, int line) {
|
||||||
|
if (identifier.isKey() && text == '\n') {
|
||||||
|
sb.append("Key ")
|
||||||
|
.append(identifier.getName())
|
||||||
|
.append(" is not followed by an equals sign on line ")
|
||||||
|
.append(line)
|
||||||
|
.append('\n');
|
||||||
|
} else {
|
||||||
|
sb.append("Invalid text after key ")
|
||||||
|
.append(identifier.getName())
|
||||||
|
.append(" on line ")
|
||||||
|
.append(line)
|
||||||
|
.append(". Make sure to terminate the value or add a comment (#).")
|
||||||
|
.append('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void invalidKey(String key, int line) {
|
void invalidKey(String key, int line) {
|
||||||
sb.append("Invalid key");
|
sb.append("Invalid key");
|
||||||
if (line > -1) {
|
if (line > -1) {
|
||||||
|
@ -79,13 +106,13 @@ class Results {
|
||||||
.append('\n');
|
.append('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
void unterminated(String key, String multiline, int line) {
|
void unterminated(String key, String value, int line) {
|
||||||
sb.append("Unterminated multiline value on line ")
|
sb.append("Unterminated value on line ")
|
||||||
.append(line)
|
.append(line)
|
||||||
.append(": ")
|
.append(": ")
|
||||||
.append(key)
|
.append(key)
|
||||||
.append(" = ")
|
.append(" = ")
|
||||||
.append(multiline.trim())
|
.append(value.trim())
|
||||||
.append('\n');
|
.append('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,203 +1,73 @@
|
||||||
package com.moandjiezana.toml;
|
package com.moandjiezana.toml;
|
||||||
|
|
||||||
|
import static com.moandjiezana.toml.IdentifierConverter.IDENTIFIER_CONVERTER;
|
||||||
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
|
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
|
||||||
import static com.moandjiezana.toml.ValueConverterUtils.isComment;
|
|
||||||
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import com.moandjiezana.toml.ValueConverterUtils.Unterminated;
|
||||||
|
|
||||||
class TomlParser {
|
class TomlParser {
|
||||||
private static final String STRING_LITERAL_DELIMITER = "'''";
|
|
||||||
private static final Pattern MULTILINE_ARRAY_REGEX = Pattern.compile("\\s*\\[([^\\]]*)");
|
|
||||||
private static final Pattern MULTILINE_ARRAY_REGEX_END = Pattern.compile("\\s*\\]");
|
|
||||||
private static final ValueConverters VALUE_ANALYSIS = new ValueConverters();
|
|
||||||
|
|
||||||
private final Results results = new Results();
|
|
||||||
|
|
||||||
Results run(String tomlString) {
|
Results run(String tomlString) {
|
||||||
|
final Results results = new Results();
|
||||||
|
|
||||||
if (tomlString.isEmpty()) {
|
if (tomlString.isEmpty()) {
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] lines = tomlString.split("[\\n\\r]");
|
char[] chars = tomlString.toCharArray();
|
||||||
int lastKeyLine = 1;
|
AtomicInteger index = new AtomicInteger();
|
||||||
StringBuilder multilineBuilder = new StringBuilder();
|
boolean inComment = false;
|
||||||
Multiline multiline = Multiline.NONE;
|
AtomicInteger line = new AtomicInteger(1);
|
||||||
|
Identifier identifier = null;
|
||||||
|
Object value = null;
|
||||||
|
|
||||||
String key = null;
|
for (int i = index.get(); i < chars.length; i = index.incrementAndGet()) {
|
||||||
String value = null;
|
char c = chars[i];
|
||||||
|
|
||||||
for (int i = 0; i < lines.length; i++) {
|
if (c == '#' && !inComment) {
|
||||||
String line = lines[i];
|
inComment = true;
|
||||||
|
} else if (!Character.isWhitespace(c) && !inComment && identifier == null) {
|
||||||
|
Identifier id = IDENTIFIER_CONVERTER.convert(chars, index);
|
||||||
|
|
||||||
if (line != null && multiline.isTrimmable()) {
|
if (id.isValid()) {
|
||||||
line = line.trim();
|
char next = chars[index.get()];
|
||||||
}
|
if (index.get() < chars.length -1 && !id.acceptsNext(next)) {
|
||||||
|
results.errors.invalidTextAfterIdentifier(id, next, line.get());
|
||||||
if (isComment(line) || line.isEmpty()) {
|
} else if (id.isKey()) {
|
||||||
continue;
|
identifier = id;
|
||||||
}
|
} else if (id.isTable()) {
|
||||||
|
results.startTables(Keys.getTableName(id.getName()));
|
||||||
// TODO check that this works in multiline context
|
} else if (id.isTableArray()) {
|
||||||
if (isTableArray(line)) {
|
results.startTableArray(Keys.getTableArrayName(id.getName()));
|
||||||
String tableName = Keys.getTableArrayName(line);
|
|
||||||
if (tableName != null) {
|
|
||||||
results.startTableArray(tableName);
|
|
||||||
} else {
|
|
||||||
results.errors.invalidTableArray(line, i + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (multiline.isNotMultiline() && isTable(line)) {
|
|
||||||
String tableName = Keys.getTableName(line);
|
|
||||||
if (tableName != null) {
|
|
||||||
results.startTables(tableName);
|
|
||||||
} else {
|
|
||||||
results.errors.invalidTable(line.trim(), i + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (multiline.isNotMultiline() && !line.contains("=")) {
|
|
||||||
results.errors.invalidKey(line, i + 1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] pair = line.split("=", 2);
|
|
||||||
|
|
||||||
if (multiline.isNotMultiline() && MULTILINE_ARRAY_REGEX.matcher(pair[1].trim()).matches()) {
|
|
||||||
multiline = Multiline.ARRAY;
|
|
||||||
key = pair[0].trim();
|
|
||||||
multilineBuilder.append(removeComment(pair[1]));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (multiline.isNotMultiline() && pair[1].trim().startsWith("\"\"\"")) {
|
|
||||||
multiline = Multiline.STRING;
|
|
||||||
multilineBuilder.append(pair[1]);
|
|
||||||
key = pair[0].trim();
|
|
||||||
|
|
||||||
if (pair[1].trim().indexOf("\"\"\"", 3) > -1) {
|
|
||||||
multiline = Multiline.NONE;
|
|
||||||
pair[1] = multilineBuilder.toString().trim();
|
|
||||||
multilineBuilder.delete(0, multilineBuilder.length());
|
|
||||||
} else {
|
|
||||||
if (multilineBuilder.toString().trim().length() > 3) {
|
|
||||||
multilineBuilder.append('\n');
|
|
||||||
}
|
}
|
||||||
continue;
|
inComment = next == '#';
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (multiline.isNotMultiline() && pair[1].trim().startsWith(STRING_LITERAL_DELIMITER)) {
|
|
||||||
multiline = Multiline.STRING_LITERAL;
|
|
||||||
multilineBuilder.append(pair[1]);
|
|
||||||
key = pair[0].trim();
|
|
||||||
|
|
||||||
if (pair[1].trim().indexOf(STRING_LITERAL_DELIMITER, 3) > -1) {
|
|
||||||
multiline = Multiline.NONE;
|
|
||||||
pair[1] = multilineBuilder.toString().trim();
|
|
||||||
multilineBuilder.delete(0, multilineBuilder.length());
|
|
||||||
} else {
|
} else {
|
||||||
if (multilineBuilder.toString().trim().length() > 3) {
|
results.errors.invalidIdentifier(id, line.get());
|
||||||
multilineBuilder.append('\n');
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
} else if (c == '\n') {
|
||||||
|
inComment = false;
|
||||||
|
identifier = null;
|
||||||
|
value = null;
|
||||||
|
line.incrementAndGet();
|
||||||
|
} else if (!inComment && identifier != null && identifier.isKey() && value == null && !Character.isWhitespace(c)) {
|
||||||
|
int startIndex = index.get();
|
||||||
|
Object converted = ValueConverters.CONVERTERS.convert(tomlString, index);
|
||||||
|
value = converted;
|
||||||
|
|
||||||
if (multiline == Multiline.ARRAY) {
|
if (converted == INVALID) {
|
||||||
String lineWithoutComment = removeComment(line);
|
results.errors.invalidValue(identifier.getName(), tomlString.substring(startIndex, Math.min(index.get(), tomlString.length() - 1)), line.get());
|
||||||
multilineBuilder.append(lineWithoutComment);
|
} else if (converted instanceof Unterminated) {
|
||||||
if (MULTILINE_ARRAY_REGEX_END.matcher(lineWithoutComment).matches()) {
|
results.errors.unterminated(identifier.getName(), ((Unterminated) converted).payload, line.get());
|
||||||
multiline = Multiline.NONE;
|
|
||||||
value = multilineBuilder.toString();
|
|
||||||
multilineBuilder.delete(0, multilineBuilder.length());
|
|
||||||
} else {
|
} else {
|
||||||
continue;
|
results.addValue(identifier.getName(), converted);
|
||||||
}
|
}
|
||||||
} else if (multiline == Multiline.STRING) {
|
} else if (value != null && !inComment && !Character.isWhitespace(c)) {
|
||||||
multilineBuilder.append(line);
|
results.errors.invalidTextAfterIdentifier(identifier, c, line.get());
|
||||||
if (line.contains("\"\"\"")) {
|
|
||||||
multiline = Multiline.NONE;
|
|
||||||
value = multilineBuilder.toString().trim();
|
|
||||||
multilineBuilder.delete(0, multilineBuilder.length());
|
|
||||||
} else {
|
|
||||||
multilineBuilder.append('\n');
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else if (multiline == Multiline.STRING_LITERAL) {
|
|
||||||
multilineBuilder.append(line);
|
|
||||||
if (line.contains(STRING_LITERAL_DELIMITER)) {
|
|
||||||
multiline = Multiline.NONE;
|
|
||||||
value = multilineBuilder.toString().trim();
|
|
||||||
multilineBuilder.delete(0, multilineBuilder.length());
|
|
||||||
} else {
|
|
||||||
multilineBuilder.append('\n');
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
key = Keys.getKey(pair[0]);
|
|
||||||
if (key == null) {
|
|
||||||
results.errors.invalidKey(pair[0], i + 1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
value = pair[1].trim();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lastKeyLine = i + 1;
|
|
||||||
Object convertedValue = VALUE_ANALYSIS.convert(value);
|
|
||||||
|
|
||||||
if (convertedValue != INVALID) {
|
|
||||||
results.addValue(key, convertedValue);
|
|
||||||
} else {
|
|
||||||
results.errors.invalidValue(key, value, i + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (multiline != Multiline.NONE) {
|
|
||||||
results.errors.unterminated(key, multilineBuilder.toString().trim(), lastKeyLine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isTableArray(String line) {
|
|
||||||
return line.startsWith("[[");
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isTable(String line) {
|
|
||||||
return line.startsWith("[");
|
|
||||||
}
|
|
||||||
|
|
||||||
private String removeComment(String line) {
|
|
||||||
line = line.trim();
|
|
||||||
if (line.startsWith("\"")) {
|
|
||||||
int startOfComment = line.indexOf('#', line.lastIndexOf('"'));
|
|
||||||
if (startOfComment > -1) {
|
|
||||||
return line.substring(0, startOfComment - 1).trim();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int startOfComment = line.indexOf('#');
|
|
||||||
if (startOfComment > -1) {
|
|
||||||
return line.substring(0, startOfComment - 1).trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static enum Multiline {
|
|
||||||
NONE, ARRAY, STRING, STRING_LITERAL;
|
|
||||||
|
|
||||||
public boolean isNotMultiline() {
|
|
||||||
return this == NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTrimmable() {
|
|
||||||
return this == NONE || this == ARRAY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,18 @@ package com.moandjiezana.toml;
|
||||||
class ValueConverterUtils {
|
class ValueConverterUtils {
|
||||||
static final Object INVALID = new Object();
|
static final Object INVALID = new Object();
|
||||||
|
|
||||||
|
static Unterminated unterminated(String payload) {
|
||||||
|
return new Unterminated(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Unterminated {
|
||||||
|
final String payload;
|
||||||
|
|
||||||
|
private Unterminated(String payload) {
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static boolean isComment(String line) {
|
static boolean isComment(String line) {
|
||||||
if (line == null || line.isEmpty()) {
|
if (line == null || line.isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -15,21 +15,12 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
class ValueConverters {
|
class ValueConverters {
|
||||||
|
|
||||||
|
static final ValueConverters CONVERTERS = new 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
|
||||||
};
|
};
|
||||||
|
|
||||||
Object convert(String value) {
|
|
||||||
for (ValueConverter valueParser : PARSERS) {
|
|
||||||
if (valueParser.canConvert(value)) {
|
|
||||||
return valueParser.convert(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Object convert(String value, AtomicInteger index) {
|
Object convert(String value, AtomicInteger index) {
|
||||||
String substring = value.substring(index.get());
|
String substring = value.substring(index.get());
|
||||||
for (ValueConverter valueParser : PARSERS) {
|
for (ValueConverter valueParser : PARSERS) {
|
||||||
|
@ -40,4 +31,6 @@ class ValueConverters {
|
||||||
|
|
||||||
return INVALID;
|
return INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ValueConverters() {}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue