Skip to content

Commit

Permalink
Add c++17 fold expression
Browse files Browse the repository at this point in the history
  • Loading branch information
i-garrison committed Jan 8, 2023
1 parent c98aae4 commit be56c19
Show file tree
Hide file tree
Showing 10 changed files with 951 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11400,4 +11400,60 @@ public void testIntegerPack_553794() throws Exception {
ITypedef type2 = helper.assertNonProblem("type2");
assertSameType(type1, type2);
}

// using size_t = decltype(sizeof(int));
//
// template<typename T> struct X {
// static constexpr size_t g(const T& arg) noexcept { return sizeof(arg); }
// };
//
// template<typename... Pack>
// constexpr size_t f1(const Pack&... pack) { return (... + X<Pack>::g(pack)); }
// template<typename... Pack>
// constexpr size_t f2(const Pack&... pack) { return (0 + ... + X<Pack>::g(pack)); }
// template<typename... Pack>
// constexpr size_t f3(const Pack&... pack) { return (X<Pack>::g(pack) + ...); }
// template<typename... Pack>
// constexpr size_t f4(const Pack&... pack) { return (X<Pack>::g(pack) + ... + 0); }
//
// static constexpr auto val1 = f1(1, 2., "1");
// static constexpr auto val2 = f2(1, 2., "12");
// static constexpr auto val3 = f3(1, 2., "123");
// static constexpr auto val4 = f4(1, 2., "1234");
public void testFoldExpression1() throws Exception {
parseAndCheckBindings();
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("val1", 14);
helper.assertVariableValue("val2", 15);
helper.assertVariableValue("val3", 16);
helper.assertVariableValue("val4", 17);
}

// using size_t = decltype(sizeof(int));
//
// template<typename... Pack>
// constexpr bool f1(const Pack&... pack) { return (... && pack); }
// template<typename... Pack>
// constexpr bool f2(const Pack&... pack) { return (pack && ...); }
// template<typename... Pack>
// constexpr bool f3(const Pack&... pack) { return (... || pack); }
// template<typename... Pack>
// constexpr bool f4(const Pack&... pack) { return (pack || ...); }
//
// static constexpr auto val1 = f1();
// static constexpr auto val21 = f2(false);
// static constexpr auto val22 = f2(true);
// static constexpr auto val3 = f3();
// static constexpr auto val41 = f4(false);
// static constexpr auto val42 = f4(true);
public void testFoldExpression2() throws Exception {
parseAndCheckBindings();
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("val1", 1);
helper.assertVariableValue("val21", 0);
helper.assertVariableValue("val22", 1);
helper.assertVariableValue("val3", 0);
helper.assertVariableValue("val41", 0);
helper.assertVariableValue("val42", 1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*******************************************************************************
* Copyright (c) 2022 Igor V. Kovalenko.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Igor V. Kovalenko - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.core.dom.ast.cpp;

public interface ICPPASTFoldExpression extends ICPPASTExpression {

}
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,12 @@ public ICPPASTFunctionWithTryBlock newFunctionTryBlock(IASTDeclSpecifier declSpe
*/
public ICPPASTLambdaExpression newLambdaExpression();

/**
* @since 8.0
*/
public ICPPASTFoldExpression newFoldExpression(int opToken, boolean isComma, IASTExpression lhs,
IASTExpression rhs);

public ICPPASTLinkageSpecification newLinkageSpecification(String literal);

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1010,9 +1010,13 @@ public BinaryOperator getNext() {
public void setNext(BinaryOperator next) {
fNext = next;
}

public int getOperatorToken() {
return fOperatorToken;
}
}

public final IASTExpression buildExpression(BinaryOperator leftChain, IASTInitializerClause expr) {
public IASTExpression buildExpression(BinaryOperator leftChain, IASTInitializerClause expr) {
BinaryOperator rightChain = null;
for (;;) {
if (leftChain == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public interface ITypeMarshalBuffer {
EVAL_FUNCTION_SET = 0x09, EVAL_ID = 0x0A, EVAL_INIT_LIST = 0x0B, EVAL_MEMBER_ACCESS = 0x0C,
EVAL_PACK_EXPANSION = 0x0D, EVAL_TYPE_ID = 0x0E, EVAL_UNARY = 0x0F, EVAL_UNARY_TYPE_ID = 0x10,
EVAL_CONSTRUCTOR = 0x11, EVAL_REFERENCE = 0x12, EVAL_POINTER = 0x13, EVAL_COMPOSITE_ACCESS = 0x14,
EVAL_NARY_TYPE_ID = 0x15;
EVAL_NARY_TYPE_ID = 0x15, EVAL_FOLD_EXPRESSION = 0x16;
// Can add more evaluations up to 0x1C, after that it will collide with TypeMarshalBuffer.UNSTORABLE_TYPE.

final static byte EXEC_COMPOUND_STATEMENT = 0x01, EXEC_BREAK = 0x02, EXEC_CASE = 0x03, EXEC_CONTINUE = 0x04,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
/*******************************************************************************
* Copyright (c) 2022 Igor V. Kovalenko.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Igor V. Kovalenko - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;

import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;

import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTImplicitDestructorName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFoldExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTPackExpansionExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.DestructorCallCollector;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFoldExpression;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalPackExpansion;

public class CPPASTFoldExpression extends ASTNode implements ICPPASTFoldExpression, IASTAmbiguityParent {
private final int fOperator;
private final boolean fIsComma;
private ICPPASTExpression fLhs;
private ICPPASTExpression fRhs;
private ICPPEvaluation fEvaluation;

private IASTImplicitDestructorName[] fImplicitDestructorNames;

public CPPASTFoldExpression(int operator, boolean isComma, IASTExpression lhs, IASTExpression rhs) {
fOperator = operator;
fIsComma = isComma;
setOperand1(lhs);
setOperand2(rhs);
}

private void setOperand1(IASTExpression expression) {
assertNotFrozen();
if (expression != null) {
if (!(expression instanceof ICPPASTExpression)) {
throw new IllegalArgumentException(expression.getClass().getName());
}

expression.setParent(this);
}
fLhs = (ICPPASTExpression) expression;
}

public void setOperand2(IASTExpression operand) {
assertNotFrozen();
if (operand != null) {
if (!(operand instanceof ICPPASTExpression)) {
throw new IllegalArgumentException(operand.getClass().getName());
}
operand.setParent(this);
}
fRhs = (ICPPASTExpression) operand;
}

@Override
public IASTExpression copy() {
return copy(CopyStyle.withoutLocations);
}

@Override
public IASTExpression copy(CopyStyle style) {
IASTExpression fLhsCopy = fLhs == null ? null : fLhs.copy(style);
IASTExpression fRhsCopy = fRhs == null ? null : fRhs.copy(style);

CPPASTFoldExpression copy = new CPPASTFoldExpression(fOperator, fIsComma, fLhsCopy, fRhsCopy);
return copy(copy, style);
}

@Override
public ICPPEvaluation getEvaluation() {
if (fEvaluation == null) {
fEvaluation = computeEvaluation();
}

return fEvaluation;
}

private final class UnexpandedParameterPackCounter extends ASTVisitor {
int count;

public UnexpandedParameterPackCounter() {
super(false);
shouldVisitExpressions = true;
count = 0;
}

public int getCount() {
return count;
}

@Override
public int visit(IASTExpression expression) {
if (expression instanceof ICPPASTPackExpansionExpression) {
return PROCESS_SKIP;
}

IType type = expression.getExpressionType();
if (type instanceof ICPPParameterPackType) {
++count;
}
return PROCESS_CONTINUE;
}
}

private int countUnexpandedParameterPacks(IASTExpression e) {
if (e == null) {
return 0;
}
UnexpandedParameterPackCounter counter = new UnexpandedParameterPackCounter();
e.accept(counter);
return counter.getCount();
}

private ICPPEvaluation computeEvaluation() {
int lhsParameterPackCount = countUnexpandedParameterPacks(fLhs);
int rhsParameterPackCount = countUnexpandedParameterPacks(fRhs);

// Either left or right hand side expression shall contain an unexpanded parameter pack,
// but not both.
if (!((lhsParameterPackCount != 0) ^ (rhsParameterPackCount != 0))) {
return EvalFixed.INCOMPLETE;
}

ICPPEvaluation packEval;
ICPPEvaluation initEval;
boolean isLeftFold;

ICPPEvaluation evalL = fLhs == null ? null : fLhs.getEvaluation();
ICPPEvaluation evalR = fRhs == null ? null : fRhs.getEvaluation();

if (lhsParameterPackCount == 0) {
isLeftFold = true;
initEval = evalL;
packEval = evalR;
} else {
isLeftFold = false;
initEval = evalR;
packEval = evalL;
}

ICPPEvaluation[] foldPattern = new ICPPEvaluation[] { new EvalPackExpansion(packEval, this) };
return new EvalFoldExpression(fOperator, fIsComma, isLeftFold, foldPattern, initEval, this);
}

@Override
public IType getExpressionType() {
return CPPEvaluation.getType(this);
}

@Override
public boolean isLValue() {
return getValueCategory() == LVALUE;
}

@Override
public ValueCategory getValueCategory() {
return CPPEvaluation.getValueCategory(this);
}

@Override
public IASTImplicitDestructorName[] getImplicitDestructorNames() {
if (fImplicitDestructorNames == null) {
fImplicitDestructorNames = DestructorCallCollector.getTemporariesDestructorCalls(this);
}

return fImplicitDestructorNames;
}

@Override
public boolean accept(ASTVisitor action) {
if (action.shouldVisitExpressions) {
switch (action.visit(this)) {
case ASTVisitor.PROCESS_ABORT:
return false;
case ASTVisitor.PROCESS_SKIP:
return true;
default:
break;
}
}

if (fLhs != null && !fLhs.accept(action)) {
return false;
}

if (fRhs != null && !fRhs.accept(action)) {
return false;
}

if (action.shouldVisitExpressions && action.leave(this) == ASTVisitor.PROCESS_ABORT) {
return false;
}

return true;
}

@Override
public void replace(IASTNode child, IASTNode other) {
if (child == fLhs) {
other.setPropertyInParent(child.getPropertyInParent());
other.setParent(child.getParent());
fLhs = (ICPPASTExpression) other;
}
if (child == fRhs) {
other.setPropertyInParent(child.getPropertyInParent());
other.setParent(child.getParent());
fRhs = (ICPPASTExpression) other;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldDesignator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFoldExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTForStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
Expand Down Expand Up @@ -565,6 +566,12 @@ public ICPPASTLambdaExpression newLambdaExpression() {
return new CPPASTLambdaExpression();
}

@Override
public ICPPASTFoldExpression newFoldExpression(int operator, boolean fIsComma, IASTExpression lhs,
IASTExpression rhs) {
return new CPPASTFoldExpression(operator, fIsComma, lhs, rhs);
}

@Override
public ICPPASTLinkageSpecification newLinkageSpecification(String literal) {
return new CPPASTLinkageSpecification(literal);
Expand Down

0 comments on commit be56c19

Please sign in to comment.