private String getOrRenderDescription()

in freemarker-core/src/main/java/freemarker/core/ParseException.java [373:493]


    private String getOrRenderDescription() {
        synchronized (this) {
            if (description != null) return description;  // When we already have it from the constructor
        }

        if (currentToken == null) {
            return null;
        }

        Token unexpectedTok = currentToken.next;

        if (unexpectedTok.kind == EOF) {
            Set<String> endTokenDescs = getExpectedEndTokenDescs();
            return "Unexpected end of file reached."
                    + (endTokenDescs.size() == 0
                            ? ""
                            : " You have an unclosed " + joinWithAnds(endTokenDescs)
                                    + ". Check if the FreeMarker end-tags are present, and aren't malformed. "
                                    + END_TAG_SYNTAX_HINT);
        }

        int maxExpectedTokenSequenceLength = 0;
        for (int i = 0; i < expectedTokenSequences.length; i++) {
            int[] expectedTokenSequence = expectedTokenSequences[i];
            if (maxExpectedTokenSequenceLength < expectedTokenSequence.length) {
                maxExpectedTokenSequenceLength = expectedTokenSequence.length;
            }
        }

        StringBuilder tokenErrDesc = new StringBuilder();
        tokenErrDesc.append("Encountered ");
        boolean encounteredEndTag = false;
        for (int i = 0; i < maxExpectedTokenSequenceLength; i++) {
            if (i != 0) {
                tokenErrDesc.append(" ");
            }
            if (unexpectedTok.kind == 0) {
                tokenErrDesc.append(tokenImage[0]);
                break;
            }

            String image = unexpectedTok.image;
            if (i == 0) {
                if (image.startsWith("</") || image.startsWith("[/")) {
                    encounteredEndTag = true;
                }
            }
            tokenErrDesc.append(StringUtil.jQuote(image));
            unexpectedTok = unexpectedTok.next;
        }
        Set<String> expectedEndTokenDescs;
        int unexpTokKind = currentToken.next.kind;
        if (getIsEndToken(unexpTokKind) || unexpTokKind == ELSE || unexpTokKind == ELSE_IF) {
            expectedEndTokenDescs = new LinkedHashSet<>(getExpectedEndTokenDescs());
            if (unexpTokKind == ELSE || unexpTokKind == ELSE_IF) {
                // If <\#if> was expected, yet #else or #elseif wasn't, then this isn't nesting related problem.
                expectedEndTokenDescs.remove(getEndTokenDescIfIsEndToken(END_IF));
            } else {
                expectedEndTokenDescs.remove(getEndTokenDescIfIsEndToken(unexpTokKind));
            }
        } else {
            expectedEndTokenDescs = Collections.emptySet();
        }
        // Generate more helpful error message if this was a nesting related problem:
        if (!expectedEndTokenDescs.isEmpty()) {
            if (unexpTokKind == ELSE || unexpTokKind == ELSE_IF) {
                tokenErrDesc.append(", which can only be used where an #if");
                if (unexpTokKind == ELSE) {
                    tokenErrDesc.append(" or #list");
                }
                tokenErrDesc.append(" could be closed");
            }
            tokenErrDesc.append(", but at this place only ");
            tokenErrDesc.append(expectedEndTokenDescs.size() > 1 ? "these" : "this");
            tokenErrDesc.append(" can be closed: ");
            boolean first = true;
            for (String expectedEndTokenDesc : expectedEndTokenDescs) {
                if (!first) {
                    tokenErrDesc.append(", ");
                } else {
                    first = false;
                }
                tokenErrDesc.append(
                        !expectedEndTokenDesc.startsWith("\"")
                                ? StringUtil.jQuote(expectedEndTokenDesc)
                                : expectedEndTokenDesc);
            }
            tokenErrDesc.append(".");
            if (encounteredEndTag) {
                tokenErrDesc.append(" This usually because of wrong nesting of FreeMarker directives, like a "
                        + "missed or malformed end-tag somewhere. " + END_TAG_SYNTAX_HINT);
            }
            tokenErrDesc.append(eol);
            tokenErrDesc.append("Was ");
        } else {
            tokenErrDesc.append(", but was ");
        }

        if (expectedTokenSequences.length == 1) {
            tokenErrDesc.append("expecting pattern:");
        } else {
            tokenErrDesc.append("expecting one of these patterns:");
        }
        tokenErrDesc.append(eol);

        for (int i = 0; i < expectedTokenSequences.length; i++) {
            if (i != 0) {
                tokenErrDesc.append(eol);
            }
            tokenErrDesc.append("    ");
            int[] expectedTokenSequence = expectedTokenSequences[i];
            for (int j = 0; j < expectedTokenSequence.length; j++) {
                if (j != 0) {
                    tokenErrDesc.append(' ');
                }
                tokenErrDesc.append(tokenImage[expectedTokenSequence[j]]);
            }
        }

        return tokenErrDesc.toString();
    }