File indexing completed on 2024-04-28 15:52:52
0001 /* 0002 SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org> 0003 SPDX-FileCopyrightText: 2008 Niko Sams <niko.sams@gmail.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only 0006 */ 0007 0008 #include "lexertest.h" 0009 0010 #include <QtTest> 0011 0012 #include "parsesession.h" 0013 #include "phplexer.h" 0014 #include "phptokentext.h" 0015 0016 QTEST_MAIN(Php::LexerTest) 0017 namespace Php 0018 { 0019 0020 #define COMPARE_TOKEN(tokenStream, index, tokenKind, startLine, startColumn, endLine, endColumn) \ 0021 { \ 0022 QVERIFY(tokenStream->at(index).kind == tokenKind); \ 0023 qint64 line; qint64 column; \ 0024 tokenStream->startPosition(index, &line, &column); \ 0025 QCOMPARE(line, (qint64) startLine); \ 0026 QCOMPARE(column, (qint64) startColumn); \ 0027 tokenStream->endPosition(index, &line, &column); \ 0028 QCOMPARE(line, (qint64) endLine); \ 0029 QCOMPARE(column, (qint64) endColumn); \ 0030 } 0031 0032 LexerTest::LexerTest() 0033 { 0034 } 0035 0036 void LexerTest::testOpenTagWithNewline() 0037 { 0038 TokenStream* ts = tokenize(QStringLiteral("<?php\nfoo;")); 0039 QVERIFY(ts->size() == 3); 0040 0041 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0042 COMPARE_TOKEN(ts, 1, Parser::Token_STRING, 1, 0, 1, 2); 0043 COMPARE_TOKEN(ts, 2, Parser::Token_SEMICOLON, 1, 3, 1, 3); 0044 0045 delete ts; 0046 } 0047 0048 void LexerTest::testOpenTagWithSpace() 0049 { 0050 TokenStream* ts = tokenize(QStringLiteral("<?php foo;")); 0051 QVERIFY(ts->size() == 3); 0052 0053 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0054 COMPARE_TOKEN(ts, 1, Parser::Token_STRING, 0, 6, 0, 8); 0055 COMPARE_TOKEN(ts, 2, Parser::Token_SEMICOLON, 0, 9, 0, 9); 0056 delete ts; 0057 } 0058 0059 void LexerTest::testCommentOneLine() 0060 { 0061 TokenStream* ts = tokenize(QStringLiteral("<?php\n//comment\nfoo;")); 0062 QVERIFY(ts->size() == 4); 0063 0064 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0065 COMPARE_TOKEN(ts, 1, Parser::Token_COMMENT, 1, 0, 1, 9); 0066 COMPARE_TOKEN(ts, 2, Parser::Token_STRING, 2, 0, 2, 2); 0067 COMPARE_TOKEN(ts, 3, Parser::Token_SEMICOLON, 2, 3, 2, 3); 0068 delete ts; 0069 } 0070 0071 void LexerTest::testCommentOneLine2() 0072 { 0073 TokenStream* ts = tokenize(QStringLiteral("<?php\n#comment\nfoo;")); 0074 QVERIFY(ts->size() == 4); 0075 0076 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0077 COMPARE_TOKEN(ts, 1, Parser::Token_COMMENT, 1, 0, 1, 8); 0078 COMPARE_TOKEN(ts, 2, Parser::Token_STRING, 2, 0, 2, 2); 0079 COMPARE_TOKEN(ts, 3, Parser::Token_SEMICOLON, 2, 3, 2, 3); 0080 delete ts; 0081 } 0082 0083 void LexerTest::testCommentMultiLine() 0084 { 0085 TokenStream* ts = tokenize(QStringLiteral("<?php\n/*com\nment*/\nfoo;"), true); 0086 QVERIFY(ts->size() == 5); 0087 0088 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0089 COMPARE_TOKEN(ts, 1, Parser::Token_COMMENT, 1, 0, 2, 5); 0090 COMPARE_TOKEN(ts, 2, Parser::Token_WHITESPACE, 2, 6, 2, 6); 0091 COMPARE_TOKEN(ts, 3, Parser::Token_STRING, 3, 0, 3, 2); 0092 COMPARE_TOKEN(ts, 4, Parser::Token_SEMICOLON, 3, 3, 3, 3); 0093 delete ts; 0094 } 0095 0096 void LexerTest::testCommentMultiLine2() 0097 { 0098 TokenStream* ts = tokenize(QStringLiteral("<?php\n/*\nment*/\nfoo;"), true); 0099 QVERIFY(ts->size() == 5); 0100 0101 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0102 COMPARE_TOKEN(ts, 1, Parser::Token_COMMENT, 1, 0, 2, 5); 0103 COMPARE_TOKEN(ts, 2, Parser::Token_WHITESPACE, 2, 6, 2, 6); 0104 COMPARE_TOKEN(ts, 3, Parser::Token_STRING, 3, 0, 3, 2); 0105 COMPARE_TOKEN(ts, 4, Parser::Token_SEMICOLON, 3, 3, 3, 3); 0106 delete ts; 0107 } 0108 0109 void LexerTest::testEndTag() 0110 { 0111 TokenStream* ts = tokenize(QStringLiteral("<?\n':\n'?>\n>"), true, Lexer::DefaultState); 0112 //don't crash and we are fine 0113 delete ts; 0114 } 0115 0116 void LexerTest::testNewlineInString() 0117 { 0118 //0 1 0119 //012345 6 7 890123456789 0120 TokenStream* ts = tokenize(QStringLiteral("<?php \"\n\";"), true); 0121 QVERIFY(ts->size() == 3); 0122 0123 COMPARE_TOKEN(ts, 1, Parser::Token_CONSTANT_ENCAPSED_STRING, 0, 6, 1, 0); 0124 COMPARE_TOKEN(ts, 2, Parser::Token_SEMICOLON, 1, 1, 1, 1); 0125 delete ts; 0126 } 0127 0128 void LexerTest::testNewlineInString2() 0129 { 0130 //0 0131 //0123 4567 0132 TokenStream* ts = tokenize(QStringLiteral("<?php '\n';"), true); 0133 QCOMPARE((int)ts->size(), 3); 0134 0135 COMPARE_TOKEN(ts, 1, Parser::Token_CONSTANT_ENCAPSED_STRING, 0, 6, 1, 0); 0136 COMPARE_TOKEN(ts, 2, Parser::Token_SEMICOLON, 1, 1, 1, 1); 0137 delete ts; 0138 } 0139 0140 void LexerTest::testNewlineInStringWithVar() 0141 { 0142 TokenStream* ts = tokenize(QStringLiteral("<?php \"$a\n\";"), true); 0143 QCOMPARE((int)ts->size(), 6); 0144 0145 COMPARE_TOKEN(ts, 1, Parser::Token_DOUBLE_QUOTE, 0, 6, 0, 6); 0146 COMPARE_TOKEN(ts, 2, Parser::Token_VARIABLE, 0, 7, 0, 8); 0147 COMPARE_TOKEN(ts, 3, Parser::Token_ENCAPSED_AND_WHITESPACE, 0, 9, 0, 9); 0148 COMPARE_TOKEN(ts, 4, Parser::Token_DOUBLE_QUOTE, 1, 0, 1, 0); 0149 COMPARE_TOKEN(ts, 5, Parser::Token_SEMICOLON, 1, 1, 1, 1); 0150 delete ts; 0151 } 0152 0153 void LexerTest::testNewlineInStringWithVar2() 0154 { 0155 //0 1 0156 //012345 6 789 0123456789 0157 TokenStream* ts = tokenize(QStringLiteral("<?php \"\n$a\n\";"), true); 0158 QCOMPARE((int)ts->size(), 7); 0159 0160 COMPARE_TOKEN(ts, 1, Parser::Token_DOUBLE_QUOTE, 0, 6, 0, 6); 0161 COMPARE_TOKEN(ts, 2, Parser::Token_ENCAPSED_AND_WHITESPACE, 0, 7, 0, 7); 0162 COMPARE_TOKEN(ts, 3, Parser::Token_VARIABLE, 1, 0, 1, 1); 0163 COMPARE_TOKEN(ts, 4, Parser::Token_ENCAPSED_AND_WHITESPACE, 1, 2, 1, 2); 0164 COMPARE_TOKEN(ts, 5, Parser::Token_DOUBLE_QUOTE, 2, 0, 2, 0); 0165 COMPARE_TOKEN(ts, 6, Parser::Token_SEMICOLON, 2, 1, 2, 1); 0166 delete ts; 0167 } 0168 0169 void LexerTest::testNewlineInStringWithVar3() 0170 { 0171 //0 1 0172 //012345 6 789 0123456789 0173 TokenStream* ts = tokenize(QStringLiteral("<?php \"{$$a}\";"), true); 0174 QCOMPARE((int)ts->size(), 7); 0175 0176 COMPARE_TOKEN(ts, 1, Parser::Token_DOUBLE_QUOTE, 0, 6, 0, 6); 0177 COMPARE_TOKEN(ts, 2, Parser::Token_ENCAPSED_AND_WHITESPACE, 0, 7, 0, 8); 0178 COMPARE_TOKEN(ts, 3, Parser::Token_VARIABLE, 0, 9, 0, 10); 0179 COMPARE_TOKEN(ts, 4, Parser::Token_ENCAPSED_AND_WHITESPACE, 0, 11, 0, 11); 0180 COMPARE_TOKEN(ts, 5, Parser::Token_DOUBLE_QUOTE, 0, 12, 0, 12); 0181 COMPARE_TOKEN(ts, 6, Parser::Token_SEMICOLON, 0, 13, 0, 13); 0182 delete ts; 0183 } 0184 0185 void LexerTest::testMultiplePhpSections() 0186 { 0187 0188 //0 1 0189 //012345 6 789 0123456789 0190 TokenStream* ts = tokenize(QStringLiteral("<?php $a;?>\n<html>\n<?php $a;?>"), true); 0191 QCOMPARE((int)ts->size(), 9); 0192 0193 qint64 index = 0; 0194 for (qint64 line = 0; line <= 2; ++line) { 0195 if (line == 1) { 0196 // the html stuff in the middle 0197 COMPARE_TOKEN(ts, index, Parser::Token_INLINE_HTML, 0, 11, 1, 6); 0198 ++index; 0199 } else { 0200 // the php stuff (symmetric) at the start and end 0201 COMPARE_TOKEN(ts, index, Parser::Token_OPEN_TAG, line, 0, line, 5); 0202 ++index; 0203 0204 COMPARE_TOKEN(ts, index, Parser::Token_VARIABLE, line, 6, line, 7); 0205 ++index; 0206 0207 COMPARE_TOKEN(ts, index, Parser::Token_SEMICOLON, line, 8, line, 8); 0208 ++index; 0209 0210 COMPARE_TOKEN(ts, index, Parser::Token_CLOSE_TAG, line, 9, line, 10); 0211 ++index; 0212 } 0213 } 0214 delete ts; 0215 } 0216 0217 void LexerTest::testHereDoc() 0218 { 0219 TokenStream* ts = tokenize(QStringLiteral("<?php\necho <<<EOD1\nstart $text\nend\nEOD1;\n$extern;"), true); 0220 QCOMPARE((int)ts->size(), 12); 0221 0222 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0223 COMPARE_TOKEN(ts, 1, Parser::Token_ECHO, 1, 0, 1, 3); 0224 COMPARE_TOKEN(ts, 3, Parser::Token_START_HEREDOC, 1, 5, 1, 12); 0225 COMPARE_TOKEN(ts, 4, Parser::Token_ENCAPSED_AND_WHITESPACE, 2, 0, 2, 5); 0226 COMPARE_TOKEN(ts, 5, Parser::Token_VARIABLE, 2, 6, 2, 10); 0227 COMPARE_TOKEN(ts, 6, Parser::Token_ENCAPSED_AND_WHITESPACE, 2, 11, 3, 3); 0228 COMPARE_TOKEN(ts, 7, Parser::Token_END_HEREDOC, 4, 0, 4, 3); 0229 COMPARE_TOKEN(ts, 8, Parser::Token_SEMICOLON, 4, 4, 4, 4); 0230 COMPARE_TOKEN(ts, 10, Parser::Token_VARIABLE, 5, 0, 5, 6); 0231 COMPARE_TOKEN(ts, 11, Parser::Token_SEMICOLON, 5, 7, 5, 7); 0232 delete ts; 0233 } 0234 0235 void LexerTest::testHereDocQuoted() 0236 { 0237 TokenStream* ts = tokenize(QStringLiteral("<?php\necho <<<\"EOD1\"\nstart $text\nend\nEOD1;\n$extern;"), true); 0238 QCOMPARE((int)ts->size(), 12); 0239 0240 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0241 COMPARE_TOKEN(ts, 1, Parser::Token_ECHO, 1, 0, 1, 3); 0242 COMPARE_TOKEN(ts, 3, Parser::Token_START_HEREDOC, 1, 5, 1, 14); 0243 COMPARE_TOKEN(ts, 4, Parser::Token_ENCAPSED_AND_WHITESPACE, 2, 0, 2, 5); 0244 COMPARE_TOKEN(ts, 5, Parser::Token_VARIABLE, 2, 6, 2, 10); 0245 COMPARE_TOKEN(ts, 6, Parser::Token_ENCAPSED_AND_WHITESPACE, 2, 11, 3, 3); 0246 COMPARE_TOKEN(ts, 7, Parser::Token_END_HEREDOC, 4, 0, 4, 3); 0247 COMPARE_TOKEN(ts, 8, Parser::Token_SEMICOLON, 4, 4, 4, 4); 0248 COMPARE_TOKEN(ts, 10, Parser::Token_VARIABLE, 5, 0, 5, 6); 0249 COMPARE_TOKEN(ts, 11, Parser::Token_SEMICOLON, 5, 7, 5, 7); 0250 delete ts; 0251 } 0252 0253 void LexerTest::testNowdoc() 0254 { 0255 TokenStream* ts = tokenize(QStringLiteral("<?php\necho <<<'EOD1'\nstart $text\nend\nEOD1;\n$extern;"), true); 0256 QCOMPARE((int)ts->size(), 10); 0257 0258 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0259 COMPARE_TOKEN(ts, 1, Parser::Token_ECHO, 1, 0, 1, 3); 0260 COMPARE_TOKEN(ts, 3, Parser::Token_START_NOWDOC, 1, 5, 1, 14); 0261 COMPARE_TOKEN(ts, 4, Parser::Token_STRING, 2, 0, 3, 3); 0262 COMPARE_TOKEN(ts, 5, Parser::Token_END_NOWDOC, 4, 0, 4, 3); 0263 COMPARE_TOKEN(ts, 6, Parser::Token_SEMICOLON, 4, 4, 4, 4); 0264 COMPARE_TOKEN(ts, 8, Parser::Token_VARIABLE, 5, 0, 5, 6); 0265 COMPARE_TOKEN(ts, 9, Parser::Token_SEMICOLON, 5, 7, 5, 7); 0266 delete ts; 0267 } 0268 0269 void LexerTest::testCommonStringTokens() 0270 { 0271 // all these should have open_tag followed by constant encapsed string 0272 foreach ( const QString& code, QStringList() << "<?php ''" << "<?php \"\"" << "<?php '" << "<?php \"" ) { 0273 qDebug() << code; 0274 TokenStream* ts = tokenize(code, true); 0275 0276 QCOMPARE((int)ts->size(), 2); 0277 0278 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0279 COMPARE_TOKEN(ts, 1, Parser::Token_CONSTANT_ENCAPSED_STRING, 0, 6, 0, code.size() - 1); 0280 0281 delete ts; 0282 } 0283 } 0284 0285 void LexerTest::testNonTerminatedStringWithVar() 0286 { 0287 TokenStream* ts = tokenize(QStringLiteral("<?php \"$a"), true); 0288 0289 QCOMPARE((int)ts->size(), 3); 0290 0291 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0292 COMPARE_TOKEN(ts, 1, Parser::Token_DOUBLE_QUOTE, 0, 6, 0, 6); 0293 COMPARE_TOKEN(ts, 2, Parser::Token_VARIABLE, 0, 7, 0, 8); 0294 delete ts; 0295 } 0296 0297 void LexerTest::testPhpBlockWithComment() 0298 { 0299 TokenStream* ts = tokenize( 0300 QStringLiteral("<?php\n" 0301 "//asdf\n" 0302 "?>\n" 0303 "<?php\n") 0304 , true); 0305 0306 QCOMPARE((int)ts->size(), 5); 0307 0308 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0309 COMPARE_TOKEN(ts, 1, Parser::Token_COMMENT, 1, 0, 1, 6); 0310 COMPARE_TOKEN(ts, 2, Parser::Token_CLOSE_TAG, 2, 0, 2, 1); 0311 COMPARE_TOKEN(ts, 3, Parser::Token_INLINE_HTML, 2, 2, 2, 2); 0312 COMPARE_TOKEN(ts, 4, Parser::Token_OPEN_TAG, 3, 0, 3, 5); 0313 delete ts; 0314 } 0315 0316 void LexerTest::testNamespaces() 0317 { 0318 TokenStream* ts = tokenize( 0319 QStringLiteral("<?php\n" 0320 "namespace Foo;\n" 0321 "namespace Foo\\Bar;\n" 0322 "namespace Foo\\Bar\\Asd {\n" 0323 "}\n") 0324 , true); 0325 QCOMPARE((int)ts->size(), 25); 0326 0327 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0328 0329 COMPARE_TOKEN(ts, 1, Parser::Token_NAMESPACE, 1, 0, 1, 8); 0330 COMPARE_TOKEN(ts, 2, Parser::Token_WHITESPACE, 1, 9, 1, 9); 0331 COMPARE_TOKEN(ts, 3, Parser::Token_STRING, 1, 10, 1, 12); 0332 COMPARE_TOKEN(ts, 4, Parser::Token_SEMICOLON, 1, 13, 1, 13); 0333 0334 COMPARE_TOKEN(ts, 6, Parser::Token_NAMESPACE, 2, 0, 2, 8); 0335 COMPARE_TOKEN(ts, 7, Parser::Token_WHITESPACE, 2, 9, 2, 9); 0336 COMPARE_TOKEN(ts, 8, Parser::Token_STRING, 2, 10, 2, 12); 0337 COMPARE_TOKEN(ts, 9, Parser::Token_BACKSLASH, 2, 13, 2, 13); 0338 COMPARE_TOKEN(ts, 10, Parser::Token_STRING, 2, 14, 2, 16); 0339 COMPARE_TOKEN(ts, 11, Parser::Token_SEMICOLON, 2, 17, 2, 17); 0340 0341 COMPARE_TOKEN(ts, 13, Parser::Token_NAMESPACE, 3, 0, 3, 8); 0342 COMPARE_TOKEN(ts, 14, Parser::Token_WHITESPACE, 3, 9, 3, 9); 0343 COMPARE_TOKEN(ts, 15, Parser::Token_STRING, 3, 10, 3, 12); 0344 COMPARE_TOKEN(ts, 16, Parser::Token_BACKSLASH, 3, 13, 3, 13); 0345 COMPARE_TOKEN(ts, 17, Parser::Token_STRING, 3, 14, 3, 16); 0346 COMPARE_TOKEN(ts, 18, Parser::Token_BACKSLASH, 3, 17, 3, 17); 0347 COMPARE_TOKEN(ts, 19, Parser::Token_STRING, 3, 18, 3, 20); 0348 COMPARE_TOKEN(ts, 20, Parser::Token_WHITESPACE, 3, 21, 3, 21); 0349 COMPARE_TOKEN(ts, 21, Parser::Token_LBRACE, 3, 22, 3, 22); 0350 COMPARE_TOKEN(ts, 23, Parser::Token_RBRACE, 4, 0, 4, 0); 0351 0352 delete ts; 0353 } 0354 0355 void LexerTest::testCloseTagInComment() 0356 { 0357 { 0358 TokenStream* ts = tokenize( 0359 QStringLiteral("<?php // asdf ?>") 0360 , true); 0361 QCOMPARE((int)ts->size(), 3); 0362 0363 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0364 COMPARE_TOKEN(ts, 1, Parser::Token_COMMENT, 0, 6, 0, 13); 0365 COMPARE_TOKEN(ts, 2, Parser::Token_CLOSE_TAG, 0, 14, 0, 15); 0366 0367 delete ts; 0368 } 0369 { 0370 TokenStream* ts = tokenize( 0371 QStringLiteral("<?php # asdf ?>") 0372 , true); 0373 QCOMPARE((int)ts->size(), 3); 0374 0375 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0376 COMPARE_TOKEN(ts, 1, Parser::Token_COMMENT, 0, 6, 0, 13); 0377 COMPARE_TOKEN(ts, 2, Parser::Token_CLOSE_TAG, 0, 14, 0, 15); 0378 0379 delete ts; 0380 } 0381 } 0382 0383 void LexerTest::testBinaryNumber() 0384 { 0385 TokenStream* ts = tokenize(QStringLiteral("<?php\n0b01;\n0B01;"), true); 0386 QCOMPARE((int)ts->size(), 6); 0387 0388 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0389 COMPARE_TOKEN(ts, 1, Parser::Token_LNUMBER, 1, 0, 1, 3); 0390 COMPARE_TOKEN(ts, 2, Parser::Token_SEMICOLON, 1, 4, 1, 4); 0391 COMPARE_TOKEN(ts, 3, Parser::Token_WHITESPACE, 1, 5, 1, 5); 0392 COMPARE_TOKEN(ts, 4, Parser::Token_LNUMBER, 2, 0, 2, 3); 0393 COMPARE_TOKEN(ts, 5, Parser::Token_SEMICOLON, 2, 4, 2, 4); 0394 delete ts; 0395 } 0396 0397 void LexerTest::testHexadecimalNumber() 0398 { 0399 TokenStream* ts = tokenize(QStringLiteral("<?php\n0x01;\n0X01;\n0xABC12;\n0Xab10A;"), true); 0400 QCOMPARE((int)ts->size(), 12); 0401 0402 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0403 COMPARE_TOKEN(ts, 1, Parser::Token_LNUMBER, 1, 0, 1, 3); 0404 COMPARE_TOKEN(ts, 2, Parser::Token_SEMICOLON, 1, 4, 1, 4); 0405 COMPARE_TOKEN(ts, 3, Parser::Token_WHITESPACE, 1, 5, 1, 5); 0406 COMPARE_TOKEN(ts, 4, Parser::Token_LNUMBER, 2, 0, 2, 3); 0407 COMPARE_TOKEN(ts, 5, Parser::Token_SEMICOLON, 2, 4, 2, 4); 0408 COMPARE_TOKEN(ts, 6, Parser::Token_WHITESPACE, 2, 5, 2, 5); 0409 COMPARE_TOKEN(ts, 7, Parser::Token_LNUMBER, 3, 0, 3, 6); 0410 COMPARE_TOKEN(ts, 8, Parser::Token_SEMICOLON, 3, 7, 3, 7); 0411 COMPARE_TOKEN(ts, 9, Parser::Token_WHITESPACE, 3, 8, 3, 8); 0412 COMPARE_TOKEN(ts, 10, Parser::Token_LNUMBER, 4, 0, 4, 6); 0413 COMPARE_TOKEN(ts, 11, Parser::Token_SEMICOLON, 4, 7, 4, 7); 0414 delete ts; 0415 } 0416 0417 void LexerTest::testTypeHintsOnFunction() 0418 { 0419 QScopedPointer<TokenStream> ts(tokenize(QStringLiteral("<?php\nfunction a($a, array $b = [], callable $c) {}"), true)); 0420 QCOMPARE((int)ts->size(), 25); 0421 0422 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0423 COMPARE_TOKEN(ts, 1, Parser::Token_FUNCTION, 1, 0, 1, 7); 0424 COMPARE_TOKEN(ts, 2, Parser::Token_WHITESPACE, 1, 8, 1, 8); 0425 COMPARE_TOKEN(ts, 3, Parser::Token_STRING, 1, 9, 1, 9); 0426 COMPARE_TOKEN(ts, 4, Parser::Token_LPAREN, 1, 10, 1, 10); 0427 COMPARE_TOKEN(ts, 5, Parser::Token_VARIABLE, 1, 11, 1, 12); 0428 COMPARE_TOKEN(ts, 6, Parser::Token_COMMA, 1, 13, 1, 13); 0429 COMPARE_TOKEN(ts, 7, Parser::Token_WHITESPACE, 1, 14, 1, 14); 0430 COMPARE_TOKEN(ts, 8, Parser::Token_ARRAY, 1, 15, 1, 19); 0431 COMPARE_TOKEN(ts, 9, Parser::Token_WHITESPACE, 1, 20, 1, 20); 0432 COMPARE_TOKEN(ts, 10, Parser::Token_VARIABLE, 1, 21, 1, 22); 0433 COMPARE_TOKEN(ts, 11, Parser::Token_WHITESPACE, 1, 23, 1, 23); 0434 COMPARE_TOKEN(ts, 12, Parser::Token_ASSIGN, 1, 24, 1, 24); 0435 COMPARE_TOKEN(ts, 13, Parser::Token_WHITESPACE, 1, 25, 1, 25); 0436 COMPARE_TOKEN(ts, 14, Parser::Token_LBRACKET, 1, 26, 1, 26); 0437 COMPARE_TOKEN(ts, 15, Parser::Token_RBRACKET, 1, 27, 1, 27); 0438 COMPARE_TOKEN(ts, 16, Parser::Token_COMMA, 1, 28, 1, 28); 0439 COMPARE_TOKEN(ts, 17, Parser::Token_WHITESPACE, 1, 29, 1, 29); 0440 COMPARE_TOKEN(ts, 18, Parser::Token_CALLABLE, 1, 30, 1, 37); 0441 COMPARE_TOKEN(ts, 19, Parser::Token_WHITESPACE, 1, 38, 1, 38); 0442 COMPARE_TOKEN(ts, 20, Parser::Token_VARIABLE, 1, 39, 1, 40); 0443 COMPARE_TOKEN(ts, 21, Parser::Token_RPAREN, 1, 41, 1, 41); 0444 COMPARE_TOKEN(ts, 22, Parser::Token_WHITESPACE, 1, 42, 1, 42); 0445 COMPARE_TOKEN(ts, 23, Parser::Token_LBRACE, 1, 43, 1, 43); 0446 COMPARE_TOKEN(ts, 24, Parser::Token_RBRACE, 1, 44, 1, 44); 0447 } 0448 0449 void LexerTest::testReturnTypeHints() 0450 { 0451 QScopedPointer<TokenStream> ts(tokenize(QStringLiteral("<?php\nfunction a(): string {}"), true)); 0452 QCOMPARE((int)ts->size(), 12); 0453 0454 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0455 COMPARE_TOKEN(ts, 1, Parser::Token_FUNCTION, 1, 0, 1, 7); 0456 COMPARE_TOKEN(ts, 2, Parser::Token_WHITESPACE, 1, 8, 1, 8); 0457 COMPARE_TOKEN(ts, 3, Parser::Token_STRING, 1, 9, 1, 9); 0458 COMPARE_TOKEN(ts, 4, Parser::Token_LPAREN, 1, 10, 1, 10); 0459 COMPARE_TOKEN(ts, 5, Parser::Token_RPAREN, 1, 11, 1, 11); 0460 COMPARE_TOKEN(ts, 6, Parser::Token_COLON, 1, 12, 1, 12); 0461 COMPARE_TOKEN(ts, 7, Parser::Token_WHITESPACE, 1, 13, 1, 13); 0462 COMPARE_TOKEN(ts, 8, Parser::Token_STRING, 1, 14, 1, 19); 0463 COMPARE_TOKEN(ts, 9, Parser::Token_WHITESPACE, 1, 20, 1, 20); 0464 COMPARE_TOKEN(ts, 10, Parser::Token_LBRACE, 1, 21, 1, 21); 0465 COMPARE_TOKEN(ts, 11, Parser::Token_RBRACE, 1, 22, 1, 22); 0466 } 0467 0468 void LexerTest::testExponentiation() 0469 { 0470 QScopedPointer<TokenStream> ts(tokenize(QStringLiteral("<?php\n$a = 2 ** 3; $a **= 2;"), true)); 0471 QCOMPARE((int)ts->size(), 18); 0472 0473 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0474 COMPARE_TOKEN(ts, 1, Parser::Token_VARIABLE, 1, 0, 1, 1); 0475 COMPARE_TOKEN(ts, 2, Parser::Token_WHITESPACE, 1, 2, 1, 2); 0476 COMPARE_TOKEN(ts, 3, Parser::Token_ASSIGN, 1, 3, 1, 3); 0477 COMPARE_TOKEN(ts, 4, Parser::Token_WHITESPACE, 1, 4, 1, 4); 0478 COMPARE_TOKEN(ts, 5, Parser::Token_LNUMBER, 1, 5, 1, 5); 0479 COMPARE_TOKEN(ts, 6, Parser::Token_WHITESPACE, 1, 6, 1, 6); 0480 COMPARE_TOKEN(ts, 7, Parser::Token_EXP, 1, 7, 1, 8); 0481 COMPARE_TOKEN(ts, 8, Parser::Token_WHITESPACE, 1, 9, 1, 9); 0482 COMPARE_TOKEN(ts, 9, Parser::Token_LNUMBER, 1, 10, 1, 10); 0483 COMPARE_TOKEN(ts, 10, Parser::Token_SEMICOLON, 1, 11, 1, 11); 0484 COMPARE_TOKEN(ts, 11, Parser::Token_WHITESPACE, 1, 12, 1, 12); 0485 COMPARE_TOKEN(ts, 12, Parser::Token_VARIABLE, 1, 13, 1, 14); 0486 COMPARE_TOKEN(ts, 13, Parser::Token_WHITESPACE, 1, 15, 1, 15); 0487 COMPARE_TOKEN(ts, 14, Parser::Token_EXP_ASSIGN, 1, 16, 1, 18); 0488 COMPARE_TOKEN(ts, 15, Parser::Token_WHITESPACE, 1, 19, 1, 19); 0489 COMPARE_TOKEN(ts, 16, Parser::Token_LNUMBER, 1, 20, 1, 20); 0490 COMPARE_TOKEN(ts, 17, Parser::Token_SEMICOLON, 1, 21, 1, 21); 0491 0492 } 0493 0494 void LexerTest::testExceptionFinally() 0495 { 0496 QScopedPointer<TokenStream> ts(tokenize(QStringLiteral("<?php\ntry { $a = 1; } finally { }"), true)); 0497 QCOMPARE((int)ts->size(), 19); 0498 0499 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0500 COMPARE_TOKEN(ts, 1, Parser::Token_TRY, 1, 0, 1, 2); 0501 COMPARE_TOKEN(ts, 2, Parser::Token_WHITESPACE, 1, 3, 1, 3); 0502 COMPARE_TOKEN(ts, 3, Parser::Token_LBRACE, 1, 4, 1, 4); 0503 COMPARE_TOKEN(ts, 4, Parser::Token_WHITESPACE, 1, 5, 1, 5); 0504 COMPARE_TOKEN(ts, 5, Parser::Token_VARIABLE, 1, 6, 1, 7); 0505 COMPARE_TOKEN(ts, 6, Parser::Token_WHITESPACE, 1, 8, 1, 8); 0506 COMPARE_TOKEN(ts, 7, Parser::Token_ASSIGN, 1, 9, 1, 9); 0507 COMPARE_TOKEN(ts, 8, Parser::Token_WHITESPACE, 1, 10, 1, 10); 0508 COMPARE_TOKEN(ts, 9, Parser::Token_LNUMBER, 1, 11, 1, 11); 0509 COMPARE_TOKEN(ts, 10, Parser::Token_SEMICOLON, 1, 12, 1, 12); 0510 COMPARE_TOKEN(ts, 11, Parser::Token_WHITESPACE, 1, 13, 1, 13); 0511 COMPARE_TOKEN(ts, 12, Parser::Token_RBRACE, 1, 14, 1, 14); 0512 COMPARE_TOKEN(ts, 13, Parser::Token_WHITESPACE, 1, 15, 1, 15); 0513 COMPARE_TOKEN(ts, 14, Parser::Token_FINALLY, 1, 16, 1, 22); 0514 COMPARE_TOKEN(ts, 15, Parser::Token_WHITESPACE, 1, 23, 1, 23); 0515 COMPARE_TOKEN(ts, 16, Parser::Token_LBRACE, 1, 24, 1, 24); 0516 COMPARE_TOKEN(ts, 17, Parser::Token_WHITESPACE, 1, 25, 1, 25); 0517 COMPARE_TOKEN(ts, 18, Parser::Token_RBRACE, 1, 26, 1, 26); 0518 } 0519 0520 void LexerTest::testEllipsis() 0521 { 0522 QScopedPointer<TokenStream> ts(tokenize(QStringLiteral("<?php\nfunction foo(...$args) {}"), true)); 0523 QCOMPARE((int)ts->size(), 11); 0524 0525 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0526 COMPARE_TOKEN(ts, 1, Parser::Token_FUNCTION, 1, 0, 1, 7); 0527 COMPARE_TOKEN(ts, 2, Parser::Token_WHITESPACE, 1, 8, 1, 8); 0528 COMPARE_TOKEN(ts, 3, Parser::Token_STRING, 1, 9, 1, 11); 0529 COMPARE_TOKEN(ts, 4, Parser::Token_LPAREN, 1, 12, 1, 12); 0530 COMPARE_TOKEN(ts, 5, Parser::Token_ELLIPSIS, 1, 13, 1, 15); 0531 COMPARE_TOKEN(ts, 6, Parser::Token_VARIABLE, 1, 16, 1, 20); 0532 COMPARE_TOKEN(ts, 7, Parser::Token_RPAREN, 1, 21, 1, 21); 0533 COMPARE_TOKEN(ts, 8, Parser::Token_WHITESPACE, 1, 22, 1, 22); 0534 COMPARE_TOKEN(ts, 9, Parser::Token_LBRACE, 1, 23, 1, 23); 0535 COMPARE_TOKEN(ts, 10, Parser::Token_RBRACE, 1, 24, 1, 24); 0536 } 0537 0538 void LexerTest::testSpaceship() 0539 { 0540 QScopedPointer<TokenStream> ts(tokenize(QStringLiteral("<?php\n$a = 'ab' <=> 'b';"), true)); 0541 QCOMPARE((int)ts->size(), 11); 0542 0543 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0544 COMPARE_TOKEN(ts, 1, Parser::Token_VARIABLE, 1, 0, 1, 1); 0545 COMPARE_TOKEN(ts, 2, Parser::Token_WHITESPACE, 1, 2, 1, 2); 0546 COMPARE_TOKEN(ts, 3, Parser::Token_ASSIGN, 1, 3, 1, 3); 0547 COMPARE_TOKEN(ts, 4, Parser::Token_WHITESPACE, 1, 4, 1, 4); 0548 COMPARE_TOKEN(ts, 5, Parser::Token_CONSTANT_ENCAPSED_STRING, 1, 5, 1, 8); 0549 COMPARE_TOKEN(ts, 6, Parser::Token_WHITESPACE, 1, 9, 1, 9); 0550 COMPARE_TOKEN(ts, 7, Parser::Token_SPACESHIP, 1, 10, 1, 12); 0551 COMPARE_TOKEN(ts, 8, Parser::Token_WHITESPACE, 1, 13, 1, 13); 0552 COMPARE_TOKEN(ts, 9, Parser::Token_CONSTANT_ENCAPSED_STRING, 1, 14, 1, 16); 0553 COMPARE_TOKEN(ts, 10, Parser::Token_SEMICOLON, 1, 17, 1, 17); 0554 } 0555 0556 void LexerTest::testNullCoalesce() 0557 { 0558 QScopedPointer<TokenStream> ts(tokenize(QStringLiteral("<?php\n$a = null ?? true;"), true)); 0559 QCOMPARE((int)ts->size(), 11); 0560 0561 COMPARE_TOKEN(ts, 0, Parser::Token_OPEN_TAG, 0, 0, 0, 5); 0562 COMPARE_TOKEN(ts, 1, Parser::Token_VARIABLE, 1, 0, 1, 1); 0563 COMPARE_TOKEN(ts, 2, Parser::Token_WHITESPACE, 1, 2, 1, 2); 0564 COMPARE_TOKEN(ts, 3, Parser::Token_ASSIGN, 1, 3, 1, 3); 0565 COMPARE_TOKEN(ts, 4, Parser::Token_WHITESPACE, 1, 4, 1, 4); 0566 COMPARE_TOKEN(ts, 5, Parser::Token_STRING, 1, 5, 1, 8); 0567 COMPARE_TOKEN(ts, 6, Parser::Token_WHITESPACE, 1, 9, 1, 9); 0568 COMPARE_TOKEN(ts, 7, Parser::Token_NULL_COALESCE, 1, 10, 1, 11); 0569 COMPARE_TOKEN(ts, 8, Parser::Token_WHITESPACE, 1, 12, 1, 12); 0570 COMPARE_TOKEN(ts, 9, Parser::Token_STRING, 1, 13, 1, 16); 0571 COMPARE_TOKEN(ts, 10, Parser::Token_SEMICOLON, 1, 17, 1, 17); 0572 } 0573 0574 TokenStream* LexerTest::tokenize(const QString& unit, bool debug, int initialState) 0575 { 0576 auto* tokenStream = new TokenStream; 0577 Lexer lexer(tokenStream, unit, initialState); 0578 int token; 0579 int i = 0; 0580 QList<Parser::Token> tokens; 0581 while ((token = lexer.nextTokenKind())) { 0582 Parser::Token &t = tokenStream->push(); 0583 t.begin = lexer.tokenBegin(); 0584 t.end = lexer.tokenEnd(); 0585 t.kind = token; 0586 tokens << t; 0587 } 0588 if (debug) { 0589 foreach(const Parser::Token &t, tokens) { 0590 qint64 beginLine; 0591 qint64 beginColumn; 0592 tokenStream->startPosition(i, &beginLine, &beginColumn); 0593 qint64 endLine; 0594 qint64 endColumn; 0595 tokenStream->endPosition(i, &endLine, &endColumn); 0596 qDebug() << tokenText(t.kind) 0597 << unit.mid(t.begin, t.end - t.begin + 1).replace('\n', QLatin1String("\\n")) 0598 << QStringLiteral("[%0-%1] - [%2-%3]").arg(beginLine).arg(beginColumn).arg(endLine).arg(endColumn); 0599 ++i; 0600 } 0601 } 0602 return tokenStream; 0603 } 0604 } 0605 0606 #include "moc_lexertest.cpp"