in freemarker-docgen-core/src/main/java/org/freemarker/docgen/core/CJSONInterpreter.java [774:1147]
private Object fetchExpression(boolean forceStr, boolean mapKey)
throws EvaluationException {
char c;
if (p >= ln) { //!!a
throw new BugException("Calling fetchExpression when p >= ln.");
}
c = tx.charAt(p);
// JSON Object:
if (c == '{') {
Object nr;
p++;
Object res;
Map<String, Object> map = new LinkedHashMap<String, Object>();
boolean done = false;
try {
try {
nr = ee.notify(
EvaluationEvent.ENTER_MAP,
this, null, map);
done = true;
} catch (Throwable e) {
throw newWrappedError(e);
}
if (nr == null) {
fetchMapInner(map, '}', forceStr);
res = map;
} else {
p--;
int p2 = p;
skipExpression();
res = new Fragment(tx, p2, p, fileName);
p--;
}
} finally {
if (done) {
try {
ee.notify(
EvaluationEvent.LEAVE_MAP,
this, null, map);
} catch (Throwable e) {
throw newWrappedError(e);
}
}
}
p++;
return res; //!
}
// JSON array:
if (c == '[') {
p++;
List<Object> res = new ArrayList<Object>();
boolean done = false;
try {
try {
ee.notify(
EvaluationEvent.ENTER_LIST,
this, null, res);
done = true;
} catch (Throwable e) {
throw newWrappedError(e);
}
fetchListInner(res, ']', forceStr);
} finally {
if (done) {
try {
ee.notify(
EvaluationEvent.LEAVE_LIST,
this, null, res);
} catch (Throwable e) {
throw newWrappedError(e);
}
}
}
p++;
return res; //!
}
int b = p;
// Quoted string:
if (c == '"' || c == '\'') {
char q = c;
p++;
while (p < ln) {
c = tx.charAt(p);
if (c == '\\') {
break;
}
p++;
if (c == q) {
return tx.substring(b + 1, p - 1); //!
}
}
if (p == ln) {
throw newSyntaxError(
"The closing " + TextUtil.jQuoteOrName(q)
+ " of the string is missing.",
b);
}
int bidx = b + 1;
StringBuilder buf = new StringBuilder();
while (true) {
buf.append(tx.substring(bidx, p));
if (p == ln - 1) {
throw newSyntaxError(
"The closing " + TextUtil.jQuoteOrName(q)
+ " of the string is missing.",
b);
}
c = tx.charAt(p + 1);
switch (c) {
case '"':
buf.append('"');
bidx = p + 2;
break;
case '\'':
buf.append('\'');
bidx = p + 2;
break;
case '\\':
buf.append('\\');
bidx = p + 2;
break;
case 'n':
buf.append('\n');
bidx = p + 2;
break;
case 'r':
buf.append('\r');
bidx = p + 2;
break;
case 't':
buf.append('\t');
bidx = p + 2;
break;
case 'f':
buf.append('\f');
bidx = p + 2;
break;
case 'b':
buf.append('\b');
bidx = p + 2;
break;
case 'g':
buf.append('>');
bidx = p + 2;
break;
case 'l':
buf.append('<');
bidx = p + 2;
break;
case 'a':
buf.append('&');
bidx = p + 2;
break;
case '{':
buf.append('{');
bidx = p + 2;
break;
case '/': // JSON have this
buf.append('/');
bidx = p + 2;
break;
case 'x':
case 'u':
{
p += 2;
int x = p;
int y = 0;
int z = (ln - p) > 4 ? p + 4 : ln;
while (p < z) {
char c2 = tx.charAt(p);
if (c2 >= '0' && c2 <= '9') {
y <<= 4;
y += c2 - '0';
} else if (c2 >= 'a' && c2 <= 'f') {
y <<= 4;
y += c2 - 'a' + 10;
} else if (c2 >= 'A' && c2 <= 'F') {
y <<= 4;
y += c2 - 'A' + 10;
} else {
break;
}
p++;
}
if (x < p) {
buf.append((char) y);
} else {
throw newSyntaxError(
"Invalid hexadecimal UNICODE escape in "
+ "the string literal.",
x - 2);
}
bidx = p;
break;
}
default:
if (isWS(c)) {
boolean hasWS = false;
bidx = p + 1;
do {
if (c == 0xA || c == 0xD) {
if (hasWS) {
break;
}
hasWS = true;
if (c == 0xD && bidx < ln - 1) {
if (tx.charAt(bidx + 1) == 0xA) {
bidx++;
}
}
}
bidx++;
if (bidx == ln) {
break;
}
c = tx.charAt(bidx);
} while (isWS(c));
if (!hasWS) {
throw newSyntaxError(
"Invalid usage of escape sequence "
+ "\\white-space. This escape sequence "
+ "can be used only before "
+ "line-break.");
}
} else {
throw newSyntaxError(
"Invalid escape sequence \\" + c
+ " in the string literal.");
}
}
p = bidx;
while (true) {
if (p == ln) {
throw newSyntaxError(
"The closing " + TextUtil.jQuoteOrName(q)
+ " of the string is missing.",
b);
}
c = tx.charAt(p);
if (c == '\\') {
break;
}
if (c == q) {
buf.append(tx.substring(bidx, p));
p++;
return buf.toString(); //!
}
p++;
}
} // while true
} // if quoted string
// Raw string:
char c2;
if (p < ln - 1) {
c2 = tx.charAt(p + 1);
} else {
c2 = 0x20;
}
if (c == 'r' && (c2 == '"' || c2 == '\'')) {
char q = c2;
p += 2;
while (p < ln) {
c = tx.charAt(p);
p++;
if (c == q) {
return tx.substring(b + 2, p - 1); //!
}
}
throw newSyntaxError(
"The closing " + TextUtil.jQuoteOrName(q)
+ " of the string is missing.",
b);
}
// Unquoted string, boolean or number, or function call
uqsLoop: while (true) {
c = tx.charAt(p);
if (!isUnquotedStringChar(c) && !(p == b && c == '+')) {
break uqsLoop;
}
p++;
if (p == ln) {
break uqsLoop;
}
}
if (b == p) {
throw newSyntaxError("Unexpected character.", b);
} else {
String s = tx.substring(b, p);
int funcP = b;
int oldP = p;
c = skipWS();
if (c == '(') {
p++;
List<Object> params;
boolean done = false;
try {
try {
ee.notify(
EvaluationEvent.ENTER_FUNCTION_PARAMS,
this, s, null);
} catch (Throwable e) {
throw newWrappedError(e, funcP);
}
done = true;
params = fetchListInner(
new ArrayList<Object>(), ')', forceStr);
} finally {
if (done) {
try {
ee.notify(
EvaluationEvent.LEAVE_FUNCTION_PARAMS,
this, s, null);
} catch (Throwable e) {
throw newWrappedError(e);
}
}
}
p++;
FunctionCall func = new FunctionCall(s, params);
if (!mapKey) {
try {
return ee.evalFunctionCall(func, this); //!
} catch (Throwable e) {
throw newError("Failed to evaluate function "
+ TextUtil.jQuote(func.getName()) + ".",
b, e);
}
} else {
return func;
}
} else {
p = oldP;
if (!forceStr && !mapKey) {
if (s.equals("true")) {
return Boolean.TRUE; //!
} else if (s.equals("false")) {
return Boolean.FALSE; //!
} else if (s.equals("null")) {
return null; //!
}
c = s.charAt(0);
if ((c >= '0' && c <= '9') || c == '+' || c == '-') {
String s2;
if (c == '+') {
s2 = s.substring(1); // Integer(s) doesn't know +.
} else {
s2 = s;
}
try {
return new Integer(s2); //!
} catch (NumberFormatException exc) {
// ignore
}
try {
return new BigDecimal(s2); //!
} catch (NumberFormatException exc) {
// ignore
}
}
}
return s; //!
} // if not '('
} // if b == p
}