in meecrowave-core/src/main/java/org/apache/meecrowave/lang/Substitutor.java [51:133]
private int substitute(final StringBuilder buf, final int offset, final int length, List<String> priorVariables) {
final boolean top = priorVariables == null;
boolean altered = false;
int lengthChange = 0;
char[] chars = buf.toString().toCharArray();
int bufEnd = offset + length;
int pos = offset;
while (pos < bufEnd) {
final int startMatchLen = isMatch(PREFIX, chars, pos, bufEnd);
if (startMatchLen == 0) {
pos++;
} else {
if (pos > offset && chars[pos - 1] == ESCAPE) {
buf.deleteCharAt(pos - 1);
chars = buf.toString().toCharArray();
lengthChange--;
altered = true;
bufEnd--;
} else {
final int startPos = pos;
pos += startMatchLen;
int endMatchLen;
while (pos < bufEnd) {
endMatchLen = isMatch(SUFFIX, chars, pos, bufEnd);
if (endMatchLen == 0) {
pos++;
} else {
String varNameExpr = new String(chars, startPos
+ startMatchLen, pos - startPos
- startMatchLen);
pos += endMatchLen;
final int endPos = pos;
String varName = varNameExpr;
String varDefaultValue = null;
final char[] varNameExprChars = varNameExpr.toCharArray();
for (int i = 0; i < varNameExprChars.length; i++) {
if (isMatch(PREFIX, varNameExprChars, i, varNameExprChars.length) != 0) {
break;
}
final int match = isMatch(VALUE_DELIMITER, varNameExprChars, i, varNameExprChars.length);
if (match != 0) {
varName = varNameExpr.substring(0, i);
varDefaultValue = varNameExpr.substring(i + match);
break;
}
}
if (priorVariables == null) {
priorVariables = new ArrayList<>();
priorVariables.add(new String(chars,
offset, length));
}
checkCyclicSubstitution(varName, priorVariables);
priorVariables.add(varName);
final String varValue = getOrDefault(varName, varDefaultValue);
if (varValue != null) {
final int varLen = varValue.length();
buf.replace(startPos, endPos, varValue);
altered = true;
int change = substitute(buf, startPos, varLen, priorVariables);
change = change + varLen - (endPos - startPos);
pos += change;
bufEnd += change;
lengthChange += change;
chars = buf.toString().toCharArray();
}
priorVariables.remove(priorVariables.size() - 1);
break;
}
}
}
}
}
if (top) {
return altered ? 1 : 0;
}
return lengthChange;
}