Skip to content

Commit

Permalink
Add basic support for c++20 three-way comparison operator
Browse files Browse the repository at this point in the history
  • Loading branch information
i-garrison authored and jonahgraham committed Jan 28, 2023
1 parent ccf8053 commit ff8ac10
Show file tree
Hide file tree
Showing 21 changed files with 96 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,18 @@ public class LexerTests extends BaseTestCase {
private static final LexerOptions DEFAULT_OPTIONS = new LexerOptions();
private static final LexerOptions NO_DOLLAR = new LexerOptions();
private static final LexerOptions NO_MINMAX = new LexerOptions();
private static final LexerOptions NO_MINMAX_CPP = new LexerOptions();
private static final LexerOptions SLASH_PERCENT = new LexerOptions();
private static final LexerOptions CPP_OPTIONS = new LexerOptions();
static {
NO_DOLLAR.fSupportDollarInIdentifiers = false;
NO_MINMAX.fSupportMinAndMax = false;
NO_MINMAX_CPP.fSupportMinAndMax = false;
NO_MINMAX_CPP.fSupportThreeWayComparisonOperator = true;
SLASH_PERCENT.fSupportSlashPercentComments = true;
CPP_OPTIONS.fSupportRawStringLiterals = true;
CPP_OPTIONS.fSupportDigitSeparators = true;
CPP_OPTIONS.fSupportThreeWayComparisonOperator = true;
}

static String TRIGRAPH_REPLACES_CHARS = "#^[]|{}~\\";
Expand Down Expand Up @@ -716,11 +720,26 @@ public void testOperatorAndPunctuators() throws Exception {
IToken.tGTEQUAL, IToken.tAND, IToken.tOR, IToken.tINCR, IToken.tDECR, IToken.tCOMMA, IToken.tARROWSTAR,
IToken.tARROW, IGCCToken.tMIN, IGCCToken.tMAX, Lexer.tOTHER_CHARACTER, };

verifyOperatorAndPunctuators(ops, tokens, DEFAULT_OPTIONS, NO_MINMAX);
}

public void testOperatorAndPunctuatorsCpp20() throws Exception {
final String ops = "<<>><<=>>===!=<=>>=<=&&";

final int[] tokens = new int[] { IToken.tSHIFTL, IToken.tSHIFTR, IToken.tSHIFTLASSIGN, IToken.tSHIFTRASSIGN,
IToken.tEQUAL, IToken.tNOTEQUAL, IToken.tTHREEWAYCOMPARISON, IToken.tGTEQUAL, IToken.tLTEQUAL,
IToken.tAND, };

verifyOperatorAndPunctuators(ops, tokens, CPP_OPTIONS, NO_MINMAX_CPP);
}

private void verifyOperatorAndPunctuators(String ops, int[] tokens, LexerOptions options,
LexerOptions optionsNoMinMax) throws Exception {
for (int splices = 0; splices < 9; splices++) {
for (int trigraphs = 0; trigraphs < 6; trigraphs++) {
StringBuilder buf = new StringBuilder();
String input = useTrigraphs(ops.toCharArray(), trigraphs);
init(instertLineSplices(input, splices));
init(instertLineSplices(input, splices), options);
for (int token2 : tokens) {
Token token = fLexer.currentToken();
buf.append(token.getCharImage());
Expand All @@ -729,7 +748,7 @@ public void testOperatorAndPunctuators() throws Exception {
eof();
assertEquals(ops, buf.toString()); // check token image

init(input, NO_MINMAX);
init(input, optionsNoMinMax);
for (int token : tokens) {
switch (token) {
case IGCCToken.tMIN:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,8 @@ public static char[] getBinaryOperatorString(IASTBinaryExpression be) {
return Keywords.cpEQUAL;
case IASTBinaryExpression.op_notequals:
return Keywords.cpNOTEQUAL;
case IASTBinaryExpression.op_threewaycomparison:
return Keywords.cpTHREEWAYCOMPARISON;
case IASTBinaryExpression.op_max:
return Keywords.cpMAX;
case IASTBinaryExpression.op_min:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1311,6 +1311,9 @@ public static String getBinaryOperatorString(IASTBinaryExpression be) {
case IASTBinaryExpression.op_notequals:
opString = String.valueOf(Keywords.cpNOTEQUAL);
break;
case IASTBinaryExpression.op_threewaycomparison:
opString = String.valueOf(Keywords.cpTHREEWAYCOMPARISON);
break;
case IASTBinaryExpression.op_max:
opString = String.valueOf(Keywords.cpMAX);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,13 @@ public interface IASTBinaryExpression extends IASTExpression {
*/
public static final int op_ellipses = 34;

/**
* For c++, only.
* <code>op_threewaycompare</code> represents <code><=></code> three-way comparison operator.
* @since 8.0
*/
public static final int op_threewaycomparison = 35;

/**
* Get the first operand.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ public interface IToken {
int tNOTEQUAL = 35;
int tNOT = 36;
int tEQUAL = 37;
/** @since 8.0 */
int tTHREEWAYCOMPARISON = 8001;
int tASSIGN = 38;
int tUNKNOWN_CHAR = 39;
int tSHIFTL = 40;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ public class Keywords {
public static final char[] cpNOTEQUAL = "!=".toCharArray();
public static final char[] cpNOT = "!".toCharArray();
public static final char[] cpEQUAL = "==".toCharArray();
public static final char[] cpTHREEWAYCOMPARISON = "<=>".toCharArray();
public static final char[] cpASSIGN = "=".toCharArray();
public static final char[] cpSHIFTL = "<<".toCharArray();
public static final char[] cpLTEQUAL = "<=".toCharArray();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,19 +224,21 @@ private int getPrecendence(IASTBinaryExpression r) {
case IASTBinaryExpression.op_max:
case IASTBinaryExpression.op_min:
return 7;
case IASTBinaryExpression.op_threewaycomparison:
return 8;
case IASTBinaryExpression.op_shiftLeft:
case IASTBinaryExpression.op_shiftRight:
return 8;
return 9;
case IASTBinaryExpression.op_plus:
case IASTBinaryExpression.op_minus:
return 9;
return 10;
case IASTBinaryExpression.op_multiply:
case IASTBinaryExpression.op_divide:
case IASTBinaryExpression.op_modulo:
return 10;
return 11;
case IASTBinaryExpression.op_pmarrow:
case IASTBinaryExpression.op_pmdot:
return 11;
return 12;
}
assert false;
return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1123,6 +1123,9 @@ private IASTExpression buildExpression(IASTExpression left, BinaryOperator opera
case IToken.tNOTEQUAL:
op = IASTBinaryExpression.op_notequals;
break;
case IToken.tTHREEWAYCOMPARISON:
op = IASTBinaryExpression.op_threewaycomparison;
break;
case IToken.tGT:
op = IASTBinaryExpression.op_greaterThan;
break;
Expand Down Expand Up @@ -2731,6 +2734,7 @@ protected boolean canBeCastExpression() throws EndOfFileException {
case IToken.tDOT:
case IToken.tDOTSTAR:
case IToken.tEQUAL:
case IToken.tTHREEWAYCOMPARISON:
case IToken.tGT:
case IToken.tGT_in_SHIFTR:
case IToken.tGTEQUAL:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,9 @@ private static IntegralValue applyBinaryOperator(final int op, final long v1, fi
case IASTBinaryExpression.op_greaterEqual:
value = v1 >= v2 ? 1l : 0l;
break;
case IASTBinaryExpression.op_threewaycomparison:
// TODO: implement for <=>
break;
case IASTBinaryExpression.op_binaryAnd:
value = v1 & v2;
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ protected Optional<Integer> rwInBinaryExpression(IASTNode node, IASTBinaryExpres
case IASTBinaryExpression.op_notequals:
case IASTBinaryExpression.op_shiftLeft:
case IASTBinaryExpression.op_shiftRight:
case IASTBinaryExpression.op_threewaycomparison:
return Optional.of(READ);

case IASTBinaryExpression.op_minus:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,10 @@ public IType getExpressionType() {
case op_notequals:
return new CBasicType(Kind.eInt, 0, this);

case op_threewaycomparison:
// TODO: implement for <=>
break;

case IASTBinaryExpression.op_plus:
if (type1 instanceof IArrayType) {
return Conversions.arrayTypeToPointerType((ICArrayType) type1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,7 @@ private IASTExpression expression(final ExprKind kind) throws EndOfFileException
break;
case IToken.tEQUAL:
case IToken.tNOTEQUAL:
case IToken.tTHREEWAYCOMPARISON:
lastOperator = new BinaryOperator(lastOperator, lastExpression, lt1, 80, 81);
break;
case IToken.tGT:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,7 @@ private ICPPASTExpression expression(final ExprKind kind, final BinaryExprCtx ct
break;
case IToken.tEQUAL:
case IToken.tNOTEQUAL:
case IToken.tTHREEWAYCOMPARISON:
lastOperator = new BinaryOperator(lastOperator, expr, lt1, 80, 81);
break;
case IToken.tGT:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ public enum OverloadableOperator {
GT(">"), LT("<"), NOT("!"), BITCOMPLEMENT("~"), BITOR("|"), AMPER("&"), XOR("^"), MOD("%"), DIV("/"), STAR("*"),
PLUS("+"), BRACKET("[]"), PAREN("()"), ARROW("->"), ARROWSTAR("->*"), COMMA(","), MINUS("-"), DECR("--"),
INCR("++"), OR("||"), AND("&&"), ASSIGN("="), GTEQUAL(">="), LTEQUAL("<="), NOTEQUAL("!="), EQUAL("=="),
SHIFTR(">>"), SHIFTL("<<"), SHIFTLASSIGN("<<="), SHIFTRASSIGN(">>="), BITORASSIGN("|="), AMPERASSIGN("&="),
XORASSIGN("^="), MODASSIGN("%="), DIVASSIGN("/="), STARASSIGN("*="), MINUSASSIGN("-="), PLUSASSIGN("+="),
NEW("new"), DELETE_ARRAY("delete[]"), DELETE("delete"), NEW_ARRAY("new[]"),
SHIFTR(">>"), SHIFTL("<<"), SHIFTLASSIGN("<<="), SHIFTRASSIGN(">>="), THREEWAYCOMPARISON("<=>"), BITORASSIGN("|="),
AMPERASSIGN("&="), XORASSIGN("^="), MODASSIGN("%="), DIVASSIGN("/="), STARASSIGN("*="), MINUSASSIGN("-="),
PLUSASSIGN("+="), NEW("new"), DELETE_ARRAY("delete[]"), DELETE("delete"), NEW_ARRAY("new[]"),

/**
* Cannot be overloaded by the user, however overload resolution needs to be performed.
Expand Down Expand Up @@ -155,6 +155,8 @@ public static OverloadableOperator valueOf(IToken token) {
return LT;
case IToken.tLTEQUAL:
return LTEQUAL;
case IToken.tTHREEWAYCOMPARISON:
return THREEWAYCOMPARISON;

// other
case IToken.tASSIGN:
Expand Down Expand Up @@ -247,6 +249,8 @@ public static OverloadableOperator fromBinaryExpression(int binaryOp) {
return LT;
case IASTBinaryExpression.op_lessEqual:
return LTEQUAL;
case IASTBinaryExpression.op_threewaycomparison:
return THREEWAYCOMPARISON;

// other
case IASTBinaryExpression.op_assign:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ private ICPPFunction[] create() {
comparison(true);
break;

case THREEWAYCOMPARISON:
// TODO: implement for <=>
break;

case GT:
case GTEQUAL:
case LT:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import static org.eclipse.cdt.core.dom.ast.IASTBinaryExpression.op_shiftLeftAssign;
import static org.eclipse.cdt.core.dom.ast.IASTBinaryExpression.op_shiftRight;
import static org.eclipse.cdt.core.dom.ast.IASTBinaryExpression.op_shiftRightAssign;
import static org.eclipse.cdt.core.dom.ast.IASTBinaryExpression.op_threewaycomparison;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.PRVALUE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.glvalueType;
Expand Down Expand Up @@ -388,6 +389,10 @@ public IType computeType() {
case op_notequals:
return CPPBasicType.BOOLEAN;

case op_threewaycomparison:
// TODO: implement for <=>
return ProblemType.UNKNOWN_FOR_EXPRESSION;

case op_plus:
if (type1 instanceof IPointerType) {
return ExpressionTypes.restoreTypedefs(type1, originalType1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ public class ExpressionWriter extends NodeWriter {
private static final String ELLIPSES = " ... "; //$NON-NLS-1$
private static final String NOT_EQUALS_OP = " != "; //$NON-NLS-1$
private static final String EQUALS_OP = " == "; //$NON-NLS-1$
private static final String THREEWAYCOMPARISON_OP = " <=> "; //$NON-NLS-1$
private static final String BINARY_OR_ASSIGN = " |= "; //$NON-NLS-1$
private static final String BINARY_XOR_ASSIGN_OP = " ^= "; //$NON-NLS-1$
private static final String BINARY_AND_ASSIGN_OP = " &= "; //$NON-NLS-1$
Expand Down Expand Up @@ -226,6 +227,8 @@ private String getBinaryExpressionOperator(int operator) {
return EQUALS_OP;
case IASTBinaryExpression.op_notequals:
return NOT_EQUALS_OP;
case IASTBinaryExpression.op_threewaycomparison:
return THREEWAYCOMPARISON_OP;
case ICPPASTBinaryExpression.op_pmdot:
return PMDOT_OP;
case ICPPASTBinaryExpression.op_pmarrow:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
private static final int ORIGIN_INACTIVE_CODE = OffsetLimitReachedException.ORIGIN_INACTIVE_CODE;

private static final char[] ONE = "1".toCharArray(); //$NON-NLS-1$
private static final char[] CPP_IMPL_THREE_WAY_COMPARISON = "__cpp_impl_three_way_comparison".toCharArray(); //$NON-NLS-1$

// Standard built-ins
private static final ObjectStyleMacro __CDT_PARSER__ = new ObjectStyleMacro("__CDT_PARSER__".toCharArray(), //$NON-NLS-1$
Expand Down Expand Up @@ -352,6 +353,10 @@ public CPreprocessor(FileContent fileContent, IScannerInfo info, ParserLanguage
fIncludeSearchPath = configureIncludeSearchPath(new File(contextPath).getParentFile(), info);
setupMacroDictionary(configuration, info, language);

if (fMacroDictionary.containsKey(CPP_IMPL_THREE_WAY_COMPARISON)) {
fLexOptions.fSupportThreeWayComparisonOperator = true;
}

ILocationCtx ctx = fLocationMap.pushTranslationUnit(fRootContent.getFileLocation(), fRootContent.getSource());
Lexer lexer = new Lexer(fRootContent.getSource(), fLexOptions, this, this);
fRootContext = fCurrentContext = new ScannerContext(ctx, null, lexer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public final static class LexerOptions implements Cloneable {
public boolean fSupportRawStringLiterals = false;
public boolean fSupportUserDefinedLiterals = false;
public boolean fSupportDigitSeparators = false;
public boolean fSupportThreeWayComparisonOperator = false;
public IncludeExportPatterns fIncludeExportPatterns;

@Override
Expand Down Expand Up @@ -641,7 +642,13 @@ private Token fetchToken() throws OffsetLimitReachedException {

switch (d) {
case '=':
nextCharPhase3();
final int se = nextCharPhase3();
if (fOptions.fSupportThreeWayComparisonOperator) {
if (se == '>') {
nextCharPhase3();
return newToken(IToken.tTHREEWAYCOMPARISON, start);
}
}
return newToken(IToken.tLTEQUAL, start);
case '<':
final int e = nextCharPhase3();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public static boolean isOperator(int kind) {
case IToken.tGTEQUAL:
case IToken.tLT:
case IToken.tLTEQUAL:
case IToken.tTHREEWAYCOMPARISON:

// other
case IToken.tASSIGN:
Expand Down Expand Up @@ -164,6 +165,8 @@ public static char[] getImage(int type) {
return Keywords.cpNOT;
case IToken.tEQUAL:
return Keywords.cpEQUAL;
case IToken.tTHREEWAYCOMPARISON:
return Keywords.cpTHREEWAYCOMPARISON;
case IToken.tASSIGN:
return Keywords.cpASSIGN;
case IToken.tSHIFTL:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,11 @@ public int leave(IASTExpression expression) {
}
}

if (binaryExpression.getOperator() == IASTBinaryExpression.op_threewaycomparison) {
// TODO: implement for three-way comparison operator x <=> y
return PROCESS_CONTINUE;
}

IType operand1Type = binaryExpression.getOperand1().getExpressionType();
IASTInitializerClause operand2 = binaryExpression.getInitOperand2();
IType operand2Type;
Expand Down

0 comments on commit ff8ac10

Please sign in to comment.