1------------------------------------------------------------------------------- 2-- SPDX-FileCopyrightText: 2008 Niko Sams <niko.sams@gmail.com> 3-- 4-- SPDX-License-Identifier: LGPL-2.0-or-later 5----------------------------------------------------------- 6 7 8----------------------------------------------------------- 9-- Grammar for PHP 5.2 10-- Modelled after the Zend Grammar shipped with PHP5.2 11-- source, the PHP Language Reference documentation, 12-- and parts taken from KDevelop Java Grammar 13----------------------------------------------------------- 14 15-- 4 first/first conflicts: 16-- - var_expression: variable vs. varExpressionNormal 17-- no problem because of ifs that allow always just one rule 18-- - classNameReference: STRING vs. staticMember (foo vs. foo::$bar) 19-- resolved by LA() 20-- - encapsVar: STRING_VARNAME LBRACKET vs. expr (expr allows STRING_VARNAME too - but not LBRACKET) 21-- resolved by LA() 22-- - constantOrClassConst: constant vs. class constant (FOO v.s Cls::FOO) 23-- resolved by LA() (could be avoided, but the Ast is much cleaner that way) 24-- 1 first/follow conflicts: 25-- - elseifList: dangling-else conflict - should be ok 26 27-- TODO: (post 1.0.0 release) 28-- 1) decrease memory consumption 29-- 1.1) use quint32 instead of qint64 for end/start tokens 30-- 1.2) investigate whether using a map/hash for the ducontext member of all 31-- ast nodes gives a significant memory decrease while not hampering performance 32-- 1.3) investigate how unions could be used for exclusive AST node members 33-- 1.4) see whether we can always use the expression lists instead of both 34-- single member pointer and list of members, esp. in expressions 35-- 2) better cope with invalid code, have at least a partial AST 36-- 3) investigate whether expanding the visitor lookup to a 37-- (albeit huge) switch() in KDev-PG-Qt gives a significant performance gain 38-- I have the gut feeling that the current lookup takes unnecessary much time 39-- 40 41------------------------------------------------------------ 42-- Forward declaration in phpast.h 43------------------------------------------------------------ 44 45[: 46 47#include <QtCore/QRegularExpression> 48 49namespace KDevelop 50{ 51 class DUContext; 52} 53 54:] 55 56------------------------------------------------------------ 57-- Additional includes for the parser 58------------------------------------------------------------ 59 60%parser_declaration_header "parser/tokenstream.h" 61%parser_declaration_header "QtCore/QString" 62%parser_declaration_header "language/duchain/problem.h" 63%parser_declaration_header "parser/phplexer.h" 64 65%parser_bits_header "parserdebug.h" 66 67------------------------------------------------------------ 68-- Export macro to use the parser in a shared lib 69------------------------------------------------------------ 70%export_macro "KDEVPHPPARSER_EXPORT" 71%export_macro_header "parserexport.h" 72 73 74------------------------------------------------------------ 75-- Enumeration types for additional AST members, 76-- in the global "Php" namespace 77------------------------------------------------------------ 78%namespace 79[: 80 class Lexer; 81 82 enum ModifierFlags { 83 ModifierPrivate = 1, 84 ModifierPublic = 1 << 1, 85 ModifierProtected = 1 << 2, 86 ModifierStatic = 1 << 3, 87 ModifierFinal = 1 << 4, 88 ModifierAbstract = 1 << 5 89 }; 90 91 enum ClassModifier { 92 NormalClass, 93 AbstractClass, 94 FinalClass 95 }; 96 97 enum ScalarTypes { 98 ScalarTypeInt, 99 ScalarTypeFloat, 100 ScalarTypeString 101 }; 102 103 enum CastType { 104 CastInt, 105 CastDouble, 106 CastString, 107 CastArray, 108 CastObject, 109 CastBool, 110 CastUnset 111 }; 112 113 enum OperationType { 114 OperationPlus = 1, 115 OperationMinus, 116 OperationConcat, 117 OperationMul, 118 OperationDiv, 119 OperationExp, 120 OperationMod, 121 OperationAnd, 122 OperationOr, 123 OperationXor, 124 OperationSl, 125 OperationSr, 126 OperationSpaceship, 127 }; 128:] 129 130------------------------------------------------------------ 131-- Ast Node class members 132------------------------------------------------------------ 133%ast_extra_members 134[: 135 KDevelop::DUContext* ducontext; 136:] 137 138------------------------------------------------------------ 139-- Parser class members 140------------------------------------------------------------ 141 142%parserclass (public declaration) 143[: 144 /** 145 * Transform the raw input into tokens. 146 * When this method returns, the parser's token stream has been filled 147 * and any parse*() method can be called. 148 */ 149 void tokenize(const QString& contents, int initialState = Lexer::HtmlState); 150 151 enum ProblemType { 152 Error, 153 Warning, 154 Info, 155 Todo 156 }; 157 KDevelop::ProblemPointer reportProblem( Parser::ProblemType type, const QString& message, int tokenOffset = -1 ); 158 QList<KDevelop::ProblemPointer> problems() { 159 return m_problems; 160 } 161 QString tokenText(qint64 begin, qint64 end); 162 void setDebug(bool debug); 163 void setCurrentDocument(KDevelop::IndexedString url); 164 void setTodoMarkers(const QStringList& markers); 165 void extractTodosFromComment(const QString& comment, qint64 offset); 166 167 enum InitialLexerState { 168 HtmlState = 0, 169 DefaultState = 1 170 }; 171 172:] 173 174%parserclass (private declaration) 175[: 176 enum VarExpressionState { 177 Normal, 178 OnlyVariable, 179 OnlyNewObject 180 }; 181 QString m_contents; 182 bool m_debug; 183 KDevelop::IndexedString m_currentDocument; 184 QList<KDevelop::ProblemPointer> m_problems; 185 186 struct ParserState { 187 VarExpressionState varExpressionState; 188 bool varExpressionIsVariable; 189 }; 190 ParserState m_state; 191 192 QRegularExpression m_todoMarkers; 193:] 194 195%parserclass (constructor) 196[: 197 m_state.varExpressionState = Normal; 198 m_state.varExpressionIsVariable = false; 199:] 200 201 202%token_stream TokenStream ;; 203 204----------------------------------------------------------- 205-- List of defined tokens 206----------------------------------------------------------- 207 208-- keywords: 209%token ABSTRACT ("abstract"), BREAK ("break"), CASE ("case"), CATCH ("catch"), 210 CLASS ("class"), CONST ("const"), CONTINUE ("continue"), 211 DEFAULT ("default"), DO ("do"), ELSE ("else"), EXTENDS ("extends"), 212 FINAL ("final"), FOR ("for"), IF ("if"), 213 IMPLEMENTS ("implements"), INSTANCEOF ("instanceof"), INTERFACE ("interface"), 214 NEW ("new"), PRIVATE ("private"), PROTECTED ("protected"), PUBLIC ("public"), 215 RETURN ("return"), STATIC ("static"), SWITCH ("switch"), THROW ("throw"), 216 TRY ("try"), WHILE ("while"), ECHO ("echo"), PRINT ("print"), FINALLY ("finally"), 217 CLONE ("clone"), EXIT ("exit"), ELSEIF ("elseif"), ENDIF ("endif"), 218 ENDWHILE ("endwhile"), ENDFOR ("endfor"), FOREACH ("foreach"), ENDFOREACH ("endforeach"), 219 DECLARE ("declare"), ENDDECLARE ("enddeclare"), AS ("as"), ENDSWITCH ("endswitch"), 220 FUNCTION ("function"), USE ("use"), GLOBAL ("global"), VAR ("var "), UNSET ("unset"), 221 ISSET ("isset"), EMPTY ("empty"), HALT_COMPILER ("halt compiler"), 222 DOUBLE_ARROW ("=>"), LIST ("list"), ARRAY ("array"), CLASS_C ("__CLASS__"), 223 METHOD_C ("__METHOD__"), FUNC_C ("__FUNCTION__"), LINE ("__LINE__"), 224 FILE ("__FILE__"), COMMENT ("comment"), DOC_COMMENT ("doc comment"), PAAMAYIM_NEKUDOTAYIM ("::"), 225 INCLUDE ("include"), INCLUDE_ONCE ("include_once"), EVAL ("eval"), REQUIRE ("require"), 226 REQUIRE_ONCE ("require_once"), NAMESPACE ("namespace"), NAMESPACE_C("__NAMESPACE__"), USE("use"), 227 GOTO ("goto"), TRAIT ("trait"), INSTEADOF ("insteadof"), CALLABLE ("callable"), 228 VOID ("void"), DIR ("__DIR__"), TRAIT_C ("__TRAIT__"), YIELD ("yield"), YIELD_FROM("yield from") ;; 229 230-- casts: 231%token INT_CAST ("int cast"), DOUBLE_CAST ("double cast"), STRING_CAST ("string cast"), 232 ARRAY_CAST ("array cast"), OBJECT_CAST ("object cast"), BOOL_CAST ("bool cast"), 233 UNSET_CAST ("unset cast") ;; 234 235-- seperators: 236%token SEMICOLON (";"), DOUBLE_QUOTE ("\""), LBRACKET ("["), 237 RBRACKET ("]"), 238 LPAREN ("("), RPAREN (")"), LBRACE ("{"), RBRACE ("}"), 239 COMMA (","), AT ("@"), 240 CURLY_OPEN ("curly open"), -- { in "{$foo}"; not the same as LBRACE 241 DOLLAR_OPEN_CURLY_BRACES ("${"), 242 START_HEREDOC ("start heredoc"), END_HEREDOC ("end heredoc"), 243 BACKTICK ("`"), BACKSLASH ("\\"), 244 START_NOWDOC("start nowdoc"), END_NOWDOC("end nowdoc") ;; 245 246-- operators: 247%token IS_EQUAL ("=="), IS_NOT_EQUAL ("!="), IS_IDENTICAL ("==="), 248 IS_NOT_IDENTICAL ("!=="), IS_SMALLER ("<"), IS_GREATER (">"), 249 IS_SMALLER_OR_EQUAL ("<="), IS_GREATER_OR_EQUAL (">="), 250 BOOLEAN_OR ("||"), BOOLEAN_AND ("&&"), ASSIGN ("="), EXP_ASSIGN("**="), 251 PLUS_ASSIGN ("+="), MINUS_ASSIGN ("-="), MUL_ASSIGN ("*="), DIV_ASSIGN ("/="), 252 CONCAT_ASSIGN (".="), MOD_ASSIGN ("%="), AND_ASSIGN ("&="), OR_ASSIGN ("|="), 253 XOR_ASSIGN ("^="), SL_ASSIGN ("<<="), SR_ASSIGN (">>="), OBJECT_OPERATOR ("->"), 254 PLUS ("+"), MINUS("-"), CONCAT("."), 255 INC ("++"), DEC ("--"), BANG ("!"), QUESTION ("?"), COLON (":"), 256 BIT_AND ("&"), BIT_OR("|"), BIT_XOR ("^"), 257 SL ("<<"), SR (">>"), MUL("*"), DIV("/"), MOD ("%"), 258 TILDE ("~"), DOLLAR ("$"), EXP ("**"), ELLIPSIS ("..."), 259 NULL_COALESCE ("??"), SPACESHIP ("<=>"), 260 LOGICAL_OR ("logical or"), LOGICAL_AND ("logical and"), LOGICAL_XOR ("logical xor") ;; 261 262-- literals and identifiers: 263%token INLINE_HTML ("inline html"), WHITESPACE ("whitespace"), 264 CONSTANT_ENCAPSED_STRING ("constant encapsed string"), 265 VARIABLE ("variable"), ENCAPSED_AND_WHITESPACE ("encapsed and whitespace"), 266 DNUMBER ("double number"), LNUMBER ("long number"), 267 NUM_STRING ("num string"), STRING ("string"), 268 STRING_VARNAME ("string varname") ;; -- when in "${varname}" 269 270-- open/close tags 271%token OPEN_TAG ("<?"), CLOSE_TAG ("?>"), OPEN_TAG_WITH_ECHO ("<?=");; 272 273-- token that makes the parser fail in any case: 274%token INVALID ("invalid token") ;; 275 276 277 278-- The actual grammar starts here. 279 280#statements=outerTopStatement* 281-> start ;; 282 283 namespaceDeclaration=namespaceDeclarationStatement 284 | statement=topStatement 285-> outerTopStatement ;; 286 287-- first/first conflict for FUNCTION 288 (?[: (LA(1).kind == Token_FUNCTION && ((LA(2).kind == Token_BIT_AND && LA(3).kind == Token_LPAREN) 289 || LA(2).kind == Token_LPAREN)) 290 || LA(1).kind != Token_FUNCTION :] 291 statement=statement ) 292 | functionDeclaration=functionDeclarationStatement 293 | classDeclaration=classDeclarationStatement 294 | traitDeclaration=traitDeclarationStatement 295 | interfaceDeclaration=interfaceDeclarationStatement 296 | HALT_COMPILER LPAREN RPAREN SEMICOLON -- Lexer stops allready 297-> topStatement ;; 298 299[: bool reported = false; while ( true ) { :] 300 try/recover(#statements=topStatement)* 301[: if (yytoken != Token_RBRACE && yytoken != Token_EOF && yytoken != Token_CLOSE_TAG 302 && yytoken != Token_ELSEIF && yytoken != Token_ELSE 303 && yytoken != Token_ENDIF && yytoken != Token_ENDFOREACH && yytoken != Token_ENDFOR 304 && yytoken != Token_ENDWHILE && yytoken != Token_ENDSWITCH && yytoken != Token_ENDDECLARE 305 && yytoken != Token_CASE && yytoken != Token_DEFAULT) { 306 if (!reported) { 307 qint64 index = tokenStream->index() - 1; 308 Token &token = tokenStream->at(index); 309 QString tokenValue = token.kind != 0 ? tokenText(token.begin, token.end) : QStringLiteral("EOF"); 310 reportProblem(Error, QStringLiteral("Unexpected token \"%1\".").arg(tokenValue)); 311 reported = true; 312 } 313 yylex(); 314 } else { 315 break; 316 } 317} :] 318-> innerStatementList ;; 319 320--Operator Precedence, from PHP Manual 321--left or 322--left xor 323--left and 324--right print 325--right = += -= *= /= .= %= &= |= ^= <<= >>= assignment 326--left ? : ternary 327--right ?? comparison 328--left || logical 329--left && logical 330--left | bitwise 331--left ^ bitwise 332--left & bitwise and references 333--non-associative == != === !== <=> comparison 334--non-associative < <= > >= comparison 335--left << >> bitwise 336--left + - . arithmetic and string 337--left * / % arithmetic 338--non-associative ! ~ - (int) (float) (string) (array) (object) @ types 339--non-associative ++ -- increment/decrement 340--left [ array() 341--non-associative new new 342 343 expression=logicalOrExpression 344-> expr ;; 345 346 #expression=logicalXorExpression @ LOGICAL_OR 347-> logicalOrExpression ;; 348 349 #expression=logicalAndExpression @ LOGICAL_XOR 350-> logicalXorExpression ;; 351 352 #expression=printExpression @ LOGICAL_AND 353-> logicalAndExpression ;; 354 355 (print=PRINT | 0) expression=assignmentExpression 356-> printExpression ;; 357 358-- leftside must me a variable, we check afterwards if it was a variable and 359-- if not we report an error 3600 --needed for line below 361[: m_state.varExpressionIsVariable = false; :] --reset flag 362expression=conditionalExpression 363( 364 assignmentExpressionEqual=assignmentExpressionEqual | ( 365 ( 366 PLUS_ASSIGN [: (*yynode)->operation = OperationPlus; :] 367 | MINUS_ASSIGN [: (*yynode)->operation = OperationMinus; :] 368 | MUL_ASSIGN [: (*yynode)->operation = OperationMul; :] 369 | EXP_ASSIGN [: (*yynode)->operation = OperationExp; :] 370 | DIV_ASSIGN [: (*yynode)->operation = OperationDiv; :] 371 | CONCAT_ASSIGN [: (*yynode)->operation = OperationConcat; :] 372 | MOD_ASSIGN [: (*yynode)->operation = OperationMod; :] 373 | AND_ASSIGN [: (*yynode)->operation = OperationAnd; :] 374 | OR_ASSIGN [: (*yynode)->operation = OperationOr; :] 375 | XOR_ASSIGN [: (*yynode)->operation = OperationXor; :] 376 | SL_ASSIGN [: (*yynode)->operation = OperationSl; :] 377 | SR_ASSIGN [: (*yynode)->operation = OperationSr; :] 378 ) 379 assignmentExpressionCheckIfVariable 380 assignmentExpression=assignmentExpression) 381 | 0) 382-> assignmentExpression [ 383 member variable operation: OperationType; 384];; 385 386--=& is special: 387 -- $foo =& $var; is allowed but not $foo =& 'static'; 388 -- $foo =& new bar(); is allowed too but deprecated and reports a warning 389 --we set a flag (varExpressionState) with that var_expression accepts only valid parts 390 --this is done in such a strage way because we need the full expression to allow 391 --things like $foo =& $bar || e(); 392ASSIGN 393 assignmentExpressionCheckIfVariable --as in assignmentExpression 394 (BIT_AND [: if (yytoken == Token_NEW) { 395 reportProblem(Warning, QStringLiteral("=& new foo() is deprecated"), -2); 396 m_state.varExpressionState = OnlyNewObject; 397 } else { 398 m_state.varExpressionState = OnlyVariable; 399 }:] 400 | 0) assignmentExpression=assignmentExpression [: m_state.varExpressionState = Normal; :] 401-> assignmentExpressionEqual ;; 402 403 404-- check if var_expression was a variable, if not report an error 405-- varExpressionIsVariable is set in var_expression 4060 --to allow cpp-code 407[: 408 if (!m_state.varExpressionIsVariable) { 409 reportProblem(Error, QStringLiteral("Left side is not a variable")); 410 return false; 411 } 412:] 413-> assignmentExpressionCheckIfVariable ;; 414 415expression=nullCoalesceExpression 416 ( QUESTION (ifExpression=expr|0) 417 COLON elseExpression=conditionalExpression 418 | 0 419 ) 420-> conditionalExpression ;; 421 422 #expression=booleanOrExpression @ NULL_COALESCE 423-> nullCoalesceExpression ;; 424 425 #expression=booleanAndExpression @ BOOLEAN_OR 426-> booleanOrExpression ;; 427 428 #expression=bitOrExpression @ BOOLEAN_AND 429-> booleanAndExpression ;; 430 431 #expression=bitXorExpression @ BIT_OR 432-> bitOrExpression ;; 433 434 #expression=bitAndExpression @ BIT_XOR 435-> bitXorExpression ;; 436 437 #expression=equalityExpression @ BIT_AND 438-> bitAndExpression ;; 439 440 expression=relationalExpression 441 (additionalExpression=equalityExpressionRest | 0) 442-> equalityExpression ;; 443 444 ( IS_EQUAL | IS_NOT_EQUAL | IS_IDENTICAL | IS_NOT_IDENTICAL | SPACESHIP [: (*yynode)->operation = OperationSpaceship; :] ) 445 expression=relationalExpression 446-> equalityExpressionRest [ 447 member variable operation: OperationType; 448];; 449 450 451 expression=shiftExpression 452 ( additionalExpression=relationalExpressionRest 453 --instanceof as in java.g (correct??) 454 | INSTANCEOF instanceofType=classNameReference 455 | 0 456 ) 457-> relationalExpression ;; 458 459 ( IS_SMALLER | IS_GREATER | IS_SMALLER_OR_EQUAL | IS_GREATER_OR_EQUAL ) 460 expression=shiftExpression 461-> relationalExpressionRest ;; 462 463 464 expression=additiveExpression 465 (#additionalExpression=shiftExpressionRest)* 466-> shiftExpression ;; 467 468 ( SL | SR ) 469 expression=additiveExpression 470-> shiftExpressionRest ;; 471 472 473 expression=multiplicativeExpression 474 (#additionalExpression=additiveExpressionRest)* 475-> additiveExpression ;; 476 477 ( 478 PLUS [: (*yynode)->operation = OperationPlus; :] 479 | MINUS [: (*yynode)->operation = OperationMinus; :] 480 | CONCAT [: (*yynode)->operation = OperationConcat; :] 481 ) 482 expression=multiplicativeExpression 483-> additiveExpressionRest [ 484 member variable operation: OperationType; 485];; 486 487 488 expression=unaryExpression 489 (#additionalExpression=multiplicativeExpressionRest)* 490-> multiplicativeExpression ;; 491 492 ( 493 MUL [: (*yynode)->operation = OperationMul; :] 494 | DIV [: (*yynode)->operation = OperationDiv; :] 495 | EXP [: (*yynode)->operation = OperationExp; :] 496 | MOD [: (*yynode)->operation = OperationMod; :] 497 ) 498 expression=unaryExpression 499-> multiplicativeExpressionRest [ 500 member variable operation: OperationType; 501];; 502 503 ( 504 MINUS unaryExpression=unaryExpression 505 | PLUS unaryExpression=unaryExpression 506 | BANG unaryExpression=unaryExpression 507 | TILDE unaryExpression=unaryExpression 508 | INT_CAST unaryExpression=unaryExpression [: (*yynode)->castType = CastInt; :] 509 | DOUBLE_CAST unaryExpression=unaryExpression [: (*yynode)->castType = CastDouble; :] 510 | STRING_CAST unaryExpression=unaryExpression [: (*yynode)->castType = CastString; :] 511 | ARRAY_CAST unaryExpression=unaryExpression [: (*yynode)->castType = CastArray; :] 512 | OBJECT_CAST unaryExpression=unaryExpression [: (*yynode)->castType = CastObject; :] 513 | BOOL_CAST unaryExpression=unaryExpression [: (*yynode)->castType = CastBool; :] 514 | UNSET_CAST unaryExpression=unaryExpression [: (*yynode)->castType = CastUnset; :] 515 | AT unaryExpression=unaryExpression 516 | LIST LPAREN assignmentList=assignmentList RPAREN ASSIGN unaryExpression=unaryExpression 517 | EXIT (LPAREN (expression=expr | 0) RPAREN | 0) 518 | EVAL LPAREN expression=expr RPAREN 519 | INCLUDE includeExpression=unaryExpression 520 | INCLUDE_ONCE includeExpression=unaryExpression 521 | REQUIRE includeExpression=unaryExpression 522 | REQUIRE_ONCE includeExpression=unaryExpression 523 524 | unaryExpressionNotPlusminus=unaryExpressionNotPlusminus 525 ) 526-> unaryExpression [ 527 member variable castType: CastType; 528];; 529 530 (#prefixOperator=postprefixOperator)* 531 varExpression=varExpression 532 (#postfixOperator=postprefixOperator)* 533-> unaryExpressionNotPlusminus ;; 534 535 op=INC | op=DEC 536-> postprefixOperator ;; 537 538-- 10 first follow conflicts because we go back up the chain (affects both print and yield) 539 (print=PRINT+) printExpression=assignmentExpression 540 | isGenerator=YIELD (generatorExpression=printExpression ( DOUBLE_ARROW generatorValueExpr=printExpression | 0 ) | 0) 541 | isGenerator=YIELD_FROM generatorExpression=printExpression 542--first/first conflict - no problem because of ifs 543 | ?[: m_state.varExpressionState == OnlyVariable :] 0 [: m_state.varExpressionState = Normal; :] variable=variable 544 | ?[: m_state.varExpressionState == OnlyNewObject :] 0 [: m_state.varExpressionState = Normal; :] newObject=varExpressionNewObject 545 | varExpressionNormal=varExpressionNormal 546 | varExpressionArray=varExpressionArray arrayIndex=arrayIndexSpecifier* 547-> varExpression ;; 548 549 (?[: LA(1).kind == Token_LPAREN && LA(2).kind == Token_FUNCTION && LA(3).kind == Token_LPAREN :] iife=iifeSyntax ) 550 | LPAREN try/rollback (newObject=varExpressionNewObject RPAREN (#variableProperties=instantiationAccess*)) 551 catch (expression=expr RPAREN) 552 | BACKTICK encapsList=encapsList BACKTICK 553 --try/rollback resolves conflict scalar vs. staticMember (foo::bar vs. foo::$bar) 554 --varExpressionIsVariable flag is needed for assignmentExpression 555 | try/rollback (variable=variable [: m_state.varExpressionIsVariable = true; :]) 556 catch (scalar=scalar) 557 | ISSET LPAREN (#issetVariable=variable @ COMMA) RPAREN 558 | EMPTY LPAREN emptyExpression=expr RPAREN 559 | newObject=varExpressionNewObject 560 | CLONE cloneCar=varExpressionNormal 561 | closure=closure 562-> varExpressionNormal ;; 563 564 ARRAY LPAREN 565 (#arrayValues=arrayPairValue 566 -- break because array(1,) is allowed (solves FIRST/FOLLOW conflict) 567 @ (COMMA [: if (yytoken == Token_RPAREN) { break; } :] ) | 0) 568 RPAREN 569 | LBRACKET 570 (#arrayValues=arrayPairValue 571 -- break because [1,] is allowed (solves FIRST/FOLLOW conflict) 572 @ (COMMA [: if (yytoken == Token_RBRACKET) { break; } :] ) | 0) 573 RBRACKET 574-> varExpressionArray ;; 575 576-- https://wiki.php.net/rfc/closures 577 FUNCTION (isRef=BIT_AND|0) LPAREN parameters=parameterList RPAREN 578 ( USE LPAREN lexicalVars=lexicalVarList RPAREN | 0) 579 ( COLON returnType=returnType | 0) 580 LBRACE try/recover(functionBody=innerStatementList) RBRACE 581-> closure ;; 582 583 LPAREN try/rollback (closure=closure RPAREN LPAREN parameterList=functionCallParameterList RPAREN) 584 catch (expression=expr RPAREN) 585-> iifeSyntax ;; 586 587 (#lexicalVars=lexicalVar @ COMMA) | 0 [: reportProblem(Error, QStringLiteral("Use list of closure must not be empty.")); :] 588-> lexicalVarList ;; 589 590 (isRef=BIT_AND | 0) variable=variableIdentifier 591-> lexicalVar ;; 592 593 NEW classNameReference=classNameReference ctor=ctorArguments 594-> varExpressionNewObject ;; 595 596 LPAREN parameterList=functionCallParameterList RPAREN 597 | 0 598-> ctorArguments ;; 599 600 #parameters=functionCallParameterListElement @ COMMA | 0 601-> functionCallParameterList ;; 602 603 (BIT_AND variable=variable) | (isVariadic=ELLIPSIS | 0) expr=expr 604-> functionCallParameterListElement ;; 605 606 #element=assignmentListElement @COMMA 607-> assignmentList ;; 608 609 variable=variable 610 | LIST LPAREN assignmentList=assignmentList RPAREN 611 | 0 612-> assignmentListElement ;; 613 614 expr=expr (DOUBLE_ARROW (exprValue=expr | BIT_AND varValue=variable) | 0) 615 | BIT_AND variable=variable 616-> arrayPairValue ;; 617 618 var=baseVariableWithFunctionCalls (#variableProperties=variableObjectProperty*) 619-> variable ;; 620 621 OBJECT_OPERATOR 622 | PAAMAYIM_NEKUDOTAYIM 623-> objectOperator ;; 624 625 ( ?[: LA(1).kind == Token_DOLLAR:] LBRACE variable=variable RBRACE | objectProperty=objectProperty ) 626 (isFunctionCall=LPAREN parameterList=functionCallParameterList RPAREN arrayIndex=arrayIndexSpecifier* | 0) 627-> variableProperty ;; 628 629 objectOperator variableProperty=variableProperty 630-> variableObjectProperty ;; 631 632 OBJECT_OPERATOR variableProperty=variableProperty 633-> instantiationAccess ;; 634 635 --Conflict 636 -- foo::$bar[0] (=baseVariable-staticMember) 637 --vs.foo::$bar[0](); (=static function call) 638 try/rollback (functionCall=functionCall arrayIndex=arrayIndexSpecifier*) 639 catch (baseVariable=baseVariable) 640-> baseVariableWithFunctionCalls ;; 641 642 LBRACKET (expr=expr | 0) RBRACKET 643-> arrayIndexSpecifier ;; 644 645 LBRACKET (expr=expr) RBRACKET 646-> stringIndexSpecifier ;; 647 648 stringFunctionNameOrClass=namespacedIdentifier ( 649 LPAREN stringParameterList=functionCallParameterList RPAREN 650 | PAAMAYIM_NEKUDOTAYIM 651 ( 652 stringFunctionName=semiReservedIdentifier LPAREN stringParameterList=functionCallParameterList RPAREN 653 | varFunctionName=variableWithoutObjects LPAREN stringParameterList=functionCallParameterList RPAREN 654 | LBRACE (expr=expr) RBRACE LPAREN stringParameterList=functionCallParameterList RPAREN 655 ) 656 ) 657 | varFunctionName=variableWithoutObjects LPAREN varParameterList=functionCallParameterList RPAREN 658-> functionCall ;; 659 660 var=compoundVariableWithSimpleIndirectReference #offsetItems=dimListItem* 661 | staticMember=staticMember 662-> baseVariable ;; 663 664 variable=variableIdentifier 665 | DOLLAR LBRACE expr=expr RBRACE 666-> compoundVariable ;; 667 668 ( DOLLAR ( DOLLAR+ | 0 ) ( indirectVariable=variableIdentifier | LBRACE expr=expr RBRACE ) | variable=variableIdentifier ) 669-> compoundVariableWithSimpleIndirectReference ;; 670 671 className=namespacedIdentifier staticProperty=staticProperty 672-> staticMember ;; 673 674 LBRACE try/recover(statements=innerStatementList) RBRACE 675 | IF LPAREN ifExpr=expr RPAREN 676 ( COLON statements=innerStatementList newElseifList newElseSingle ENDIF semicolonOrCloseTag 677 | ifStatement=statement elseifList=elseifList elseSingle=elseSingle 678 ) 679 | WHILE LPAREN whileExpr=expr RPAREN whileStatement=whileStatement 680 | FOR LPAREN forExpr1=forExpr SEMICOLON forExpr2=forExpr 681 SEMICOLON forExpr3=forExpr RPAREN forStatement=forStatement 682 | SWITCH LPAREN swtichExpr=expr RPAREN switchCaseList=switchCaseList 683 684 | FOREACH LPAREN ( 685 -- allow $var as &$i and not expr() as &$i 686 try/rollback(foreachVar=variable AS foreachVarAsVar=foreachVariable) 687 catch(foreachExpr=expr AS foreachExprAsVar=variable)) 688 (DOUBLE_ARROW foreachVariable=foreachVariable | 0) RPAREN 689 foreachStatement=foreachStatement 690 | DECLARE LPAREN declareItem=declareItem @ COMMA RPAREN declareStatement 691 | SEMICOLON -- empty statement 692 | TRY LBRACE try/recover(statements=innerStatementList) RBRACE 693 #catches=catchItem* 694 (FINALLY LBRACE finallyBody=innerStatementList RBRACE | 0) 695 | UNSET LPAREN #unsetVariables=variable @ COMMA RPAREN semicolonOrCloseTag 696 -- fix first/follow with goto target 697 | ( ?[: LA(1).kind != Token_STRING || LA(2).kind != Token_COLON :] expr=expr semicolonOrCloseTag ) 698 | DO doStatement=statement WHILE LPAREN whileExpr=expr RPAREN semicolonOrCloseTag 699 | BREAK (breakExpr=expr | 0) semicolonOrCloseTag 700 | CONTINUE (continueExpr=expr | 0) semicolonOrCloseTag 701 | RETURN (returnExpr=expr | 0) semicolonOrCloseTag 702 | GLOBAL #globalVars=globalVar @ COMMA semicolonOrCloseTag 703 | STATIC #staticVars=staticVar @ COMMA semicolonOrCloseTag 704 | ECHO #echoExprs=expr @ COMMA semicolonOrCloseTag 705 | THROW throwExpr=expr semicolonOrCloseTag 706 -- throws error in zend parser, so ignored | USE use_filename semicolonOrCloseTag 707 708 | CLOSE_TAG 709 | OPEN_TAG 710 | OPEN_TAG_WITH_ECHO expr=expr semicolonOrCloseTag 711 | INLINE_HTML 712 | CONST #consts=constantDeclaration @ COMMA SEMICOLON 713 | USE useStatement=useStatement 714 | GOTO gotoLabel=STRING SEMICOLON 715 | gotoTarget=STRING COLON 716-> statement ;; 717 718 ( useFunction=FUNCTION | useConst=CONST | 0 ) #useNamespace=useNamespace @ COMMA SEMICOLON 719-> useStatement ;; 720 721 identifier=namespacedIdentifier (AS aliasIdentifier=identifier | 0) 722-> useNamespace ;; 723 724 identifier=identifier ASSIGN scalar=expr 725-> constantDeclaration ;; 726 727 identifier=semiReservedIdentifier ASSIGN scalar=expr 728-> classConstantDeclaration ;; 729 730 SEMICOLON | CLOSE_TAG 731-> semicolonOrCloseTag ;; 732 733 LBRACE (SEMICOLON | 0) try/recover(caseList=caseList) RBRACE 734 | COLON (SEMICOLON | 0) caseList=caseList ENDSWITCH semicolonOrCloseTag 735-> switchCaseList ;; 736 737 #caseItems=case_item* 738-> caseList ;; 739 740 CASE expr=expr (COLON | SEMICOLON) statements=innerStatementList 741 | def=DEFAULT (COLON | SEMICOLON) statements=innerStatementList 742-> case_item ;; 743 744 CATCH LPAREN #catchClass=namespacedIdentifier @ BIT_OR var=variableIdentifier RPAREN 745 LBRACE try/recover(statements=innerStatementList) RBRACE 746-> catchItem ;; 747 748 statement=statement 749 | COLON statements=innerStatementList ENDDECLARE semicolonOrCloseTag 750-> declareStatement ;; 751 752 STRING ASSIGN scalar=staticScalar 753-> declareItem ;; 754 755 (BIT_AND | 0) variable=variable 756-> foreachVariable ;; 757 758 statement=statement 759 | COLON statements=innerStatementList ENDFOREACH semicolonOrCloseTag 760-> foreachStatement ;; 761 762 var=variableIdentifier (ASSIGN value=staticScalar | 0) 763-> staticVar ;; 764 765 var=variableIdentifier 766 | DOLLAR (dollarVar=variable | LBRACE expr=expr RBRACE) 767-> globalVar ;; 768 769 #exprs=expr @ COMMA | 0 770-> forExpr ;; 771 772 statement=statement 773 | COLON statements=innerStatementList ENDFOR semicolonOrCloseTag 774-> forStatement ;; 775 776 statement=statement 777 | COLON statements=innerStatementList ENDWHILE semicolonOrCloseTag 778-> whileStatement ;; 779 780 --first/follow conflict; todo check if this is a problem 781 #elseifListItem=elseifListItem* 782-> elseifList ;; 783 784 ELSEIF LPAREN expr=expr RPAREN statement=statement 785-> elseifListItem ;; 786 787 ELSE statement=statement | 0 788-> elseSingle ;; 789 790 #newElseifListItem=newelseifListItem* 791-> newElseifList ;; 792 793 ELSEIF LPAREN expr=expr RPAREN COLON statements=innerStatementList 794-> newelseifListItem ;; 795 796 ELSE COLON statements=innerStatementList | 0 797-> newElseSingle ;; 798 799 className=className (staticProperty=staticProperty #properties=classProperty* | 0) 800 | baseVariable=variableWithoutObjects #properties=classProperty* 801-> classNameReference ;; 802 803 identifier=namespacedIdentifier 804 | staticIdentifier = STATIC 805-> className ;; 806 807 PAAMAYIM_NEKUDOTAYIM staticProperty=compoundVariableWithSimpleIndirectReference #offsetItems=dimListItem* 808-> staticProperty ;; 809 810 (staticProperty=staticProperty | OBJECT_OPERATOR property=objectProperty) 811-> classProperty ;; 812 813 objectDimList=objectDimList 814 | variableWithoutObjects=variableWithoutObjects 815-> objectProperty ;; 816 817 variableName=variableName #offsetItems=dimListItem* 818-> objectDimList ;; 819 820 variable=compoundVariableWithSimpleIndirectReference #offsetItems=dimListItem* 821-> variableWithoutObjects ;; 822 823arrayIndex=arrayIndexSpecifier | LBRACE expr=expr RBRACE 824-> dimListItem ;; 825 826 name=identifier 827 | LBRACE expr=expr RBRACE 828-> variableName ;; 829 830 commonScalar=commonScalar 831 | constantOrClassConst=constantOrClassConst #offsetItem=dimListItem* 832 | varname=STRING_VARNAME 833 | DOUBLE_QUOTE encapsList=encapsList DOUBLE_QUOTE stringIndex=stringIndexSpecifier* 834 | START_HEREDOC encapsList=encapsList END_HEREDOC 835-> scalar ;; 836 837 constant=namespacedIdentifier 838 ( PAAMAYIM_NEKUDOTAYIM classConstant=classConstant | 0 ) 839-> constantOrClassConst ;; 840 841 semiReservedIdentifier 842-> classConstant ;; 843 844 #encaps=encaps* 845-> encapsList ;; 846 847 var=encapsVar | value=ENCAPSED_AND_WHITESPACE 848-> encaps ;; 849 850 -- first/first conflict resolved by LA(2) 851 --(expr allows STRING_VARNAME too - but without [expr]) 852 DOLLAR_OPEN_CURLY_BRACES ( ?[: LA(2).kind == Token_LBRACKET:] STRING_VARNAME arrayIndex=arrayIndexSpecifier RBRACE 853 | expr=expr RBRACE ) 854 | variable=variableIdentifier (OBJECT_OPERATOR propertyIdentifier=identifier | LBRACKET offset=encapsVarOffset RBRACKET | 0) 855 | CURLY_OPEN expr=expr RBRACE 856-> encapsVar ;; 857 858 STRING 859 | NUM_STRING 860 | variableIdentifier 861-> encapsVarOffset ;; 862 863 864 LNUMBER [: (*yynode)->scalarType = ScalarTypeInt; :] 865 | DNUMBER [: (*yynode)->scalarType = ScalarTypeFloat; :] 866 | string=CONSTANT_ENCAPSED_STRING [: (*yynode)->scalarType = ScalarTypeString; :] stringIndex=stringIndexSpecifier* 867 | LINE [: (*yynode)->scalarType = ScalarTypeInt; :] 868 | DIR [: (*yynode)->scalarType = ScalarTypeString; :] 869 | FILE [: (*yynode)->scalarType = ScalarTypeString; :] 870 | CLASS_C [: (*yynode)->scalarType = ScalarTypeString; :] 871 | TRAIT_C [: (*yynode)->scalarType = ScalarTypeString; :] 872 | METHOD_C [: (*yynode)->scalarType = ScalarTypeString; :] 873 | FUNC_C [: (*yynode)->scalarType = ScalarTypeString; :] 874 | NAMESPACE_C [: (*yynode)->scalarType = ScalarTypeString; :] 875 | START_NOWDOC STRING END_NOWDOC [: (*yynode)->scalarType = ScalarTypeString; :] 876-> commonScalar [ 877 member variable scalarType: ScalarTypes; 878] ;; 879 880 FUNCTION (BIT_AND | 0) functionName=identifier 881 LPAREN parameters=parameterList RPAREN (COLON returnType=returnType | 0) 882 LBRACE try/recover(functionBody=innerStatementList) RBRACE 883-> functionDeclarationStatement ;; 884 885 (#parameters=parameter @ COMMA) | 0 886-> parameterList ;; 887 888(parameterType=parameterType | 0) (isRef=BIT_AND | 0) 889 (isVariadic=ELLIPSIS | 0) variable=variableIdentifier (ASSIGN defaultValue=expr | 0) 890-> parameter ;; 891 892 genericType=namespacedIdentifier 893 | arrayType=ARRAY 894 | callableType=CALLABLE 895-> genericTypeHint ;; 896 897 (isNullable=QUESTION | 0) typehint=genericTypeHint 898-> parameterType ;; 899 900 (isNullable=QUESTION | 0) ( 901 typehint=genericTypeHint 902 | voidType=VOID 903 ) 904-> returnType ;; 905 906 value=commonScalar 907 | constantOrClassConst=constantOrClassConst 908 | PLUS plusValue=staticScalar 909 | MINUS minusValue=staticScalar 910 | array=ARRAY LPAREN 911 (#arrayValues=staticArrayPairValue 912 -- break because array(1,) is allowed 913 @ (COMMA [: if (yytoken == Token_RPAREN) { break; } :] ) | 0) 914 RPAREN 915 | array=LBRACKET 916 (#arrayValues=staticArrayPairValue 917 -- break because [1,] is allowed 918 @ (COMMA [: if (yytoken == Token_RBRACKET) { break; } :] ) | 0) 919 RBRACKET 920-> staticScalar ;; 921 922 #val1=staticScalar (DOUBLE_ARROW #val2=staticScalar | 0) 923-> staticArrayPairValue ;; 924 925 (isGlobal=BACKSLASH | 0) 926 #namespaceName=identifier+ @ BACKSLASH 927-> namespacedIdentifier ;; 928 929 string=STRING 930-> identifier ;; 931 932 INCLUDE | INCLUDE_ONCE | EVAL | REQUIRE | REQUIRE_ONCE | LOGICAL_OR | LOGICAL_XOR | LOGICAL_AND 933 | INSTANCEOF | NEW | CLONE | EXIT | IF | ELSEIF | ELSE | ENDIF | ECHO | DO | WHILE | ENDWHILE 934 | FOR | ENDFOR | FOREACH | ENDFOREACH | DECLARE | ENDDECLARE | AS | TRY | CATCH | FINALLY 935 | THROW | USE | INSTEADOF | GLOBAL | VAR | UNSET | ISSET | EMPTY | CONTINUE | GOTO 936 | FUNCTION | CONST | RETURN | PRINT | YIELD | LIST | SWITCH | ENDSWITCH | CASE | DEFAULT | BREAK 937 | ARRAY | CALLABLE | EXTENDS | IMPLEMENTS | NAMESPACE | TRAIT | INTERFACE | CLASS 938 | CLASS_C | TRAIT_C | FUNC_C | METHOD_C | LINE | FILE | DIR | NAMESPACE_C 939-> reservedNonModifiers ;; 940 941 reservedNonModifiers 942 | STATIC | ABSTRACT | FINAL | PRIVATE | PROTECTED | PUBLIC 943-> semiReserved ;; 944 945 identifier 946[: 947 qint64 index = tokenStream->index() - 2; 948 (*yynode)->string = index; 949:] 950 | semiReserved 951[: 952 qint64 index = tokenStream->index() - 2; 953 (*yynode)->string = index; 954:] 955-> semiReservedIdentifier [ 956 member variable string: qint64; 957] ;; 958 959 identifier 960[: 961 qint64 index = tokenStream->index() - 2; 962 (*yynode)->string = index; 963:] 964 | reservedNonModifiers 965[: 966 qint64 index = tokenStream->index() - 2; 967 (*yynode)->string = index; 968:] 969-> reservedNonModifierIdentifier [ 970 member variable string: qint64; 971] ;; 972 973 variable=VARIABLE 974-> variableIdentifier ;; 975 976 NAMESPACE #namespaceName=identifier* @ BACKSLASH 977 ( 978 -- the semicolon case needs at least one namespace identifier, the {...} case not... 979 SEMICOLON [: if (!(*yynode)->namespaceNameSequence) { reportProblem(Error, QStringLiteral("Missing namespace identifier."), -2); } :] 980 | LBRACE try/recover(body=innerStatementList) RBRACE ) 981-> namespaceDeclarationStatement ;; 982 983 INTERFACE interfaceName=identifier (EXTENDS extends=classImplements | 0) 984 LBRACE try/recover(body=classBody) RBRACE 985-> interfaceDeclarationStatement ;; 986 987 TRAIT traitName=identifier 988 LBRACE body=classBody RBRACE 989-> traitDeclarationStatement ;; 990 991 modifier=optionalClassModifier CLASS className=identifier 992 (EXTENDS extends=classExtends | 0) 993 (IMPLEMENTS implements=classImplements | 0) 994 LBRACE body=classBody RBRACE 995-> classDeclarationStatement ;; 996 997identifier=namespacedIdentifier 998-> classExtends ;; 999 1000#implements=namespacedIdentifier @ COMMA 1001-> classImplements ;; 1002 1003-- error recovery, to understand it you probably have to look at the generated code ;-) 1004[: bool reported = false; while ( true ) { :] 1005try/recover(#classStatements=classStatement)* 1006[: if (yytoken != Token_RBRACE && yytoken != Token_EOF && yytoken != Token_CLOSE_TAG) { 1007 if (!reported) { 1008 reportProblem(Error, QStringLiteral("Unexpected token in class context.")); 1009 reported = true; 1010 } 1011 yylex(); 1012 } else { 1013 break; 1014 } 1015} :] 1016 RBRACE [: rewind(tokenStream->index() - 2); :] 1017-> classBody ;; 1018 1019 VAR variable=classVariableDeclaration SEMICOLON 1020 | modifiers=optionalModifiers 1021 ( (propertyType=propertyType | 0) variable=classVariableDeclaration SEMICOLON 1022 | FUNCTION (BIT_AND | 0) methodName=semiReservedIdentifier LPAREN parameters=parameterList RPAREN 1023 ( COLON returnType=returnType | 0) 1024 methodBody=methodBody 1025 | CONST #consts=classConstantDeclaration @ COMMA SEMICOLON 1026 ) 1027 | USE #traits=namespacedIdentifier @ COMMA (imports=traitAliasDeclaration|SEMICOLON) 1028-> classStatement ;; 1029 1030 (isNullable=QUESTION | 0) typehint=propertyTypeHint 1031-> propertyType ;; 1032 1033 ( genericType=namespacedIdentifier 1034 | arrayType=ARRAY ) 1035 [: (*yynode)->callableType = -1; :] 1036-> propertyTypeHint[ 1037 member variable callableType: int; 1038] ;; 1039 1040 LBRACE #statements=traitAliasStatement 1041 @ (SEMICOLON [: if (yytoken == Token_RBRACE) { break; } :]) RBRACE 1042-> traitAliasDeclaration ;; 1043 1044 importIdentifier=traitAliasIdentifier 1045-- first/first conflict resolved by LA(2) 1046-- We can either have a single token (modifier or identifier), or a combination 1047 ( AS (?[: LA(2).kind == Token_SEMICOLON :] 1048 (modifiers=traitVisibilityModifiers | aliasNonModifierIdentifier=reservedNonModifierIdentifier) 1049 | modifiers=traitVisibilityModifiers aliasIdentifier=semiReservedIdentifier 1050 ) 1051 | INSTEADOF #conflictIdentifier=namespacedIdentifier @ COMMA 1052 ) 1053-> traitAliasStatement ;; 1054 1055 identifier=namespacedIdentifier PAAMAYIM_NEKUDOTAYIM methodIdentifier=semiReservedIdentifier 1056-> traitAliasIdentifier ;; 1057 1058 SEMICOLON -- abstract method 1059 | LBRACE try/recover(statements=innerStatementList) RBRACE 1060-> methodBody ;; 1061 1062#vars=classVariable @ COMMA 1063-> classVariableDeclaration ;; 1064 1065 variable=variableIdentifier (ASSIGN value=staticScalar | 0) 1066-> classVariable ;; 1067 1068 PUBLIC [: (*yynode)->modifiers |= ModifierPublic; :] 1069 | PROTECTED [: (*yynode)->modifiers |= ModifierProtected; :] 1070 | PRIVATE [: (*yynode)->modifiers |= ModifierPrivate; :] 1071 | STATIC [: (*yynode)->modifiers |= ModifierStatic; :] 1072 | ABSTRACT [: (*yynode)->modifiers |= ModifierAbstract; :] 1073 | FINAL [: (*yynode)->modifiers |= ModifierFinal; :] 1074-> traitVisibilityModifiers[ 1075 member variable modifiers: unsigned int; 1076] ;; 1077 1078 ( 1079 PUBLIC [: (*yynode)->modifiers |= ModifierPublic; :] 1080 | PROTECTED [: (*yynode)->modifiers |= ModifierProtected; :] 1081 | PRIVATE [: (*yynode)->modifiers |= ModifierPrivate; :] 1082 | STATIC [: (*yynode)->modifiers |= ModifierStatic; :] 1083 | ABSTRACT [: (*yynode)->modifiers |= ModifierAbstract; :] 1084 | FINAL [: (*yynode)->modifiers |= ModifierFinal; :] 1085 | 0 1086 )* 1087-> optionalModifiers[ 1088 member variable modifiers: unsigned int; 1089] ;; 1090 1091 ( 1092 ABSTRACT [: (*yynode)->modifier = AbstractClass; :] 1093 | FINAL [: (*yynode)->modifier = FinalClass; :] 1094 | 0 1095 ) 1096-> optionalClassModifier[ 1097 member variable modifier: ClassModifier; 1098] ;; 1099 1100 1101 1102 1103 1104----------------------------------------------------------------- 1105-- Code segments copied to the implementation (.cpp) file. 1106-- If existent, kdevelop-pg's current syntax requires this block 1107-- to occur at the end of the file. 1108----------------------------------------------------------------- 1109 1110[: 1111 1112#include <QtCore/QDebug> 1113#include <language/editor/documentrange.h> 1114 1115namespace Php 1116{ 1117 1118void Parser::tokenize(const QString& contents, int initialState) 1119{ 1120 m_contents = contents; 1121 Lexer lexer(tokenStream, contents, initialState); 1122 int kind = Parser::Token_EOF; 1123 int lastDocCommentBegin; 1124 int lastDocCommentEnd; 1125 1126 do 1127 { 1128 lastDocCommentBegin = 0; 1129 lastDocCommentEnd = 0; 1130 kind = lexer.nextTokenKind(); 1131 while (kind == Parser::Token_WHITESPACE || kind == Parser::Token_COMMENT || kind == Parser::Token_DOC_COMMENT) { 1132 if (kind == Parser::Token_COMMENT || kind == Parser::Token_DOC_COMMENT) { 1133 extractTodosFromComment(tokenText(lexer.tokenBegin(), lexer.tokenEnd()), lexer.tokenBegin()); 1134 } 1135 if (kind == Parser::Token_DOC_COMMENT) { 1136 lastDocCommentBegin = lexer.tokenBegin(); 1137 lastDocCommentEnd = lexer.tokenEnd(); 1138 } 1139 kind = lexer.nextTokenKind(); 1140 } 1141 if ( !kind ) // when the lexer returns 0, the end of file is reached 1142 { 1143 kind = Parser::Token_EOF; 1144 } 1145 Parser::Token &t = tokenStream->push(); 1146 t.begin = lexer.tokenBegin(); 1147 t.end = lexer.tokenEnd(); 1148 t.kind = kind; 1149 t.docCommentBegin = lastDocCommentBegin; 1150 t.docCommentEnd = lastDocCommentEnd; 1151 //if ( m_debug ) qDebug() << kind << tokenText(t.begin,t.end) << t.begin << t.end; 1152 } 1153 while ( kind != Parser::Token_EOF ); 1154 1155 yylex(); // produce the look ahead token 1156} 1157 1158void Parser::extractTodosFromComment(const QString& comment, qint64 startPosition) 1159{ 1160 auto i = m_todoMarkers.globalMatch(comment); 1161 while (i.hasNext()) { 1162 auto match = i.next(); 1163 auto p = reportProblem(Todo, match.captured(1), 0); 1164 if (!p) { 1165 continue; 1166 } 1167 1168 qint64 line = 0; 1169 qint64 column = 0; 1170 tokenStream->locationTable()->positionAt(startPosition, &line, &column); 1171 1172 auto location = p->finalLocation(); 1173 location.setStart(KTextEditor::Cursor(line, column + match.capturedStart(1))); 1174 location.setEnd(KTextEditor::Cursor(line, column + match.capturedEnd(1))); 1175 p->setFinalLocation(location); 1176 }; 1177} 1178 1179void Parser::setTodoMarkers(const QStringList& markers) 1180{ 1181 QString pattern = QStringLiteral("^(?:[/\\*\\s]*)(.*(?:"); 1182 bool first = true; 1183 foreach(const QString& marker, markers) { 1184 if (!first) { 1185 pattern += '|'; 1186 } 1187 pattern += QRegularExpression::escape(marker); 1188 first = false; 1189 } 1190 pattern += QStringLiteral(").*?)(?:[/\\*\\s]*)$"); 1191 m_todoMarkers.setPatternOptions(QRegularExpression::MultilineOption); 1192 m_todoMarkers.setPattern(pattern); 1193} 1194 1195QString Parser::tokenText(qint64 begin, qint64 end) 1196{ 1197 return m_contents.mid(begin,end-begin+1); 1198} 1199 1200 1201KDevelop::ProblemPointer Parser::reportProblem( Parser::ProblemType type, const QString& message, int offset ) 1202{ 1203 qint64 sLine; 1204 qint64 sCol; 1205 qint64 index = tokenStream->index() + offset; 1206 if (index >= tokenStream->size()) { 1207 return {}; 1208 } 1209 tokenStream->startPosition(index, &sLine, &sCol); 1210 qint64 eLine; 1211 qint64 eCol; 1212 tokenStream->endPosition(index, &eLine, &eCol); 1213 auto p = KDevelop::ProblemPointer(new KDevelop::Problem()); 1214 p->setSource(KDevelop::IProblem::Parser); 1215 switch ( type ) { 1216 case Error: 1217 p->setSeverity(KDevelop::IProblem::Error); 1218 break; 1219 case Warning: 1220 p->setSeverity(KDevelop::IProblem::Warning); 1221 break; 1222 case Info: 1223 p->setSeverity(KDevelop::IProblem::Hint); 1224 break; 1225 case Todo: 1226 p->setSeverity(KDevelop::IProblem::Hint); 1227 p->setSource(KDevelop::IProblem::ToDo); 1228 break; 1229 } 1230 p->setDescription(message); 1231 KTextEditor::Range range(sLine, sCol, eLine, eCol + 1); 1232 p->setFinalLocation(KDevelop::DocumentRange(m_currentDocument, range)); 1233 m_problems << p; 1234 return p; 1235} 1236 1237 1238// custom error recovery 1239void Parser::expectedToken(int /*expected*/, qint64 /*where*/, const QString& name) 1240{ 1241 reportProblem( Parser::Error, QStringLiteral("Expected token \"%1\"").arg(name)); 1242} 1243 1244void Parser::expectedSymbol(int /*expectedSymbol*/, const QString& name) 1245{ 1246 qint64 line; 1247 qint64 col; 1248 qint64 index = tokenStream->index()-1; 1249 Token &token = tokenStream->at(index); 1250 qCDebug(PARSER) << "token starts at:" << token.begin; 1251 qCDebug(PARSER) << "index is:" << index; 1252 tokenStream->startPosition(index, &line, &col); 1253 QString tokenValue = tokenText(token.begin, token.end); 1254 qint64 eLine; 1255 qint64 eCol; 1256 tokenStream->endPosition(index, &eLine, &eCol); 1257 reportProblem( Parser::Error, 1258 QStringLiteral("Expected symbol \"%1\" (current token: \"%2\" [%3] at %4:%5 - %6:%7)") 1259 .arg(name, 1260 token.kind != 0 ? tokenValue : QStringLiteral("EOF")) 1261 .arg(token.kind) 1262 .arg(line) 1263 .arg(col) 1264 .arg(eLine) 1265 .arg(eCol)); 1266} 1267 1268void Parser::setDebug( bool debug ) 1269{ 1270 m_debug = debug; 1271} 1272 1273void Parser::setCurrentDocument(KDevelop::IndexedString url) 1274{ 1275 m_currentDocument = url; 1276} 1277 1278 1279Parser::ParserState *Parser::copyCurrentState() 1280{ 1281 ParserState *state = new ParserState(); 1282 state->varExpressionState = m_state.varExpressionState; 1283 state->varExpressionIsVariable = m_state.varExpressionIsVariable; 1284 return state; 1285} 1286 1287void Parser::restoreState( Parser::ParserState* state) 1288{ 1289 m_state.varExpressionState = state->varExpressionState; 1290 m_state.varExpressionIsVariable = state->varExpressionIsVariable; 1291} 1292 1293} // end of namespace Php 1294 1295:] 1296 1297-- kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on; auto-insert-doxygen on; mode KDevelop-PG[-Qt] 1298