1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-07 17:56:01 +02:00

c++17 simplify fold expression parser and fix cast-expression on sides

Simplify parser by deferring fold-expression op token check until complete
expression can be examined.

Binary expression builder already produces a chain of BInaryOperator with
cast-expression objects. Use that to restrict valid fold-expression sequence
to the one containing only cast-expression on sides.
This commit is contained in:
Igor V. Kovalenko 2023-01-24 21:32:16 +03:00 committed by Jonah Graham
parent 04c2da4678
commit 58ab28dfd1

View file

@ -1018,15 +1018,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
IToken variantMark = mark(); IToken variantMark = mark();
if (expr == null) { if (expr == null) {
// Could be ellipsis of unary left fold expression Object e = castExpressionForBinaryExpression(strat, ctx);
IASTExpression foldExpression = foldStartingExpression(ctx, strat);
if (foldExpression != null) {
lt1 = LT(1);
lastOperator = new BinaryOperator(lastOperator, foldExpression, lt1, 0, 0);
consume(); // consume operator token
}
Object e = castExpressionForBinaryExpression(strat);
if (e instanceof IASTExpression) { if (e instanceof IASTExpression) {
expr = (IASTExpression) e; expr = (IASTExpression) e;
} else { } else {
@ -1212,10 +1204,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
stopWithNextOperator = true; stopWithNextOperator = true;
} else { } else {
// Could be ellipsis of any right fold expression or ellipsis of binary left fold expression // Could be ellipsis of any right fold expression or ellipsis of binary left fold expression
Object e = foldInsideExpression(ctx, strat, lt1); Object e = castExpressionForBinaryExpression(strat, ctx);
if (e == null) {
e = castExpressionForBinaryExpression(strat);
}
if (e instanceof IASTExpression) { if (e instanceof IASTExpression) {
expr = (IASTExpression) e; expr = (IASTExpression) e;
@ -1327,6 +1316,8 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
} }
} }
// Valid fold-expression has single ellipsis.
if (foldCount == 1) { if (foldCount == 1) {
BinaryOperator rightChain; BinaryOperator rightChain;
if (foldOp == null) { if (foldOp == null) {
@ -1349,12 +1340,27 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
leftChain = foldOp.getNext(); leftChain = foldOp.getNext();
} }
IASTExpression lhs = leftChain == null ? null // Valid fold-expression has at most one cast-expression on each side of ellipsis.
: super.buildExpression(leftChain.getNext(), leftChain.getExpression()); // This is easy to check since each of BinaryOperator chain elements carry single
IASTExpression rhs = super.buildExpression(rightChain, expr); // cast-expression.
return buildFoldExpression(foldOpToken, lhs, rhs, firstOffset, endOffset); if (leftChain != null && foldOpToken != leftChain.getOperatorToken()) {
} else if (foldCount > 1) { // Invalid, binary fold with different operator tokens
} else if (!allowedFoldExpressionOpToken(foldOpToken)) {
// Invalid, fold with invalid operator token
} else if (leftChain != null && leftChain.getNext() != null) {
// Invalid, more than one cast-expression on the left side
} else if (rightChain != null) {
// Invalid, more than one cast-expression on the right side
} else {
IASTExpression lhs = leftChain == null ? null : (IASTExpression) leftChain.getExpression();
IASTExpression rhs = (IASTExpression) expr;
return buildFoldExpression(foldOpToken, lhs, rhs, firstOffset, endOffset);
}
}
if (foldCount >= 1) {
// Invalid fold-expression
IASTProblem problem = createProblem(IProblem.SYNTAX_ERROR, firstOffset, endOffset - firstOffset); IASTProblem problem = createProblem(IProblem.SYNTAX_ERROR, firstOffset, endOffset - firstOffset);
IASTProblemExpression pexpr = getNodeFactory().newProblemExpression(problem); IASTProblemExpression pexpr = getNodeFactory().newProblemExpression(problem);
((ASTNode) pexpr).setOffsetAndLength(((ASTNode) problem)); ((ASTNode) pexpr).setOffsetAndLength(((ASTNode) problem));
@ -1365,47 +1371,15 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
return super.buildExpression(leftChain, expr); return super.buildExpression(leftChain, expr);
} }
private IASTExpression foldStartingExpression(final BinaryExprCtx ctx, ITemplateIdStrategy strat) public Object castExpressionForBinaryExpression(ITemplateIdStrategy s, final BinaryExprCtx ctx)
throws EndOfFileException, BacktrackException { throws EndOfFileException, BacktrackException {
if (supportFoldExpression && ctx == BinaryExprCtx.eInPrimaryExpression) { if (supportFoldExpression && ctx == BinaryExprCtx.eInPrimaryExpression && LTcatchEOF(1) == IToken.tELLIPSIS) {
if (LTcatchEOF(1) == IToken.tELLIPSIS) { // Ellipsis of fold-expression
int rightOpToken = LTcatchEOF(2); IToken foldToken = consume();
if (allowedFoldExpressionOpToken(rightOpToken)) { return buildFoldExpressionToken(foldToken.getOffset(), foldToken.getEndOffset());
// unary left fold expression: (... op pack)
IToken foldToken = consume();
return buildFoldExpressionToken(foldToken.getOffset(), foldToken.getEndOffset());
}
}
} }
return null;
}
private IASTExpression foldInsideExpression(final BinaryExprCtx ctx, ITemplateIdStrategy strat, int leftOpToken)
throws EndOfFileException, BacktrackException {
if (supportFoldExpression && ctx == BinaryExprCtx.eInPrimaryExpression) {
if (LTcatchEOF(1) == IToken.tELLIPSIS) {
if (allowedFoldExpressionOpToken(leftOpToken)) {
int rightOpToken = LTcatchEOF(2);
if (rightOpToken == 0 || rightOpToken == IToken.tRPAREN || rightOpToken == leftOpToken) {
// unary right fold: (... op pack)
// or
// binary right fold: (pack op ... op init)
// binary left fold: (init op ... op pack)
IToken foldToken = consume();
return buildFoldExpressionToken(foldToken.getOffset(), foldToken.getEndOffset());
}
}
}
}
return null;
}
public Object castExpressionForBinaryExpression(ITemplateIdStrategy s)
throws EndOfFileException, BacktrackException {
if (s != null) { if (s != null) {
return castExpression(CastExprCtx.eDirectlyInBExpr, s); return castExpression(CastExprCtx.eDirectlyInBExpr, s);
} }
@ -2294,7 +2268,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
default: default:
throwBacktrack(LA(1)); throwBacktrack(LA(1));
} }
if (lhs instanceof ICPPASTFoldExpression) { if (lhs instanceof ICPPASTFoldExpression || lhs instanceof IASTProblemExpression) {
return setRange(lhs, t.getOffset(), finalOffset); return setRange(lhs, t.getOffset(), finalOffset);
} else { } else {
return buildUnaryExpression(IASTUnaryExpression.op_bracketedPrimary, lhs, t.getOffset(), finalOffset); return buildUnaryExpression(IASTUnaryExpression.op_bracketedPrimary, lhs, t.getOffset(), finalOffset);