private Object fetchExpression()

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
    }