Cpp: support space ship operator in lexer

Fixes: QTCREATORBUG-27503
Change-Id: Idbff5a9b5b2e6e841e298ca6f706ef3c6aa1622b
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
David Schulz
2022-10-20 13:43:10 +02:00
parent c780151aec
commit 4e8b7eee9d
11 changed files with 93 additions and 49 deletions

View File

@@ -915,6 +915,10 @@ OperatorNameId::Kind Bind::cppOperator(OperatorAST *ast)
kind = OperatorNameId::ArrayAccessOp; kind = OperatorNameId::ArrayAccessOp;
break; break;
case T_LESS_EQUAL_GREATER:
kind = OperatorNameId::SpaceShipOp;
break;
default: default:
kind = OperatorNameId::InvalidOp; kind = OperatorNameId::InvalidOp;
} // switch } // switch

View File

@@ -612,7 +612,12 @@ void Lexer::scan_helper(Token *tok)
tok->f.kind = T_LESS_LESS; tok->f.kind = T_LESS_LESS;
} else if (_yychar == '=') { } else if (_yychar == '=') {
yyinp(); yyinp();
tok->f.kind = T_LESS_EQUAL; if (_languageFeatures.cxx20Enabled && _yychar == '>') {
yyinp();
tok->f.kind = T_LESS_EQUAL_GREATER;
} else {
tok->f.kind = T_LESS_EQUAL;
}
} else if (_yychar == ':') { } else if (_yychar == ':') {
if (*(_currentChar+1) != ':' || *(_currentChar+2) == ':' || *(_currentChar+2) == '>') { if (*(_currentChar+1) != ':' || *(_currentChar+2) == ':' || *(_currentChar+2) == '>') {
yyinp(); yyinp();

View File

@@ -180,7 +180,7 @@ public:
! = < > += -= *= /= %= ! = < > += -= *= /= %=
^= &= |= << >> >>= <<= == != ^= &= |= << >> >>= <<= == !=
<= >= && || ++ -- , ->* -> <= >= && || ++ -- , ->* ->
() [] () [] <=>
*/ */
enum Kind { enum Kind {
InvalidOp, InvalidOp,
@@ -225,7 +225,8 @@ public:
ArrowStarOp, ArrowStarOp,
ArrowOp, ArrowOp,
FunctionCallOp, FunctionCallOp,
ArrayAccessOp ArrayAccessOp,
SpaceShipOp
}; };
public: public:

View File

@@ -98,10 +98,11 @@ enum {
And = 8, And = 8,
Equality = 9, Equality = 9,
Relational = 10, Relational = 10,
Shift = 11, ThreeWayComp = 11,
Additive = 12, Shift = 12,
Multiplicative = 13, Additive = 13,
PointerToMember = 14 Multiplicative = 14,
PointerToMember = 15
}; };
} // namespace Precedece } // namespace Precedece
@@ -116,29 +117,30 @@ inline int precedence(int tokenKind, bool templateArguments)
return Prec::Assignment; return Prec::Assignment;
switch (tokenKind) { switch (tokenKind) {
case T_COMMA: return Prec::Comma; case T_COMMA: return Prec::Comma;
case T_QUESTION: return Prec::Conditional; case T_QUESTION: return Prec::Conditional;
case T_PIPE_PIPE: return Prec::LogicalOr; case T_PIPE_PIPE: return Prec::LogicalOr;
case T_AMPER_AMPER: return Prec::LogicalAnd; case T_AMPER_AMPER: return Prec::LogicalAnd;
case T_PIPE: return Prec::InclusiveOr; case T_PIPE: return Prec::InclusiveOr;
case T_CARET: return Prec::ExclusiveOr; case T_CARET: return Prec::ExclusiveOr;
case T_AMPER: return Prec::And; case T_AMPER: return Prec::And;
case T_EQUAL_EQUAL: case T_EQUAL_EQUAL:
case T_EXCLAIM_EQUAL: return Prec::Equality; case T_EXCLAIM_EQUAL: return Prec::Equality;
case T_GREATER: case T_GREATER:
case T_LESS: case T_LESS:
case T_LESS_EQUAL: case T_LESS_EQUAL:
case T_GREATER_EQUAL: return Prec::Relational; case T_GREATER_EQUAL: return Prec::Relational;
case T_LESS_EQUAL_GREATER: return Prec::ThreeWayComp;
case T_LESS_LESS: case T_LESS_LESS:
case T_GREATER_GREATER: return Prec::ExclusiveOr; case T_GREATER_GREATER: return Prec::ExclusiveOr;
case T_PLUS: case T_PLUS:
case T_MINUS: return Prec::Additive; case T_MINUS: return Prec::Additive;
case T_STAR: case T_STAR:
case T_SLASH: case T_SLASH:
case T_PERCENT: return Prec::Multiplicative; case T_PERCENT: return Prec::Multiplicative;
case T_ARROW_STAR: case T_ARROW_STAR:
case T_DOT_STAR: return Prec::PointerToMember; case T_DOT_STAR: return Prec::PointerToMember;
default: return Prec::Unknown; default: return Prec::Unknown;
} }
} }
@@ -1300,6 +1302,7 @@ bool Parser::parseOperator(OperatorAST *&node) // ### FIXME
case T_GREATER_EQUAL: case T_GREATER_EQUAL:
case T_GREATER_GREATER_EQUAL: case T_GREATER_GREATER_EQUAL:
case T_LESS_EQUAL: case T_LESS_EQUAL:
case T_LESS_EQUAL_GREATER:
case T_LESS_LESS_EQUAL: case T_LESS_LESS_EQUAL:
case T_MINUS_EQUAL: case T_MINUS_EQUAL:
case T_PERCENT_EQUAL: case T_PERCENT_EQUAL:

View File

@@ -91,6 +91,7 @@ const char *token_names[] = {
("<="), ("<="),
("<<"), ("<<"),
("<<="), ("<<="),
("<=>"),
("-"), ("-"),
("-="), ("-="),
("--"), ("--"),

View File

@@ -99,6 +99,7 @@ enum Kind {
T_LESS_EQUAL, T_LESS_EQUAL,
T_LESS_LESS, T_LESS_LESS,
T_LESS_LESS_EQUAL, T_LESS_LESS_EQUAL,
T_LESS_EQUAL_GREATER,
T_MINUS, T_MINUS,
T_MINUS_EQUAL, T_MINUS_EQUAL,
T_MINUS_MINUS, T_MINUS_MINUS,
@@ -446,6 +447,7 @@ struct LanguageFeatures
unsigned int cxxEnabled : 1; unsigned int cxxEnabled : 1;
unsigned int cxx11Enabled : 1; unsigned int cxx11Enabled : 1;
unsigned int cxx14Enabled : 1; unsigned int cxx14Enabled : 1;
unsigned int cxx20Enabled : 1;
unsigned int objCEnabled : 1; unsigned int objCEnabled : 1;
unsigned int c99Enabled : 1; unsigned int c99Enabled : 1;
}; };

View File

@@ -222,6 +222,9 @@ void NamePrettyPrinter::visit(const OperatorNameId *name)
case OperatorNameId::ArrayAccessOp: case OperatorNameId::ArrayAccessOp:
_name += QLatin1String("[]"); _name += QLatin1String("[]");
break; break;
case OperatorNameId::SpaceShipOp:
_name += QLatin1String("<=>");
break;
} // switch } // switch
} }

View File

@@ -202,6 +202,24 @@ struct Value
inline bool is_zero () const inline bool is_zero () const
{ return l == 0; } { return l == 0; }
template<typename T> static bool cmpImpl(T v1, T v2)
{
if (v1 < v2)
return -1;
if (v1 > v2)
return 1;
return 0;
}
Value cmp(const Value &other) const
{
Value v = *this;
if (v.is_ulong() || other.is_ulong())
v.set_long(cmpImpl(v.ul, other.ul));
else
v.set_long(cmpImpl(v.l, other.l));
return v;
}
#define PP_DEFINE_BIN_OP(name, op) \ #define PP_DEFINE_BIN_OP(name, op) \
inline Value operator op(const Value &other) const \ inline Value operator op(const Value &other) const \
{ \ { \
@@ -488,24 +506,25 @@ private:
inline int precedence(int tokenKind) const inline int precedence(int tokenKind) const
{ {
switch (tokenKind) { switch (tokenKind) {
case T_PIPE_PIPE: return 0; case T_PIPE_PIPE: return 0;
case T_AMPER_AMPER: return 1; case T_AMPER_AMPER: return 1;
case T_PIPE: return 2; case T_PIPE: return 2;
case T_CARET: return 3; case T_CARET: return 3;
case T_AMPER: return 4; case T_AMPER: return 4;
case T_EQUAL_EQUAL: case T_EQUAL_EQUAL:
case T_EXCLAIM_EQUAL: return 5; case T_EXCLAIM_EQUAL: return 5;
case T_GREATER: case T_GREATER:
case T_LESS: case T_LESS:
case T_LESS_EQUAL: case T_LESS_EQUAL:
case T_GREATER_EQUAL: return 6; case T_GREATER_EQUAL: return 6;
case T_LESS_EQUAL_GREATER: return 7;
case T_LESS_LESS: case T_LESS_LESS:
case T_GREATER_GREATER: return 7; case T_GREATER_GREATER: return 8;
case T_PLUS: case T_PLUS:
case T_MINUS: return 8; case T_MINUS: return 9;
case T_STAR: case T_STAR:
case T_SLASH: case T_SLASH:
case T_PERCENT: return 9; case T_PERCENT: return 10;
default: default:
return -1; return -1;
@@ -525,6 +544,7 @@ private:
case T_GREATER: case T_GREATER:
case T_LESS: case T_LESS:
case T_LESS_EQUAL: case T_LESS_EQUAL:
case T_LESS_EQUAL_GREATER:
case T_GREATER_EQUAL: case T_GREATER_EQUAL:
case T_LESS_LESS: case T_LESS_LESS:
case T_GREATER_GREATER: case T_GREATER_GREATER:
@@ -543,24 +563,25 @@ private:
static inline Value evaluate_expression(int tokenKind, const Value &lhs, const Value &rhs) static inline Value evaluate_expression(int tokenKind, const Value &lhs, const Value &rhs)
{ {
switch (tokenKind) { switch (tokenKind) {
case T_PIPE_PIPE: return lhs || rhs; case T_PIPE_PIPE: return lhs || rhs;
case T_AMPER_AMPER: return lhs && rhs; case T_AMPER_AMPER: return lhs && rhs;
case T_PIPE: return lhs | rhs; case T_PIPE: return lhs | rhs;
case T_CARET: return lhs ^ rhs; case T_CARET: return lhs ^ rhs;
case T_AMPER: return lhs & rhs; case T_AMPER: return lhs & rhs;
case T_EQUAL_EQUAL: return lhs == rhs; case T_EQUAL_EQUAL: return lhs == rhs;
case T_EXCLAIM_EQUAL: return lhs != rhs; case T_EXCLAIM_EQUAL: return lhs != rhs;
case T_GREATER: return lhs > rhs; case T_GREATER: return lhs > rhs;
case T_LESS: return lhs < rhs; case T_LESS: return lhs < rhs;
case T_LESS_EQUAL: return lhs <= rhs; case T_LESS_EQUAL: return lhs <= rhs;
case T_GREATER_EQUAL: return lhs >= rhs; case T_LESS_EQUAL_GREATER: return lhs.cmp(rhs);
case T_LESS_LESS: return lhs << rhs; case T_GREATER_EQUAL: return lhs >= rhs;
case T_GREATER_GREATER: return lhs >> rhs; case T_LESS_LESS: return lhs << rhs;
case T_PLUS: return lhs + rhs; case T_GREATER_GREATER: return lhs >> rhs;
case T_MINUS: return lhs - rhs; case T_PLUS: return lhs + rhs;
case T_STAR: return lhs * rhs; case T_MINUS: return lhs - rhs;
case T_SLASH: return rhs.is_zero() ? Value() : lhs / rhs; case T_STAR: return lhs * rhs;
case T_PERCENT: return rhs.is_zero() ? Value() : lhs % rhs; case T_SLASH: return rhs.is_zero() ? Value() : lhs / rhs;
case T_PERCENT: return rhs.is_zero() ? Value() : lhs % rhs;
default: default:
return Value(); return Value();

View File

@@ -219,6 +219,7 @@ QString Utils::toString(CPlusPlus::Kind kind)
TOKEN(T_LBRACKET); TOKEN(T_LBRACKET);
TOKEN(T_LESS); TOKEN(T_LESS);
TOKEN(T_LESS_EQUAL); TOKEN(T_LESS_EQUAL);
TOKEN(T_LESS_EQUAL_GREATER);
TOKEN(T_LESS_LESS); TOKEN(T_LESS_LESS);
TOKEN(T_LESS_LESS_EQUAL); TOKEN(T_LESS_LESS_EQUAL);
TOKEN(T_LPAREN); TOKEN(T_LPAREN);

View File

@@ -163,6 +163,7 @@ CPlusPlus::LanguageFeatures ProjectPart::deriveLanguageFeatures() const
CPlusPlus::LanguageFeatures features; CPlusPlus::LanguageFeatures features;
features.cxx11Enabled = languageVersion >= Utils::LanguageVersion::CXX11; features.cxx11Enabled = languageVersion >= Utils::LanguageVersion::CXX11;
features.cxx14Enabled = languageVersion >= Utils::LanguageVersion::CXX14; features.cxx14Enabled = languageVersion >= Utils::LanguageVersion::CXX14;
features.cxx20Enabled = languageVersion >= Utils::LanguageVersion::CXX20;
features.cxxEnabled = hasCxx; features.cxxEnabled = hasCxx;
features.c99Enabled = languageVersion >= Utils::LanguageVersion::C99; features.c99Enabled = languageVersion >= Utils::LanguageVersion::C99;
features.objCEnabled = languageExtensions.testFlag(Utils::LanguageExtension::ObjectiveC); features.objCEnabled = languageExtensions.testFlag(Utils::LanguageExtension::ObjectiveC);

View File

@@ -442,6 +442,7 @@ void tst_SimpleLexer::ppOpOrPunc()
const QByteArray source = QTest::currentDataTag(); const QByteArray source = QTest::currentDataTag();
LanguageFeatures languageFeatures; LanguageFeatures languageFeatures;
languageFeatures.cxxEnabled = true; languageFeatures.cxxEnabled = true;
languageFeatures.cxx20Enabled = true;
run(source, toTokens({unsigned(expectedTokenKind)}), false, CompareKind, true, languageFeatures); run(source, toTokens({unsigned(expectedTokenKind)}), false, CompareKind, true, languageFeatures);
} }
@@ -492,6 +493,7 @@ void tst_SimpleLexer::ppOpOrPunc_data()
QTest::newRow("==") << T_EQUAL_EQUAL; QTest::newRow("==") << T_EQUAL_EQUAL;
QTest::newRow("!=") << T_EXCLAIM_EQUAL; QTest::newRow("!=") << T_EXCLAIM_EQUAL;
QTest::newRow("<=") << T_LESS_EQUAL; QTest::newRow("<=") << T_LESS_EQUAL;
QTest::newRow("<=>") << T_LESS_EQUAL_GREATER;
QTest::newRow(">=") << T_GREATER_EQUAL; QTest::newRow(">=") << T_GREATER_EQUAL;
QTest::newRow("&&") << T_AMPER_AMPER; QTest::newRow("&&") << T_AMPER_AMPER;
QTest::newRow("||") << T_PIPE_PIPE; QTest::newRow("||") << T_PIPE_PIPE;