mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-10 09:45:39 +02:00
Add c++17 fold expression
This commit is contained in:
parent
eb083f8cdd
commit
f2f862351e
11 changed files with 1096 additions and 7 deletions
|
@ -0,0 +1,125 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2023 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.parser.tests.ast2.cxx17;
|
||||
|
||||
import static org.eclipse.cdt.core.parser.ParserLanguage.CPP;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTProblemStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
|
||||
import org.eclipse.cdt.core.parser.tests.ast2.AST2CPPTestBase;
|
||||
|
||||
/**
|
||||
* AST tests for C++17 fold expressions.
|
||||
*/
|
||||
public class FoldExpressionTests extends AST2CPPTestBase {
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// template <typename CharT>
|
||||
// struct ostream {
|
||||
// template <typename T>
|
||||
// ostream& operator<<(T);
|
||||
//
|
||||
// ostream& operator<<(ostream&(*)(ostream&));
|
||||
// };
|
||||
//
|
||||
// template <typename CharT>
|
||||
// ostream<CharT>& endl(ostream<CharT>&);
|
||||
//
|
||||
// template <typename... T>
|
||||
// void sum(T... vals) {
|
||||
// ostream<char> out;
|
||||
// out << (... + vals) << endl;
|
||||
// }
|
||||
public void testFoldExpressionInBinaryExpression() throws Exception {
|
||||
parseAndCheckBindings();
|
||||
}
|
||||
|
||||
// template<typename... T>
|
||||
// void sum(T... vals) {
|
||||
// bar(... + vals);
|
||||
// }
|
||||
public void testFoldExpressionRecognition1() throws Exception {
|
||||
final String code = getAboveComment();
|
||||
IASTTranslationUnit tu = parse(code, CPP, false, false);
|
||||
ICPPASTTemplateDeclaration tdef = getDeclaration(tu, 0);
|
||||
IASTFunctionDefinition fdef = (IASTFunctionDefinition) tdef.getDeclaration();
|
||||
IASTProblemStatement p1 = getStatement(fdef, 0);
|
||||
}
|
||||
|
||||
// template<typename... T>
|
||||
// void sum(T... vals) {
|
||||
// ... + vals;
|
||||
// }
|
||||
public void testFoldExpressionRecognition2() throws Exception {
|
||||
final String code = getAboveComment();
|
||||
IASTTranslationUnit tu = parse(code, CPP, false, false);
|
||||
ICPPASTTemplateDeclaration tdef = getDeclaration(tu, 0);
|
||||
IASTFunctionDefinition fdef = (IASTFunctionDefinition) tdef.getDeclaration();
|
||||
IASTProblemStatement p1 = getStatement(fdef, 0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Fold expression, introduced in C++17.
|
||||
*
|
||||
* @since 8.0
|
||||
* @noextend This interface is not intended to be extended by clients.
|
||||
* @noimplement This interface is not intended to be implemented by clients.
|
||||
*/
|
||||
|
||||
public interface ICPPASTFoldExpression extends ICPPASTExpression {
|
||||
|
||||
}
|
|
@ -242,6 +242,17 @@ public interface ICPPNodeFactory extends INodeFactory {
|
|||
*/
|
||||
public ICPPASTLambdaExpression newLambdaExpression();
|
||||
|
||||
/**
|
||||
* @since 8.0
|
||||
*/
|
||||
public IASTExpression newFoldExpressionToken();
|
||||
|
||||
/**
|
||||
* @since 8.0
|
||||
*/
|
||||
public ICPPASTFoldExpression newFoldExpression(int opToken, boolean isComma, IASTExpression lhs,
|
||||
IASTExpression rhs);
|
||||
|
||||
public ICPPASTLinkageSpecification newLinkageSpecification(String literal);
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1010,9 +1010,13 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
|||
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) {
|
||||
|
|
|
@ -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_PACK_ACCESS = 0x16;
|
||||
EVAL_NARY_TYPE_ID = 0x15, EVAL_PACK_ACCESS = 0x16, EVAL_FOLD_EXPRESSION = 0x17;
|
||||
// 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,
|
||||
|
|
|
@ -0,0 +1,232 @@
|
|||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Implementation for fold expressions.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2023 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 org.eclipse.cdt.core.dom.ast.IASTExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
|
||||
|
||||
/**
|
||||
* Represents <code>...</code> token in fold expression.
|
||||
*/
|
||||
public class CPPASTFoldExpressionToken extends ASTNode implements IASTExpression {
|
||||
|
||||
@Override
|
||||
public IType getExpressionType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLValue() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueCategory getValueCategory() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IASTExpression copy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IASTExpression copy(CopyStyle style) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -88,6 +88,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpressionList;
|
|||
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;
|
||||
|
@ -565,6 +566,17 @@ public class CPPNodeFactory extends NodeFactory implements ICPPNodeFactory {
|
|||
return new CPPASTLambdaExpression();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IASTExpression newFoldExpressionToken() {
|
||||
return new CPPASTFoldExpressionToken();
|
||||
}
|
||||
|
||||
@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);
|
||||
|
|
|
@ -64,6 +64,7 @@ import org.eclipse.cdt.core.dom.ast.IASTPointer;
|
|||
import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTProblem;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTProblemDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTProblemExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTProblemTypeId;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
|
||||
|
@ -104,6 +105,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression;
|
|||
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.ICPPASTFunctionDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier;
|
||||
|
@ -206,6 +208,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
private final boolean supportAutoTypeSpecifier;
|
||||
private final boolean supportUserDefinedLiterals;
|
||||
private final boolean supportGCCStyleDesignators;
|
||||
private final boolean supportFoldExpression;
|
||||
|
||||
private final IIndex index;
|
||||
protected ICPPASTTranslationUnit translationUnit;
|
||||
|
@ -243,6 +246,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
scanner.setSplitShiftROperator(true);
|
||||
fContextSensitiveTokens = createContextSensitiveTokenMap(config);
|
||||
additionalNumericalSuffixes = scanner.getAdditionalNumericLiteralSuffixes();
|
||||
supportFoldExpression = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -984,7 +988,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
* else where.
|
||||
*/
|
||||
private enum BinaryExprCtx {
|
||||
eInTemplateID, eNotInTemplateID
|
||||
eInTemplateID, eNotInTemplateID, eInPrimaryExpression
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1014,6 +1018,14 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
|
||||
IToken variantMark = mark();
|
||||
if (expr == null) {
|
||||
// Could be ellipsis of unary left fold expression
|
||||
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) {
|
||||
expr = (IASTExpression) e;
|
||||
|
@ -1022,7 +1034,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
|
||||
final Variant variant = (Variant) e;
|
||||
expr = variant.getExpression();
|
||||
variants.addBranchPoint(variant.getNext(), null, allowAssignment, conditionCount);
|
||||
variants.addBranchPoint(variant.getNext(), lastOperator, allowAssignment, conditionCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1199,7 +1211,12 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
if (lt1 != IToken.tCOLON && lt1 != IToken.tCOMMA)
|
||||
stopWithNextOperator = true;
|
||||
} else {
|
||||
Object e = castExpressionForBinaryExpression(strat);
|
||||
// Could be ellipsis of any right fold expression or ellipsis of binary left fold expression
|
||||
Object e = foldInsideExpression(ctx, strat, lt1);
|
||||
if (e == null) {
|
||||
e = castExpressionForBinaryExpression(strat);
|
||||
}
|
||||
|
||||
if (e instanceof IASTExpression) {
|
||||
expr = (IASTExpression) e;
|
||||
} else {
|
||||
|
@ -1259,6 +1276,134 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
return (ICPPASTExpression) buildExpression(lastOperator, expr);
|
||||
}
|
||||
|
||||
private int calculateFirstOffset(BinaryOperator leftChain, IASTInitializerClause expr) {
|
||||
int firstOffset = ((ASTNode) expr).getOffset();
|
||||
|
||||
while (leftChain != null) {
|
||||
expr = leftChain.getExpression();
|
||||
if (expr != null) {
|
||||
int exprOffset = ((ASTNode) expr).getOffset();
|
||||
if (firstOffset > exprOffset) {
|
||||
firstOffset = exprOffset;
|
||||
}
|
||||
}
|
||||
leftChain = leftChain.getNext();
|
||||
}
|
||||
|
||||
return firstOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final IASTExpression buildExpression(BinaryOperator leftChain, IASTInitializerClause expr) {
|
||||
if (supportFoldExpression && leftChain != null && expr != null) {
|
||||
int foldCount = 0;
|
||||
int foldOpToken = 0;
|
||||
|
||||
int firstOffset = calculateFirstOffset(leftChain, expr);
|
||||
int endOffset = calculateEndOffset(expr);
|
||||
|
||||
if (expr instanceof CPPASTFoldExpressionToken) {
|
||||
// unary right fold: (pack op ...)
|
||||
++foldCount;
|
||||
}
|
||||
|
||||
BinaryOperator prev = null;
|
||||
BinaryOperator foldOp = null;
|
||||
BinaryOperator foldOpPrev = null;
|
||||
|
||||
scanFoldExpressions: for (BinaryOperator op = leftChain; op != null; op = op.getNext()) {
|
||||
if (op.getExpression() instanceof CPPASTFoldExpressionToken) {
|
||||
if (++foldCount == 1) {
|
||||
foldOp = op;
|
||||
foldOpPrev = prev;
|
||||
} else {
|
||||
// only single fold token allowed
|
||||
foldOp = null;
|
||||
foldOpPrev = null;
|
||||
break scanFoldExpressions;
|
||||
}
|
||||
} else {
|
||||
prev = op;
|
||||
}
|
||||
}
|
||||
|
||||
if (foldCount == 1) {
|
||||
BinaryOperator rightChain;
|
||||
if (foldOp == null) {
|
||||
// unary right fold, remove expression and use left chain as is
|
||||
foldOpToken = leftChain.getOperatorToken();
|
||||
expr = null;
|
||||
rightChain = null;
|
||||
} else {
|
||||
foldOpToken = foldOp.getOperatorToken();
|
||||
|
||||
if (foldOpPrev != null) {
|
||||
// if fold token is not the rightmost one in original chain,
|
||||
// break the chain and move front part to the right
|
||||
foldOpPrev.setNext(null);
|
||||
rightChain = leftChain;
|
||||
} else {
|
||||
rightChain = null;
|
||||
}
|
||||
// move tail part to the left
|
||||
leftChain = foldOp.getNext();
|
||||
}
|
||||
|
||||
IASTExpression lhs = leftChain == null ? null
|
||||
: super.buildExpression(leftChain.getNext(), leftChain.getExpression());
|
||||
IASTExpression rhs = super.buildExpression(rightChain, expr);
|
||||
|
||||
return buildFoldExpression(foldOpToken, lhs, rhs, firstOffset, endOffset);
|
||||
} else if (foldCount > 1) {
|
||||
IASTProblem problem = createProblem(IProblem.SYNTAX_ERROR, firstOffset, endOffset - firstOffset);
|
||||
IASTProblemExpression pexpr = getNodeFactory().newProblemExpression(problem);
|
||||
((ASTNode) pexpr).setOffsetAndLength(((ASTNode) problem));
|
||||
return pexpr;
|
||||
}
|
||||
}
|
||||
|
||||
return super.buildExpression(leftChain, expr);
|
||||
}
|
||||
|
||||
private IASTExpression foldStartingExpression(final BinaryExprCtx ctx, ITemplateIdStrategy strat)
|
||||
throws EndOfFileException, BacktrackException {
|
||||
|
||||
if (supportFoldExpression && ctx == BinaryExprCtx.eInPrimaryExpression) {
|
||||
if (LTcatchEOF(1) == IToken.tELLIPSIS) {
|
||||
int rightOpToken = LTcatchEOF(2);
|
||||
if (allowedFoldExpressionOpToken(rightOpToken)) {
|
||||
// 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) {
|
||||
|
@ -1315,6 +1460,124 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
return result;
|
||||
}
|
||||
|
||||
private IASTExpression buildFoldExpressionToken(int firstOffset, int lastOffset) {
|
||||
IASTExpression result = getNodeFactory().newFoldExpressionToken();
|
||||
((ASTNode) result).setOffsetAndLength(firstOffset, lastOffset - firstOffset);
|
||||
return result;
|
||||
}
|
||||
|
||||
private ICPPASTFoldExpression buildFoldExpression(int opToken, IASTExpression expr1, IASTExpression expr2,
|
||||
int firstOffset, int lastOffset) {
|
||||
int op = 0;
|
||||
boolean isComma = false;
|
||||
|
||||
switch (opToken) {
|
||||
case IToken.tPLUS:
|
||||
op = IASTBinaryExpression.op_plus;
|
||||
break;
|
||||
case IToken.tMINUS:
|
||||
op = IASTBinaryExpression.op_minus;
|
||||
break;
|
||||
case IToken.tSTAR:
|
||||
op = IASTBinaryExpression.op_multiply;
|
||||
break;
|
||||
case IToken.tDIV:
|
||||
op = IASTBinaryExpression.op_divide;
|
||||
break;
|
||||
case IToken.tMOD:
|
||||
op = IASTBinaryExpression.op_modulo;
|
||||
break;
|
||||
case IToken.tXOR:
|
||||
op = IASTBinaryExpression.op_binaryXor;
|
||||
break;
|
||||
case IToken.tAMPER:
|
||||
op = IASTBinaryExpression.op_binaryAnd;
|
||||
break;
|
||||
case IToken.tBITOR:
|
||||
op = IASTBinaryExpression.op_binaryOr;
|
||||
break;
|
||||
case IToken.tASSIGN:
|
||||
op = IASTBinaryExpression.op_assign;
|
||||
break;
|
||||
case IToken.tLT:
|
||||
op = IASTBinaryExpression.op_lessThan;
|
||||
break;
|
||||
case IToken.tGT:
|
||||
op = IASTBinaryExpression.op_greaterThan;
|
||||
break;
|
||||
case IToken.tSHIFTL:
|
||||
op = IASTBinaryExpression.op_shiftLeft;
|
||||
break;
|
||||
case IToken.tSHIFTR:
|
||||
op = IASTBinaryExpression.op_shiftRight;
|
||||
break;
|
||||
case IToken.tPLUSASSIGN:
|
||||
op = IASTBinaryExpression.op_plusAssign;
|
||||
break;
|
||||
case IToken.tMINUSASSIGN:
|
||||
op = IASTBinaryExpression.op_minusAssign;
|
||||
break;
|
||||
case IToken.tSTARASSIGN:
|
||||
op = IASTBinaryExpression.op_multiplyAssign;
|
||||
break;
|
||||
case IToken.tDIVASSIGN:
|
||||
op = IASTBinaryExpression.op_divideAssign;
|
||||
break;
|
||||
case IToken.tMODASSIGN:
|
||||
op = IASTBinaryExpression.op_moduloAssign;
|
||||
break;
|
||||
case IToken.tXORASSIGN:
|
||||
op = IASTBinaryExpression.op_binaryXorAssign;
|
||||
break;
|
||||
case IToken.tAMPERASSIGN:
|
||||
op = IASTBinaryExpression.op_binaryAndAssign;
|
||||
break;
|
||||
case IToken.tBITORASSIGN:
|
||||
op = IASTBinaryExpression.op_binaryOrAssign;
|
||||
break;
|
||||
case IToken.tSHIFTLASSIGN:
|
||||
op = IASTBinaryExpression.op_shiftLeftAssign;
|
||||
break;
|
||||
case IToken.tSHIFTRASSIGN:
|
||||
op = IASTBinaryExpression.op_shiftRightAssign;
|
||||
break;
|
||||
case IToken.tEQUAL:
|
||||
op = IASTBinaryExpression.op_equals;
|
||||
break;
|
||||
case IToken.tNOTEQUAL:
|
||||
op = IASTBinaryExpression.op_notequals;
|
||||
break;
|
||||
case IToken.tLTEQUAL:
|
||||
op = IASTBinaryExpression.op_lessEqual;
|
||||
break;
|
||||
case IToken.tGTEQUAL:
|
||||
op = IASTBinaryExpression.op_greaterEqual;
|
||||
break;
|
||||
case IToken.tAND:
|
||||
op = IASTBinaryExpression.op_logicalAnd;
|
||||
break;
|
||||
case IToken.tOR:
|
||||
op = IASTBinaryExpression.op_logicalOr;
|
||||
break;
|
||||
case IToken.tCOMMA:
|
||||
isComma = true;
|
||||
break;
|
||||
case IToken.tDOTSTAR:
|
||||
op = IASTBinaryExpression.op_pmdot;
|
||||
break;
|
||||
case IToken.tARROWSTAR:
|
||||
op = IASTBinaryExpression.op_pmarrow;
|
||||
break;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
ICPPASTFoldExpression result = getNodeFactory().newFoldExpression(op, isComma, expr1, expr2);
|
||||
((ASTNode) result).setOffsetAndLength(firstOffset, lastOffset - firstOffset);
|
||||
return result;
|
||||
}
|
||||
|
||||
private ICPPASTExpression throwExpression() throws EndOfFileException, BacktrackException {
|
||||
IToken throwToken = consume();
|
||||
IASTExpression throwExpression = null;
|
||||
|
@ -2016,12 +2279,13 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
literalExpr = getNodeFactory().newLiteralExpression(IASTLiteralExpression.lk_this, t.getImage());
|
||||
return setRange(literalExpr, t.getOffset(), t.getEndOffset());
|
||||
case IToken.tLPAREN:
|
||||
// ( expression ) or fold-expression
|
||||
if (supportStatementsInExpressions && LT(2) == IToken.tLBRACE) {
|
||||
return compoundStatementExpression();
|
||||
}
|
||||
t = consume();
|
||||
int finalOffset = 0;
|
||||
IASTExpression lhs = expression(ExprKind.eExpression, BinaryExprCtx.eNotInTemplateID, null, null); // instead of expression(), to keep the stack smaller
|
||||
IASTExpression lhs = expression(ExprKind.eExpression, BinaryExprCtx.eInPrimaryExpression, null, null); // instead of expression(), to keep the stack smaller
|
||||
switch (LT(1)) {
|
||||
case IToken.tRPAREN:
|
||||
case IToken.tEOC:
|
||||
|
@ -2030,7 +2294,11 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
default:
|
||||
throwBacktrack(LA(1));
|
||||
}
|
||||
return buildUnaryExpression(IASTUnaryExpression.op_bracketedPrimary, lhs, t.getOffset(), finalOffset);
|
||||
if (lhs instanceof ICPPASTFoldExpression) {
|
||||
return setRange(lhs, t.getOffset(), finalOffset);
|
||||
} else {
|
||||
return buildUnaryExpression(IASTUnaryExpression.op_bracketedPrimary, lhs, t.getOffset(), finalOffset);
|
||||
}
|
||||
case IToken.tIDENTIFIER:
|
||||
case IToken.tCOLONCOLON:
|
||||
case IToken.t_operator:
|
||||
|
@ -2090,6 +2358,47 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
return setRange(r, t.getOffset(), t.getEndOffset());
|
||||
}
|
||||
|
||||
private boolean allowedFoldExpressionOpToken(int opToken) {
|
||||
switch (opToken) {
|
||||
case IToken.tPLUS:
|
||||
case IToken.tMINUS:
|
||||
case IToken.tSTAR:
|
||||
case IToken.tDIV:
|
||||
case IToken.tMOD:
|
||||
case IToken.tXOR:
|
||||
case IToken.tAMPER:
|
||||
case IToken.tBITOR:
|
||||
case IToken.tASSIGN:
|
||||
case IToken.tLT:
|
||||
case IToken.tGT:
|
||||
case IToken.tSHIFTL:
|
||||
case IToken.tSHIFTR:
|
||||
case IToken.tPLUSASSIGN:
|
||||
case IToken.tMINUSASSIGN:
|
||||
case IToken.tSTARASSIGN:
|
||||
case IToken.tDIVASSIGN:
|
||||
case IToken.tMODASSIGN:
|
||||
case IToken.tXORASSIGN:
|
||||
case IToken.tAMPERASSIGN:
|
||||
case IToken.tBITORASSIGN:
|
||||
case IToken.tSHIFTLASSIGN:
|
||||
case IToken.tSHIFTRASSIGN:
|
||||
case IToken.tEQUAL:
|
||||
case IToken.tNOTEQUAL:
|
||||
case IToken.tLTEQUAL:
|
||||
case IToken.tGTEQUAL:
|
||||
case IToken.tAND:
|
||||
case IToken.tOR:
|
||||
case IToken.tCOMMA:
|
||||
case IToken.tDOTSTAR:
|
||||
case IToken.tARROWSTAR:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private IASTExpression lambdaExpression() throws EndOfFileException, BacktrackException {
|
||||
final int offset = LA().getOffset();
|
||||
|
||||
|
|
|
@ -0,0 +1,318 @@
|
|||
/*******************************************************************************
|
||||
* 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.semantics;
|
||||
|
||||
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.PRVALUE;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.IType;
|
||||
import org.eclipse.cdt.core.dom.ast.IValue;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
|
||||
import org.eclipse.cdt.core.parser.util.ArrayUtil;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.InstantiationContext;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
|
||||
public class EvalFoldExpression extends CPPDependentEvaluation {
|
||||
private static final EvalFixed EVAL_TRUE = new EvalFixed(CPPBasicType.BOOLEAN, PRVALUE, IntegralValue.create(true));
|
||||
private static final EvalFixed EVAL_FALSE = new EvalFixed(CPPBasicType.BOOLEAN, PRVALUE,
|
||||
IntegralValue.create(false));
|
||||
/*private static final EvalFixed EVAL_VOID = new EvalFixed(CPPBasicType.VOID, PRVALUE,
|
||||
IntegralValue.create(0));*/
|
||||
|
||||
private final int fOperator;
|
||||
private final boolean fIsComma;
|
||||
private final boolean fIsLeftFold;
|
||||
private ICPPEvaluation[] fPackEvals;
|
||||
private ICPPEvaluation fInitEval;
|
||||
|
||||
private IType fType;
|
||||
|
||||
private boolean fCheckedIsConstantExpression;
|
||||
private boolean fIsConstantExpression;
|
||||
private ICPPEvaluation fEvaluation;
|
||||
|
||||
public EvalFoldExpression(int operator, boolean isComma, boolean isLeftFold, ICPPEvaluation[] packEvals,
|
||||
ICPPEvaluation initEval, IASTNode pointOfDefinition) {
|
||||
this(operator, isComma, isLeftFold, packEvals, initEval, findEnclosingTemplate(pointOfDefinition));
|
||||
}
|
||||
|
||||
public EvalFoldExpression(int operator, boolean isComma, boolean isLeftFold, ICPPEvaluation[] packEvals,
|
||||
ICPPEvaluation initEval, IBinding templateDefinition) {
|
||||
super(templateDefinition);
|
||||
fOperator = operator;
|
||||
fIsComma = isComma;
|
||||
fIsLeftFold = isLeftFold;
|
||||
fPackEvals = packEvals;
|
||||
fInitEval = initEval;
|
||||
}
|
||||
|
||||
public int getOperator() {
|
||||
return fOperator;
|
||||
}
|
||||
|
||||
public ICPPEvaluation getInitExpression() {
|
||||
return fInitEval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitializerList() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFunctionSet() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeDependent() {
|
||||
if (fType != null) {
|
||||
return fType instanceof TypeOfDependentExpression;
|
||||
}
|
||||
return containsDependentType(fPackEvals) || (fInitEval != null && fInitEval.isTypeDependent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValueDependent() {
|
||||
return containsDependentValue(fPackEvals) || (fInitEval != null && fInitEval.isValueDependent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantExpression() {
|
||||
if (!fCheckedIsConstantExpression) {
|
||||
fCheckedIsConstantExpression = true;
|
||||
fIsConstantExpression = computeIsConstantExpression();
|
||||
}
|
||||
return fIsConstantExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEquivalentTo(ICPPEvaluation other) {
|
||||
if (!(other instanceof EvalFoldExpression)) {
|
||||
return false;
|
||||
}
|
||||
EvalFoldExpression o = (EvalFoldExpression) other;
|
||||
return fOperator == o.fOperator && fIsComma == o.fIsComma && fIsLeftFold == o.fIsLeftFold
|
||||
&& fPackEvals == o.fPackEvals
|
||||
&& (fInitEval == null ? o.fInitEval == null : fInitEval.isEquivalentTo(o.fInitEval));
|
||||
}
|
||||
|
||||
private boolean computeIsConstantExpression() {
|
||||
return areAllConstantExpressions(fPackEvals) && (fInitEval == null || fInitEval.isConstantExpression());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IType getType() {
|
||||
if (fType == null) {
|
||||
if (isTypeDependent()) {
|
||||
fType = new TypeOfDependentExpression(this);
|
||||
} else {
|
||||
fType = computeEvaluation().getType();
|
||||
}
|
||||
}
|
||||
return fType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IValue getValue() {
|
||||
ICPPEvaluation evaluation = computeEvaluation();
|
||||
return evaluation.getValue();
|
||||
}
|
||||
|
||||
private ICPPEvaluation computeEvaluation() {
|
||||
if (fEvaluation == null) {
|
||||
if (fInitEval == null && fPackEvals.length == 0) {
|
||||
// unary fold with empty pack
|
||||
if (fIsComma) {
|
||||
// expression: void(), cannot evaluate
|
||||
fEvaluation = EvalFixed.INCOMPLETE;
|
||||
} else if (fOperator == IASTBinaryExpression.op_logicalAnd) {
|
||||
// expression: true
|
||||
fEvaluation = EVAL_TRUE;
|
||||
} else if (fOperator == IASTBinaryExpression.op_logicalOr) {
|
||||
// expression: false
|
||||
fEvaluation = EVAL_FALSE;
|
||||
} else {
|
||||
// error, cannot evaluate
|
||||
fEvaluation = EvalFixed.INCOMPLETE;
|
||||
}
|
||||
} else {
|
||||
// For right fold the expanded pack array is already reversed by instantiate()
|
||||
if (fIsComma) {
|
||||
int offset = 0;
|
||||
ICPPEvaluation[] evals;
|
||||
|
||||
if (fInitEval != null) {
|
||||
evals = new ICPPEvaluation[fPackEvals.length + 1];
|
||||
if (fIsLeftFold) {
|
||||
evals[0] = fInitEval;
|
||||
offset = 1;
|
||||
} else {
|
||||
evals[fPackEvals.length] = fInitEval;
|
||||
offset = 0;
|
||||
}
|
||||
} else {
|
||||
evals = new ICPPEvaluation[fPackEvals.length];
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
for (ICPPEvaluation packElement : fPackEvals) {
|
||||
evals[offset++] = packElement;
|
||||
}
|
||||
|
||||
fEvaluation = new EvalComma(evals, getTemplateDefinition());
|
||||
} else {
|
||||
|
||||
ICPPEvaluation folded = fInitEval;
|
||||
|
||||
for (ICPPEvaluation packElement : fPackEvals) {
|
||||
if (folded == null) {
|
||||
folded = packElement;
|
||||
} else {
|
||||
if (fIsLeftFold) {
|
||||
folded = new EvalBinary(fOperator, folded, packElement, getTemplateDefinition());
|
||||
} else {
|
||||
folded = new EvalBinary(fOperator, packElement, folded, getTemplateDefinition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fEvaluation = folded;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fEvaluation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueCategory getValueCategory() {
|
||||
return ValueCategory.PRVALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException {
|
||||
short firstBytes = ITypeMarshalBuffer.EVAL_FOLD_EXPRESSION;
|
||||
if (fIsComma) {
|
||||
firstBytes |= ITypeMarshalBuffer.FLAG1;
|
||||
}
|
||||
if (fIsLeftFold) {
|
||||
firstBytes |= ITypeMarshalBuffer.FLAG2;
|
||||
}
|
||||
buffer.putShort((byte) firstBytes);
|
||||
buffer.putInt(fOperator);
|
||||
buffer.putInt(fPackEvals.length);
|
||||
for (ICPPEvaluation arg : fPackEvals) {
|
||||
buffer.marshalEvaluation(arg, includeValue);
|
||||
}
|
||||
buffer.marshalEvaluation(fInitEval, includeValue);
|
||||
marshalTemplateDefinition(buffer);
|
||||
}
|
||||
|
||||
public static ICPPEvaluation unmarshal(short firstBytes, ITypeMarshalBuffer buffer) throws CoreException {
|
||||
boolean isComma = (firstBytes & ITypeMarshalBuffer.FLAG1) != 0;
|
||||
boolean isLeftFold = (firstBytes & ITypeMarshalBuffer.FLAG2) != 0;
|
||||
int operator = buffer.getInt();
|
||||
int len = buffer.getInt();
|
||||
ICPPEvaluation[] packEvals = new ICPPEvaluation[len];
|
||||
for (int i = 0; i < packEvals.length; i++) {
|
||||
packEvals[i] = buffer.unmarshalEvaluation();
|
||||
}
|
||||
ICPPEvaluation initEval = buffer.unmarshalEvaluation();
|
||||
IBinding templateDefinition = buffer.unmarshalBinding();
|
||||
|
||||
return new EvalFoldExpression(operator, isComma, isLeftFold, packEvals, initEval, templateDefinition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPEvaluation instantiate(InstantiationContext context, int maxDepth) {
|
||||
ICPPEvaluation[] packEvals = instantiateExpressions(fPackEvals, context, maxDepth);
|
||||
ICPPEvaluation initEval = fInitEval == null ? null : fInitEval.instantiate(context, maxDepth);
|
||||
|
||||
if (packEvals == fPackEvals && initEval == fInitEval) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (!fIsLeftFold) {
|
||||
ArrayUtil.reverse(packEvals);
|
||||
}
|
||||
|
||||
return new EvalFoldExpression(fOperator, fIsComma, fIsLeftFold, packEvals, initEval, getTemplateDefinition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPEvaluation computeForFunctionCall(ActivationRecord record, ConstexprEvaluationContext context) {
|
||||
if (context.getStepsPerformed() >= ConstexprEvaluationContext.MAX_CONSTEXPR_EVALUATION_STEPS) {
|
||||
return EvalFixed.INCOMPLETE;
|
||||
}
|
||||
|
||||
ICPPEvaluation[] packEvals = new ICPPEvaluation[fPackEvals.length];
|
||||
|
||||
for (int i = 0; i < fPackEvals.length; i++) {
|
||||
ICPPEvaluation arg = fPackEvals[i].computeForFunctionCall(record, context.recordStep());
|
||||
packEvals[i] = arg;
|
||||
}
|
||||
|
||||
ICPPEvaluation initEval = fInitEval == null ? null
|
||||
: fInitEval.computeForFunctionCall(record, context.recordStep());
|
||||
|
||||
if (packEvals == fPackEvals && initEval == fInitEval) {
|
||||
return this;
|
||||
}
|
||||
|
||||
return new EvalFoldExpression(fOperator, fIsComma, fIsLeftFold, packEvals, initEval, getTemplateDefinition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int determinePackSize(ICPPTemplateParameterMap tpMap) {
|
||||
int r = CPPTemplates.PACK_SIZE_NOT_FOUND;
|
||||
for (ICPPEvaluation packElement : fPackEvals) {
|
||||
r = CPPTemplates.combinePackSize(r, packElement.determinePackSize(tpMap));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean referencesTemplateParameter() {
|
||||
for (ICPPEvaluation arg : fPackEvals) {
|
||||
if (arg.referencesTemplateParameter()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return fInitEval != null && fInitEval.referencesTemplateParameter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNoexcept() {
|
||||
for (int i = 0; i < fPackEvals.length; i++) {
|
||||
ICPPEvaluation eval = fPackEvals[i];
|
||||
if (!eval.isNoexcept()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (fInitEval != null) {
|
||||
return fInitEval.isNoexcept();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -130,6 +130,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalCompoundStatem
|
|||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalConditional;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalConstructor;
|
||||
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.EvalFunctionCall;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFunctionSet;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalID;
|
||||
|
@ -1729,6 +1730,8 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
|
|||
return EvalNaryTypeId.unmarshal(firstBytes, buffer);
|
||||
case ITypeMarshalBuffer.EVAL_PACK_ACCESS:
|
||||
return EvalPackAccess.unmarshal(firstBytes, buffer);
|
||||
case ITypeMarshalBuffer.EVAL_FOLD_EXPRESSION:
|
||||
return EvalFoldExpression.unmarshal(firstBytes, buffer);
|
||||
}
|
||||
throw new CoreException(CCorePlugin.createStatus("Cannot unmarshal an evaluation, first bytes=" + firstBytes)); //$NON-NLS-1$
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue