Parse any number of "(expr)", "[expr]" ".expr", "?.expr", "..expr", ".(expr)" or "?.(expr)" constructs trailing the passed expression. @param pn the non-null parent node @return the outermost (lexically last occurring) expression, which will have the passed parent node as a descendant
(boolean allowCallSyntax, AstNode pn)
| 3156 | * parent node as a descendant |
| 3157 | */ |
| 3158 | private AstNode memberExprTail(boolean allowCallSyntax, AstNode pn) throws IOException { |
| 3159 | // we no longer return null for errors, so this won't be null |
| 3160 | if (pn == null) codeBug(); |
| 3161 | int pos = pn.getPosition(); |
| 3162 | int lineno, column; |
| 3163 | boolean isOptionalChain = false; |
| 3164 | tailLoop: |
| 3165 | for (; ; ) { |
| 3166 | lineno = lineNumber(); |
| 3167 | column = columnNumber(); |
| 3168 | int tt = peekToken(); |
| 3169 | switch (tt) { |
| 3170 | case Token.DOT: |
| 3171 | case Token.QUESTION_DOT: |
| 3172 | case Token.DOTDOT: |
| 3173 | isOptionalChain |= (tt == Token.QUESTION_DOT); |
| 3174 | pn = propertyAccess(tt, pn, isOptionalChain); |
| 3175 | break; |
| 3176 | |
| 3177 | case Token.DOTQUERY: |
| 3178 | consumeToken(); |
| 3179 | int opPos = ts.tokenBeg, rp = -1; |
| 3180 | mustHaveXML(); |
| 3181 | setRequiresActivation(); |
| 3182 | AstNode filter = expr(false); |
| 3183 | int end = getNodeEnd(filter); |
| 3184 | if (mustMatchToken(Token.RP, "msg.no.paren", true)) { |
| 3185 | rp = ts.tokenBeg; |
| 3186 | end = ts.tokenEnd; |
| 3187 | } |
| 3188 | XmlDotQuery q = new XmlDotQuery(pos, end - pos); |
| 3189 | q.setLeft(pn); |
| 3190 | q.setRight(filter); |
| 3191 | q.setOperatorPosition(opPos); |
| 3192 | q.setRp(rp - pos); |
| 3193 | q.setLineColumnNumber(lineno, column); |
| 3194 | pn = q; |
| 3195 | break; |
| 3196 | |
| 3197 | case Token.LB: |
| 3198 | consumeToken(); |
| 3199 | pn = makeElemGet(pn, ts.tokenBeg); |
| 3200 | break; |
| 3201 | |
| 3202 | case Token.LP: |
| 3203 | if (!allowCallSyntax) { |
| 3204 | break tailLoop; |
| 3205 | } |
| 3206 | pn = makeFunctionCall(pn, pos, isOptionalChain); |
| 3207 | break; |
| 3208 | case Token.COMMENT: |
| 3209 | // Ignoring all the comments, because previous statement may not be terminated |
| 3210 | // properly. |
| 3211 | int currentFlagTOken = currentFlaggedToken; |
| 3212 | peekUntilNonComment(tt); |
| 3213 | currentFlaggedToken = |
| 3214 | (currentFlaggedToken & TI_AFTER_EOL) != 0 |
| 3215 | ? currentFlaggedToken |
no test coverage detected