summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthijs Tijink <matthijstijink@gmail.com>2017-07-12 21:23:27 (GMT)
committerAlexander Zhigalin <alexander@zhigalin.tk>2017-07-12 21:23:37 (GMT)
commit8da5db996bf9bd8432f73335b30fe85db05decfa (patch)
tree777ce846f4353bfb04388948a846978730fbcee4
parentdad970d96beeb50b67c4af3040c79f41bd6307c3 (diff)
Add spaceship and null coalesce operators to PHP language support
Summary: This diff adds the spaceship operator `<=>` (returning `-1`, `0` or `1`, useful in implementing comparison functions) and the null coalesce operator `??` (returning the left operand if it is set and is not null, otherwise the second operand). Reviewers: #kdevelop, zhigalin, pprkut Reviewed By: zhigalin Subscribers: zhigalin, kdevelop-devel, #kdevelop Tags: #kdevelop Differential Revision: https://phabricator.kde.org/D6645
-rw-r--r--completion/context.cpp2
-rw-r--r--parser/php.g11
-rw-r--r--parser/phplexer.cpp12
-rw-r--r--parser/test/lexertest.cpp36
-rw-r--r--parser/test/lexertest.h2
5 files changed, 58 insertions, 5 deletions
diff --git a/completion/context.cpp b/completion/context.cpp
index c14b88c..636b2ac 100644
--- a/completion/context.cpp
+++ b/completion/context.cpp
@@ -528,6 +528,7 @@ CodeCompletionContext::CodeCompletionContext(KDevelop::DUContextPointer context,
case Parser::Token_MOD_ASSIGN:
case Parser::Token_MUL:
case Parser::Token_MUL_ASSIGN:
+ case Parser::Token_NULL_COALESCE:
case Parser::Token_OBJECT_CAST:
case Parser::Token_OPEN_TAG_WITH_ECHO:
case Parser::Token_OR_ASSIGN:
@@ -540,6 +541,7 @@ CodeCompletionContext::CodeCompletionContext(KDevelop::DUContextPointer context,
case Parser::Token_SEMICOLON:
case Parser::Token_SL:
case Parser::Token_SL_ASSIGN:
+ case Parser::Token_SPACESHIP:
case Parser::Token_SR:
case Parser::Token_SR_ASSIGN:
case Parser::Token_START_HEREDOC:
diff --git a/parser/php.g b/parser/php.g
index 9914d23..78af85d 100644
--- a/parser/php.g
+++ b/parser/php.g
@@ -269,6 +269,7 @@ namespace KDevelop
BIT_AND ("&"), BIT_OR("|"), BIT_XOR ("^"),
SL ("<<"), SR (">>"), MUL("*"), DIV("/"), MOD ("%"),
TILDE ("~"), DOLLAR ("$"), EXP ("**"), ELLIPSIS ("..."),
+ NULL_COALESCE ("??"), SPACESHIP ("<=>"),
LOGICAL_OR ("logical or"), LOGICAL_AND ("logical and"), LOGICAL_XOR ("logical xor") ;;
-- literals and identifiers:
@@ -336,12 +337,13 @@ namespace KDevelop
--right print
--right = += -= *= /= .= %= &= |= ^= <<= >>= assignment
--left ? : ternary
+--right ?? comparison
--left || logical
--left && logical
--left | bitwise
--left ^ bitwise
--left & bitwise and references
---non-associative == != === !== comparison
+--non-associative == != === !== <=> comparison
--non-associative < <= > >= comparison
--left << >> bitwise
--left + - . arithmetic and string
@@ -423,13 +425,16 @@ ASSIGN
:]
-> assignmentExpressionCheckIfVariable ;;
-expression=booleanOrExpression
+expression=nullCoalesceExpression
( QUESTION (ifExpression=expr|0)
COLON elseExpression=conditionalExpression
| 0
)
-> conditionalExpression ;;
+ #expression=booleanOrExpression @ NULL_COALESCE
+-> nullCoalesceExpression ;;
+
#expression=booleanAndExpression @ BOOLEAN_OR
-> booleanOrExpression ;;
@@ -449,7 +454,7 @@ expression=booleanOrExpression
(#additionalExpression=equalityExpressionRest)*
-> equalityExpression ;;
- ( IS_EQUAL | IS_NOT_EQUAL | IS_IDENTICAL | IS_NOT_IDENTICAL )
+ ( IS_EQUAL | IS_NOT_EQUAL | IS_IDENTICAL | IS_NOT_IDENTICAL | SPACESHIP )
expression=relationalExpression
-> equalityExpressionRest ;;
diff --git a/parser/phplexer.cpp b/parser/phplexer.cpp
index f4a6172..f522707 100644
--- a/parser/phplexer.cpp
+++ b/parser/phplexer.cpp
@@ -345,8 +345,13 @@ int Lexer::nextTokenKind()
}
}
} else if ((it + 1)->unicode() == '=') {
- m_curpos++;
- token = Parser::Token_IS_SMALLER_OR_EQUAL;
+ if ((it + 2)->unicode() == '>') {
+ m_curpos += 2;
+ token = Parser::Token_SPACESHIP;
+ } else {
+ m_curpos++;
+ token = Parser::Token_IS_SMALLER_OR_EQUAL;
+ }
} else if ((it + 1)->unicode() == '>') {
m_curpos++;
token = Parser::Token_IS_NOT_EQUAL;
@@ -383,6 +388,9 @@ int Lexer::nextTokenKind()
token = Parser::Token_CLOSE_TAG;
m_curpos++;
while (state() != HtmlState) popState();
+ } else if ((it + 1)->unicode() == '?') {
+ token = Parser::Token_NULL_COALESCE;
+ m_curpos++;
} else {
token = Parser::Token_QUESTION;
}
diff --git a/parser/test/lexertest.cpp b/parser/test/lexertest.cpp
index e7da1ac..36996ff 100644
--- a/parser/test/lexertest.cpp
+++ b/parser/test/lexertest.cpp
@@ -547,6 +547,42 @@ void LexerTest::testEllipsis()
COMPARE_TOKEN(ts, 10, Parser::Token_RBRACE, 1, 24, 1, 24);
}
+void LexerTest::testSpaceship()
+{
+ QScopedPointer<TokenStream> ts(tokenize(QStringLiteral("<?php\n$a = 'ab' <=> 'b';"), true));
+ QCOMPARE((int)ts->size(), 11);
+
+ COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5);
+ COMPARE_TOKEN(ts, 1, Parser::Token_VARIABLE, 1, 0, 1, 1);
+ COMPARE_TOKEN(ts, 2, Parser::Token_WHITESPACE, 1, 2, 1, 2);
+ COMPARE_TOKEN(ts, 3, Parser::Token_ASSIGN, 1, 3, 1, 3);
+ COMPARE_TOKEN(ts, 4, Parser::Token_WHITESPACE, 1, 4, 1, 4);
+ COMPARE_TOKEN(ts, 5, Parser::Token_CONSTANT_ENCAPSED_STRING, 1, 5, 1, 8);
+ COMPARE_TOKEN(ts, 6, Parser::Token_WHITESPACE, 1, 9, 1, 9);
+ COMPARE_TOKEN(ts, 7, Parser::Token_SPACESHIP, 1, 10, 1, 12);
+ COMPARE_TOKEN(ts, 8, Parser::Token_WHITESPACE, 1, 13, 1, 13);
+ COMPARE_TOKEN(ts, 9, Parser::Token_CONSTANT_ENCAPSED_STRING, 1, 14, 1, 16);
+ COMPARE_TOKEN(ts, 10, Parser::Token_SEMICOLON, 1, 17, 1, 17);
+}
+
+void LexerTest::testNullCoalesce()
+{
+ QScopedPointer<TokenStream> ts(tokenize(QStringLiteral("<?php\n$a = null ?? true;"), true));
+ QCOMPARE((int)ts->size(), 11);
+
+ COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5);
+ COMPARE_TOKEN(ts, 1, Parser::Token_VARIABLE, 1, 0, 1, 1);
+ COMPARE_TOKEN(ts, 2, Parser::Token_WHITESPACE, 1, 2, 1, 2);
+ COMPARE_TOKEN(ts, 3, Parser::Token_ASSIGN, 1, 3, 1, 3);
+ COMPARE_TOKEN(ts, 4, Parser::Token_WHITESPACE, 1, 4, 1, 4);
+ COMPARE_TOKEN(ts, 5, Parser::Token_STRING, 1, 5, 1, 8);
+ COMPARE_TOKEN(ts, 6, Parser::Token_WHITESPACE, 1, 9, 1, 9);
+ COMPARE_TOKEN(ts, 7, Parser::Token_NULL_COALESCE, 1, 10, 1, 11);
+ COMPARE_TOKEN(ts, 8, Parser::Token_WHITESPACE, 1, 12, 1, 12);
+ COMPARE_TOKEN(ts, 9, Parser::Token_STRING, 1, 13, 1, 16);
+ COMPARE_TOKEN(ts, 10, Parser::Token_SEMICOLON, 1, 17, 1, 17);
+}
+
TokenStream* LexerTest::tokenize(const QString& unit, bool debug, int initialState)
{
TokenStream* tokenStream = new TokenStream;
diff --git a/parser/test/lexertest.h b/parser/test/lexertest.h
index 980b08b..0df5306 100644
--- a/parser/test/lexertest.h
+++ b/parser/test/lexertest.h
@@ -70,6 +70,8 @@ private slots:
void testExponentiation();
void testExceptionFinally();
void testEllipsis();
+ void testSpaceship();
+ void testNullCoalesce();
protected:
TokenStream* tokenize(const QString& unit, bool debug = false, int initialState = Lexer::HtmlState);