in scripts/src/main/java/com/gu/typesafe/config/impl/PathParser.java [90:180]
protected static Path parsePathExpression(Iterator<Token> expression,
ConfigOrigin origin, String originalText,
ArrayList<Token> pathTokens,
com.gu.typesafe.config.ConfigSyntax flavor) {
// each builder in "buf" is an element in the path.
List<Element> buf = new ArrayList<Element>();
buf.add(new Element("", false));
if (!expression.hasNext()) {
throw new com.gu.typesafe.config.ConfigException.BadPath(origin, originalText,
"Expecting a field name or path here, but got nothing");
}
while (expression.hasNext()) {
Token t = expression.next();
if (pathTokens != null)
pathTokens.add(t);
// Ignore all IgnoredWhitespace tokens
if (Tokens.isIgnoredWhitespace(t))
continue;
if (Tokens.isValueWithType(t, ConfigValueType.STRING)) {
com.gu.typesafe.config.impl.AbstractConfigValue v = Tokens.getValue(t);
// this is a quoted string; so any periods
// in here don't count as path separators
String s = v.transformToString();
addPathText(buf, true, s);
} else if (t == Tokens.END) {
// ignore this; when parsing a file, it should not happen
// since we're parsing a token list rather than the main
// token iterator, and when parsing a path expression from the
// API, it's expected to have an END.
} else {
// any periods outside of a quoted string count as
// separators
String text;
if (Tokens.isValue(t)) {
// appending a number here may add
// a period, but we _do_ count those as path
// separators, because we basically want
// "foo 3.0bar" to parse as a string even
// though there's a number in it. The fact that
// we tokenize non-string values is largely an
// implementation detail.
com.gu.typesafe.config.impl.AbstractConfigValue v = Tokens.getValue(t);
// We need to split the tokens on a . so that we can get sub-paths but still preserve
// the original path text when doing an insertion
if (pathTokens != null) {
pathTokens.remove(pathTokens.size() - 1);
pathTokens.addAll(splitTokenOnPeriod(t, flavor));
}
text = v.transformToString();
} else if (Tokens.isUnquotedText(t)) {
// We need to split the tokens on a . so that we can get sub-paths but still preserve
// the original path text when doing an insertion on ConfigNodeObjects
if (pathTokens != null) {
pathTokens.remove(pathTokens.size() - 1);
pathTokens.addAll(splitTokenOnPeriod(t, flavor));
}
text = Tokens.getUnquotedText(t);
} else {
throw new com.gu.typesafe.config.ConfigException.BadPath(
origin,
originalText,
"Token not allowed in path expression: "
+ t
+ " (you can double-quote this token if you really want it here)");
}
addPathText(buf, false, text);
}
}
com.gu.typesafe.config.impl.PathBuilder pb = new com.gu.typesafe.config.impl.PathBuilder();
for (Element e : buf) {
if (e.sb.length() == 0 && !e.canBeEmpty) {
throw new ConfigException.BadPath(
origin,
originalText,
"path has a leading, trailing, or two adjacent period '.' (use quoted \"\" empty string if you want an empty element)");
} else {
pb.appendKey(e.sb.toString());
}
}
return pb.result();
}