Warning, /kdevelop/kdev-php/parser/php.g is written in an unsupported language. File is not indexed.

0001 -------------------------------------------------------------------------------
0002 -- SPDX-FileCopyrightText: 2008 Niko Sams <niko.sams@gmail.com>
0003 --
0004 -- SPDX-License-Identifier: LGPL-2.0-or-later
0005 -----------------------------------------------------------
0006 
0007 
0008 -----------------------------------------------------------
0009 -- Grammar for PHP 5.2
0010 -- Modelled after the Zend Grammar shipped with PHP5.2
0011 -- source, the PHP Language Reference documentation,
0012 -- and parts taken from KDevelop Java Grammar
0013 -----------------------------------------------------------
0014 
0015 -- 4 first/first conflicts:
0016 --  - var_expression: variable vs. varExpressionNormal
0017 --    no problem because of ifs that allow always just one rule
0018 --  - classNameReference: STRING vs. staticMember (foo vs. foo::$bar)
0019 --    resolved by LA()
0020 --  - encapsVar: STRING_VARNAME LBRACKET vs. expr (expr allows STRING_VARNAME too - but not LBRACKET)
0021 --    resolved by LA()
0022 --  - constantOrClassConst: constant vs. class constant (FOO v.s Cls::FOO)
0023 --    resolved by LA() (could be avoided, but the Ast is much cleaner that way)
0024 -- 1 first/follow conflicts:
0025 --  - elseifList: dangling-else conflict - should be ok
0026 
0027 -- TODO: (post 1.0.0 release)
0028 --  1) decrease memory consumption
0029 --    1.1) use quint32 instead of qint64 for end/start tokens
0030 --    1.2) investigate whether using a map/hash for the ducontext member of all
0031 --         ast nodes gives a significant memory decrease while not hampering performance
0032 --    1.3) investigate how unions could be used for exclusive AST node members
0033 --    1.4) see whether we can always use the expression lists instead of both
0034 --         single member pointer and list of members, esp. in expressions
0035 --  2) better cope with invalid code, have at least a partial AST
0036 --  3) investigate whether expanding the visitor lookup to a
0037 --     (albeit huge) switch() in KDev-PG-Qt gives a significant performance gain
0038 --     I have the gut feeling that the current lookup takes unnecessary much time
0039 --
0040 
0041 ------------------------------------------------------------
0042 -- Forward declaration in phpast.h
0043 ------------------------------------------------------------
0044 
0045 [:
0046 
0047 #include <QtCore/QRegularExpression>
0048 
0049 namespace KDevelop
0050 {
0051     class DUContext;
0052 }
0053 
0054 :]
0055 
0056 ------------------------------------------------------------
0057 -- Additional includes for the parser
0058 ------------------------------------------------------------
0059 
0060 %parser_declaration_header "parser/tokenstream.h"
0061 %parser_declaration_header "QtCore/QString"
0062 %parser_declaration_header "language/duchain/problem.h"
0063 %parser_declaration_header "parser/phplexer.h"
0064 
0065 %parser_bits_header "parserdebug.h"
0066 
0067 ------------------------------------------------------------
0068 -- Export macro to use the parser in a shared lib
0069 ------------------------------------------------------------
0070 %export_macro "KDEVPHPPARSER_EXPORT"
0071 %export_macro_header "parserexport.h"
0072 
0073 
0074 ------------------------------------------------------------
0075 -- Enumeration types for additional AST members,
0076 -- in the global "Php" namespace
0077 ------------------------------------------------------------
0078 %namespace
0079 [:
0080     class Lexer;
0081 
0082     enum ModifierFlags {
0083         ModifierPrivate      = 1,
0084         ModifierPublic       = 1 << 1,
0085         ModifierProtected    = 1 << 2,
0086         ModifierStatic       = 1 << 3,
0087         ModifierFinal        = 1 << 4,
0088         ModifierAbstract     = 1 << 5
0089     };
0090 
0091     enum ClassModifier {
0092         NormalClass,
0093         AbstractClass,
0094         FinalClass
0095     };
0096 
0097     enum ScalarTypes {
0098         ScalarTypeInt,
0099         ScalarTypeFloat,
0100         ScalarTypeString
0101     };
0102 
0103     enum CastType {
0104         CastInt,
0105         CastDouble,
0106         CastString,
0107         CastArray,
0108         CastObject,
0109         CastBool,
0110         CastUnset
0111     };
0112 
0113     enum OperationType {
0114         OperationPlus = 1,
0115         OperationMinus,
0116         OperationConcat,
0117         OperationMul,
0118         OperationDiv,
0119         OperationExp,
0120         OperationMod,
0121         OperationAnd,
0122         OperationOr,
0123         OperationXor,
0124         OperationSl,
0125         OperationSr,
0126         OperationSpaceship,
0127     };
0128 
0129     enum UseImportType {
0130       NamespaceOrClassImport,
0131       ConstantImport,
0132       FunctionImport
0133     };
0134 
0135 :]
0136 
0137 ------------------------------------------------------------
0138 -- Ast Node class members
0139 ------------------------------------------------------------
0140 %ast_extra_members
0141 [:
0142   KDevelop::DUContext* ducontext;
0143 :]
0144 
0145 ------------------------------------------------------------
0146 -- Parser class members
0147 ------------------------------------------------------------
0148 
0149 %parserclass (public declaration)
0150 [:
0151   /**
0152    * Transform the raw input into tokens.
0153    * When this method returns, the parser's token stream has been filled
0154    * and any parse*() method can be called.
0155    */
0156   void tokenize(const QString& contents, int initialState = Lexer::HtmlState);
0157 
0158   enum ProblemType {
0159       Error,
0160       Warning,
0161       Info,
0162       Todo
0163   };
0164   KDevelop::ProblemPointer reportProblem( Parser::ProblemType type, const QString& message, int tokenOffset = -1 );
0165   QList<KDevelop::ProblemPointer> problems() {
0166       return m_problems;
0167   }
0168   QString tokenText(qint64 begin, qint64 end);
0169   void setDebug(bool debug);
0170   void setCurrentDocument(KDevelop::IndexedString url);
0171   void setTodoMarkers(const QStringList& markers);
0172   void extractTodosFromComment(const QString& comment, qint64 offset);
0173 
0174     enum InitialLexerState {
0175         HtmlState = 0,
0176         DefaultState = 1
0177     };
0178 
0179     enum ParserUseImportType {
0180         NamespaceOrClassImport,
0181         ConstantImport,
0182         FunctionImport
0183     };
0184   ParserUseImportType m_useImportType;
0185   ParserUseImportType m_useCompoundImportType;
0186 :]
0187 
0188 %parserclass (private declaration)
0189 [:
0190     enum VarExpressionState {
0191         Normal,
0192         OnlyVariable,
0193         OnlyNewObject
0194     };
0195     QString m_contents;
0196     bool m_debug;
0197     KDevelop::IndexedString m_currentDocument;
0198     QList<KDevelop::ProblemPointer> m_problems;
0199 
0200     struct ParserState {
0201         VarExpressionState varExpressionState;
0202         bool varExpressionIsVariable;
0203     };
0204     ParserState m_state;
0205 
0206     QRegularExpression m_todoMarkers;
0207 :]
0208 
0209 %parserclass (constructor)
0210 [:
0211     m_state.varExpressionState = Normal;
0212     m_state.varExpressionIsVariable = false;
0213 :]
0214 
0215 
0216 %token_stream TokenStream ;;
0217 
0218 -----------------------------------------------------------
0219 -- List of defined tokens
0220 -----------------------------------------------------------
0221 
0222 -- keywords:
0223 %token ABSTRACT ("abstract"), BREAK ("break"), CASE ("case"), CATCH ("catch"),
0224        CLASS ("class"), CONST ("const"), CONTINUE ("continue"),
0225        DEFAULT ("default"), DO ("do"), ELSE ("else"), EXTENDS ("extends"),
0226        FINAL ("final"), FOR ("for"), IF ("if"),
0227        IMPLEMENTS ("implements"), INSTANCEOF ("instanceof"), INTERFACE ("interface"),
0228        NEW ("new"), PRIVATE ("private"), PROTECTED ("protected"), PUBLIC ("public"),
0229        RETURN ("return"), STATIC ("static"), SWITCH ("switch"), THROW ("throw"),
0230        TRY ("try"), WHILE ("while"), ECHO ("echo"), PRINT ("print"), FINALLY ("finally"),
0231        CLONE ("clone"), EXIT ("exit"), ELSEIF ("elseif"), ENDIF ("endif"),
0232        ENDWHILE ("endwhile"), ENDFOR ("endfor"), FOREACH ("foreach"), ENDFOREACH ("endforeach"),
0233        DECLARE ("declare"), ENDDECLARE ("enddeclare"), AS ("as"), ENDSWITCH ("endswitch"),
0234        FUNCTION ("function"), USE ("use"), GLOBAL ("global"), VAR ("var "), UNSET ("unset"),
0235        ISSET ("isset"), EMPTY ("empty"), HALT_COMPILER ("halt compiler"),
0236        DOUBLE_ARROW ("=>"), LIST ("list"), ARRAY ("array"), CLASS_C ("__CLASS__"),
0237        METHOD_C ("__METHOD__"), FUNC_C ("__FUNCTION__"), LINE ("__LINE__"),
0238        FILE ("__FILE__"), COMMENT ("comment"), DOC_COMMENT ("doc comment"),  PAAMAYIM_NEKUDOTAYIM ("::"),
0239        INCLUDE ("include"), INCLUDE_ONCE ("include_once"), EVAL ("eval"), REQUIRE ("require"),
0240        REQUIRE_ONCE ("require_once"), NAMESPACE ("namespace"), NAMESPACE_C("__NAMESPACE__"), USE("use"),
0241        GOTO ("goto"), TRAIT ("trait"), INSTEADOF ("insteadof"), CALLABLE ("callable"),
0242        VOID ("void"), DIR ("__DIR__"), TRAIT_C ("__TRAIT__"), YIELD ("yield"), YIELD_FROM("yield from") ;;
0243 
0244 -- casts:
0245 %token INT_CAST ("int cast"), DOUBLE_CAST ("double cast"), STRING_CAST ("string cast"),
0246        ARRAY_CAST ("array cast"), OBJECT_CAST ("object cast"), BOOL_CAST ("bool cast"),
0247        UNSET_CAST ("unset cast") ;;
0248 
0249 -- seperators:
0250 %token SEMICOLON (";"), DOUBLE_QUOTE ("\""), LBRACKET ("["),
0251        RBRACKET ("]"),
0252        LPAREN ("("), RPAREN (")"), LBRACE ("{"), RBRACE ("}"),
0253        COMMA (","), AT ("@"),
0254        CURLY_OPEN ("curly open"), -- { in "{$foo}"; not the same as LBRACE
0255        DOLLAR_OPEN_CURLY_BRACES ("${"),
0256        START_HEREDOC ("start heredoc"), END_HEREDOC ("end heredoc"),
0257        BACKTICK ("`"), BACKSLASH ("\\"),
0258        START_NOWDOC("start nowdoc"), END_NOWDOC("end nowdoc") ;;
0259 
0260 -- operators:
0261 %token IS_EQUAL ("=="), IS_NOT_EQUAL ("!="), IS_IDENTICAL ("==="),
0262        IS_NOT_IDENTICAL ("!=="), IS_SMALLER ("<"), IS_GREATER (">"),
0263        IS_SMALLER_OR_EQUAL ("<="), IS_GREATER_OR_EQUAL (">="),
0264        BOOLEAN_OR ("||"), BOOLEAN_AND ("&&"), ASSIGN ("="), EXP_ASSIGN("**="),
0265        PLUS_ASSIGN ("+="), MINUS_ASSIGN ("-="), MUL_ASSIGN ("*="), DIV_ASSIGN ("/="),
0266        CONCAT_ASSIGN (".="), MOD_ASSIGN ("%="), AND_ASSIGN ("&="), OR_ASSIGN ("|="),
0267        XOR_ASSIGN ("^="), SL_ASSIGN ("<<="), SR_ASSIGN (">>="), OBJECT_OPERATOR ("->"),
0268        PLUS ("+"), MINUS("-"), CONCAT("."),
0269        INC ("++"), DEC ("--"), BANG ("!"), QUESTION ("?"), COLON (":"),
0270        BIT_AND ("&"), BIT_OR("|"), BIT_XOR ("^"),
0271        SL ("<<"), SR (">>"), MUL("*"), DIV("/"), MOD ("%"),
0272        TILDE ("~"), DOLLAR ("$"), EXP ("**"), ELLIPSIS ("..."),
0273        NULL_COALESCE ("??"), SPACESHIP ("<=>"),
0274        LOGICAL_OR ("logical or"), LOGICAL_AND ("logical and"), LOGICAL_XOR ("logical xor") ;;
0275 
0276 -- literals and identifiers:
0277 %token INLINE_HTML ("inline html"), WHITESPACE ("whitespace"),
0278        CONSTANT_ENCAPSED_STRING ("constant encapsed string"),
0279        VARIABLE ("variable"), ENCAPSED_AND_WHITESPACE ("encapsed and whitespace"),
0280        DNUMBER ("double number"), LNUMBER ("long number"),
0281        NUM_STRING ("num string"), STRING ("string"),
0282        STRING_VARNAME ("string varname") ;; -- when in "${varname}"
0283 
0284 -- open/close tags
0285 %token OPEN_TAG ("<?"), CLOSE_TAG ("?>"), OPEN_TAG_WITH_ECHO ("<?=");;
0286 
0287 -- token that makes the parser fail in any case:
0288 %token INVALID ("invalid token") ;;
0289 
0290 
0291 
0292 -- The actual grammar starts here.
0293 
0294 #statements=outerTopStatement*
0295 -> start ;;
0296 
0297   namespaceDeclaration=namespaceDeclarationStatement
0298   | statement=topStatement
0299 -> outerTopStatement ;;
0300 
0301 -- first/first conflict for FUNCTION
0302    (?[: (LA(1).kind == Token_FUNCTION && ((LA(2).kind == Token_BIT_AND && LA(3).kind == Token_LPAREN)
0303             || LA(2).kind == Token_LPAREN))
0304         || LA(1).kind != Token_FUNCTION :]
0305     statement=statement )
0306   | functionDeclaration=functionDeclarationStatement
0307   | classDeclaration=classDeclarationStatement
0308   | traitDeclaration=traitDeclarationStatement
0309   | interfaceDeclaration=interfaceDeclarationStatement
0310   | HALT_COMPILER LPAREN RPAREN SEMICOLON -- Lexer stops allready
0311 -> topStatement ;;
0312 
0313 [: bool reported = false; while ( true ) { :]
0314     try/recover(#statements=topStatement)*
0315 [: if (yytoken != Token_RBRACE && yytoken != Token_EOF && yytoken != Token_CLOSE_TAG
0316        && yytoken != Token_ELSEIF && yytoken != Token_ELSE
0317        && yytoken != Token_ENDIF && yytoken != Token_ENDFOREACH && yytoken != Token_ENDFOR
0318        && yytoken != Token_ENDWHILE && yytoken != Token_ENDSWITCH && yytoken != Token_ENDDECLARE
0319        && yytoken != Token_CASE && yytoken != Token_DEFAULT) {
0320         if (!reported) {
0321             qint64 index = tokenStream->index() - 1;
0322             Token &token = tokenStream->at(index);
0323             QString tokenValue = token.kind != 0 ? tokenText(token.begin, token.end) : QStringLiteral("EOF");
0324             reportProblem(Error, QStringLiteral("Unexpected token \"%1\".").arg(tokenValue));
0325             reported = true;
0326         }
0327         yylex();
0328    } else {
0329         break;
0330    }
0331 } :]
0332 -> innerStatementList ;;
0333 
0334 --Operator Precedence, from PHP Manual
0335 --left    or
0336 --left    xor
0337 --left    and
0338 --right   print
0339 --right   = += -= *= /= .= %= &= |= ^= <<= >>=    assignment
0340 --left    ? : ternary
0341 --right   ??  comparison
0342 --left    ||  logical
0343 --left    &&  logical
0344 --left    |   bitwise
0345 --left    ^   bitwise
0346 --left    &   bitwise and references
0347 --non-associative == != === !== <=>   comparison
0348 --non-associative < <= > >=   comparison
0349 --left    << >>   bitwise
0350 --left    + - .   arithmetic and string
0351 --left    * / %   arithmetic
0352 --non-associative ! ~ - (int) (float) (string) (array) (object) @ types
0353 --non-associative ++ --   increment/decrement
0354 --left    [   array()
0355 --non-associative new new
0356 
0357   expression=logicalOrExpression
0358 -> expr ;;
0359 
0360    #expression=logicalXorExpression @ LOGICAL_OR
0361 -> logicalOrExpression ;;
0362 
0363    #expression=logicalAndExpression @ LOGICAL_XOR
0364 -> logicalXorExpression ;;
0365 
0366    #expression=printExpression @ LOGICAL_AND
0367 -> logicalAndExpression ;;
0368 
0369    (print=PRINT | 0) expression=assignmentExpression
0370 -> printExpression ;;
0371 
0372 -- leftside must me a variable, we check afterwards if it was a variable and
0373 -- if not we report an error
0374 0 --needed for line below
0375 [: m_state.varExpressionIsVariable = false; :] --reset flag
0376 expression=conditionalExpression
0377 (
0378   assignmentExpressionEqual=assignmentExpressionEqual | (
0379      (
0380         PLUS_ASSIGN   [: (*yynode)->operation = OperationPlus; :]
0381       | MINUS_ASSIGN  [: (*yynode)->operation = OperationMinus; :]
0382       | MUL_ASSIGN    [: (*yynode)->operation = OperationMul; :]
0383       | EXP_ASSIGN    [: (*yynode)->operation = OperationExp; :]
0384       | DIV_ASSIGN    [: (*yynode)->operation = OperationDiv; :]
0385       | CONCAT_ASSIGN [: (*yynode)->operation = OperationConcat; :]
0386       | MOD_ASSIGN    [: (*yynode)->operation = OperationMod; :]
0387       | AND_ASSIGN    [: (*yynode)->operation = OperationAnd; :]
0388       | OR_ASSIGN     [: (*yynode)->operation = OperationOr; :]
0389       | XOR_ASSIGN    [: (*yynode)->operation = OperationXor; :]
0390       | SL_ASSIGN     [: (*yynode)->operation = OperationSl; :]
0391       | SR_ASSIGN     [: (*yynode)->operation = OperationSr; :]
0392      )
0393      assignmentExpressionCheckIfVariable
0394      assignmentExpression=assignmentExpression)
0395    | 0)
0396 -> assignmentExpression [
0397      member variable operation: OperationType;
0398 ];;
0399 
0400 --=& is special:
0401   -- $foo =& $var; is allowed but not $foo =& 'static';
0402   -- $foo =& new bar(); is allowed too but deprecated and reports a warning
0403   --we set a flag (varExpressionState) with that var_expression accepts only valid parts
0404   --this is done in such a strage way because we need the full expression to allow
0405   --things like $foo =& $bar || e();
0406 ASSIGN
0407     assignmentExpressionCheckIfVariable --as in assignmentExpression
0408     (BIT_AND [: if (yytoken == Token_NEW) {
0409                 reportProblem(Warning, QStringLiteral("=& new foo() is deprecated"), -2);
0410                 m_state.varExpressionState = OnlyNewObject;
0411               } else {
0412                 m_state.varExpressionState = OnlyVariable;
0413               }:]
0414      | 0) assignmentExpression=assignmentExpression [: m_state.varExpressionState = Normal; :]
0415 -> assignmentExpressionEqual ;;
0416 
0417 
0418 -- check if var_expression was a variable, if not report an error
0419 -- varExpressionIsVariable is set in var_expression
0420 0 --to allow cpp-code
0421 [:
0422     if (!m_state.varExpressionIsVariable) {
0423         reportProblem(Error, QStringLiteral("Left side is not a variable"));
0424         return false;
0425     }
0426 :]
0427 -> assignmentExpressionCheckIfVariable ;;
0428 
0429 expression=nullCoalesceExpression
0430    (  QUESTION (ifExpression=expr|0)
0431       COLON    elseExpression=conditionalExpression
0432     | 0
0433    )
0434 -> conditionalExpression ;;
0435 
0436    #expression=booleanOrExpression @ NULL_COALESCE
0437 -> nullCoalesceExpression ;;
0438 
0439    #expression=booleanAndExpression @ BOOLEAN_OR
0440 -> booleanOrExpression ;;
0441 
0442    #expression=bitOrExpression @ BOOLEAN_AND
0443 -> booleanAndExpression ;;
0444 
0445    #expression=bitXorExpression @ BIT_OR
0446 -> bitOrExpression ;;
0447 
0448    #expression=bitAndExpression @ BIT_XOR
0449 -> bitXorExpression ;;
0450 
0451    #expression=equalityExpression @ BIT_AND
0452 -> bitAndExpression ;;
0453 
0454    expression=relationalExpression
0455    (additionalExpression=equalityExpressionRest | 0)
0456 -> equalityExpression ;;
0457 
0458    (  IS_EQUAL | IS_NOT_EQUAL | IS_IDENTICAL | IS_NOT_IDENTICAL | SPACESHIP [: (*yynode)->operation = OperationSpaceship; :] )
0459    expression=relationalExpression
0460 -> equalityExpressionRest [
0461      member variable operation: OperationType;
0462 ];;
0463 
0464 
0465    expression=shiftExpression
0466    (  additionalExpression=relationalExpressionRest
0467       --instanceof as in java.g (correct??)
0468     | INSTANCEOF instanceofType=classNameReference
0469     | 0
0470    )
0471 -> relationalExpression ;;
0472 
0473    ( IS_SMALLER | IS_GREATER | IS_SMALLER_OR_EQUAL | IS_GREATER_OR_EQUAL )
0474    expression=shiftExpression
0475 -> relationalExpressionRest ;;
0476 
0477 
0478    expression=additiveExpression
0479    (#additionalExpression=shiftExpressionRest)*
0480 -> shiftExpression ;;
0481 
0482    ( SL | SR )
0483    expression=additiveExpression
0484 -> shiftExpressionRest ;;
0485 
0486 
0487    expression=multiplicativeExpression
0488    (#additionalExpression=additiveExpressionRest)*
0489 -> additiveExpression ;;
0490 
0491    (
0492        PLUS   [: (*yynode)->operation = OperationPlus; :]
0493      | MINUS  [: (*yynode)->operation = OperationMinus; :]
0494      | CONCAT [: (*yynode)->operation = OperationConcat; :]
0495    )
0496    expression=multiplicativeExpression
0497 -> additiveExpressionRest [
0498      member variable operation: OperationType;
0499 ];;
0500 
0501 
0502    expression=unaryExpression
0503    (#additionalExpression=multiplicativeExpressionRest)*
0504 -> multiplicativeExpression ;;
0505 
0506    (
0507        MUL [: (*yynode)->operation = OperationMul; :]
0508      | DIV [: (*yynode)->operation = OperationDiv; :]
0509      | EXP [: (*yynode)->operation = OperationExp; :]
0510      | MOD [: (*yynode)->operation = OperationMod; :]
0511    )
0512    expression=unaryExpression
0513 -> multiplicativeExpressionRest [
0514      member variable operation: OperationType;
0515 ];;
0516 
0517  (
0518     MINUS unaryExpression=unaryExpression
0519   | PLUS  unaryExpression=unaryExpression
0520   | BANG unaryExpression=unaryExpression
0521   | TILDE unaryExpression=unaryExpression
0522   | INT_CAST unaryExpression=unaryExpression    [: (*yynode)->castType = CastInt; :]
0523   | DOUBLE_CAST unaryExpression=unaryExpression [: (*yynode)->castType = CastDouble; :]
0524   | STRING_CAST unaryExpression=unaryExpression [: (*yynode)->castType = CastString; :]
0525   | ARRAY_CAST unaryExpression=unaryExpression  [: (*yynode)->castType = CastArray; :]
0526   | OBJECT_CAST unaryExpression=unaryExpression [: (*yynode)->castType = CastObject; :]
0527   | BOOL_CAST unaryExpression=unaryExpression   [: (*yynode)->castType = CastBool; :]
0528   | UNSET_CAST unaryExpression=unaryExpression  [: (*yynode)->castType = CastUnset; :]
0529   | AT unaryExpression=unaryExpression
0530   | LIST LPAREN assignmentList=assignmentList RPAREN ASSIGN unaryExpression=unaryExpression
0531   | EXIT (LPAREN (expression=expr | 0) RPAREN | 0)
0532   | EVAL LPAREN expression=expr RPAREN
0533   | INCLUDE includeExpression=unaryExpression
0534   | INCLUDE_ONCE includeExpression=unaryExpression
0535   | REQUIRE includeExpression=unaryExpression
0536   | REQUIRE_ONCE includeExpression=unaryExpression
0537 
0538   | unaryExpressionNotPlusminus=unaryExpressionNotPlusminus
0539  )
0540 -> unaryExpression [
0541      member variable castType: CastType;
0542 ];;
0543 
0544     (#prefixOperator=postprefixOperator)*
0545     varExpression=varExpression
0546     (#postfixOperator=postprefixOperator)*
0547 -> unaryExpressionNotPlusminus ;;
0548 
0549    op=INC | op=DEC
0550 -> postprefixOperator ;;
0551 
0552 -- 10 first follow conflicts because we go back up the chain (affects both print and yield)
0553     (print=PRINT+) printExpression=assignmentExpression
0554   | isGenerator=YIELD (generatorExpression=printExpression ( DOUBLE_ARROW generatorValueExpr=printExpression | 0 ) | 0)
0555   | isGenerator=YIELD_FROM generatorExpression=printExpression
0556 --first/first conflict - no problem because of ifs
0557   | ?[: m_state.varExpressionState == OnlyVariable :] 0 [: m_state.varExpressionState = Normal; :] variable=variable
0558   | ?[: m_state.varExpressionState == OnlyNewObject :] 0 [: m_state.varExpressionState = Normal; :] newObject=varExpressionNewObject
0559   | varExpressionNormal=varExpressionNormal
0560   | varExpressionArray=varExpressionArray arrayIndex=arrayIndexSpecifier*
0561 -> varExpression ;;
0562 
0563     (?[: LA(1).kind == Token_LPAREN && LA(2).kind == Token_FUNCTION && LA(3).kind == Token_LPAREN :] iife=iifeSyntax )
0564   | LPAREN try/rollback (newObject=varExpressionNewObject RPAREN (#variableProperties=instantiationAccess*))
0565     catch (expression=expr RPAREN)
0566   | BACKTICK encapsList=encapsList BACKTICK
0567   --try/rollback resolves conflict scalar vs. staticMember (foo::bar vs. foo::$bar)
0568   --varExpressionIsVariable flag is needed for assignmentExpression
0569   | try/rollback (variable=variable [: m_state.varExpressionIsVariable = true; :])
0570     catch (scalar=scalar)
0571   | ISSET LPAREN (#issetVariable=variable @ COMMA) RPAREN
0572   | EMPTY LPAREN emptyExpression=expr RPAREN
0573   | newObject=varExpressionNewObject
0574   | CLONE cloneCar=varExpressionNormal
0575   | closure=closure
0576 -> varExpressionNormal ;;
0577 
0578     ARRAY LPAREN
0579         (#arrayValues=arrayPairValue
0580              -- break because array(1,) is allowed (solves FIRST/FOLLOW conflict)
0581           @ (COMMA [: if (yytoken == Token_RPAREN) { break; } :] ) | 0)
0582     RPAREN
0583   | LBRACKET
0584         (#arrayValues=arrayPairValue
0585              -- break because [1,] is allowed (solves FIRST/FOLLOW conflict)
0586           @ (COMMA [: if (yytoken == Token_RBRACKET) { break; } :] ) | 0)
0587     RBRACKET
0588 -> varExpressionArray ;;
0589 
0590 -- https://wiki.php.net/rfc/closures
0591     FUNCTION (isRef=BIT_AND|0) LPAREN parameters=parameterList RPAREN
0592         ( USE LPAREN lexicalVars=lexicalVarList RPAREN | 0)
0593         ( COLON returnType=returnType | 0)
0594         LBRACE try/recover(functionBody=innerStatementList) RBRACE
0595 -> closure ;;
0596 
0597     LPAREN try/rollback (closure=closure RPAREN LPAREN parameterList=functionCallParameterList RPAREN)
0598     catch (expression=expr RPAREN)
0599 -> iifeSyntax ;;
0600 
0601     (#lexicalVars=lexicalVar
0602         -- break because (1,) is allowed
0603         @ (COMMA [: if (yytoken == Token_RPAREN) { break; } :] ) | 0 [: reportProblem(Error, QStringLiteral("Use list of closure must not be empty.")); :])
0604 -> lexicalVarList ;;
0605 
0606   (isRef=BIT_AND | 0) variable=variableIdentifier
0607 -> lexicalVar ;;
0608 
0609     NEW classNameReference=classNameReference ctor=ctorArguments
0610 -> varExpressionNewObject ;;
0611 
0612     LPAREN parameterList=functionCallParameterList RPAREN
0613   | 0
0614 -> ctorArguments ;;
0615 
0616     (#parameters=functionCallParameterListElement
0617             -- break because (1,) is allowed
0618         @ (COMMA [: if (yytoken == Token_RPAREN) { break; } :] ) | 0)
0619 -> functionCallParameterList ;;
0620 
0621     (BIT_AND variable=variable) | (isVariadic=ELLIPSIS | 0) expr=expr
0622 -> functionCallParameterListElement ;;
0623 
0624     #element=assignmentListElement @COMMA
0625 -> assignmentList ;;
0626 
0627     variable=variable
0628   | LIST LPAREN assignmentList=assignmentList RPAREN
0629   | 0
0630 -> assignmentListElement ;;
0631 
0632     expr=expr (DOUBLE_ARROW (exprValue=expr | BIT_AND varValue=variable) | 0)
0633   | BIT_AND variable=variable
0634 -> arrayPairValue ;;
0635 
0636    var=baseVariableWithFunctionCalls (#variableProperties=variableObjectProperty*)
0637 -> variable ;;
0638 
0639     OBJECT_OPERATOR
0640   | PAAMAYIM_NEKUDOTAYIM
0641 -> objectOperator ;;
0642 
0643     ( ?[: LA(1).kind == Token_DOLLAR:] LBRACE variable=variable RBRACE | objectProperty=objectProperty )
0644     (isFunctionCall=LPAREN parameterList=functionCallParameterList RPAREN arrayIndex=arrayIndexSpecifier* | 0)
0645 -> variableProperty ;;
0646 
0647    objectOperator variableProperty=variableProperty
0648 -> variableObjectProperty ;;
0649 
0650    OBJECT_OPERATOR variableProperty=variableProperty
0651 -> instantiationAccess ;;
0652 
0653    --Conflict
0654    --   foo::$bar[0] (=baseVariable-staticMember)
0655    --vs.foo::$bar[0](); (=static function call)
0656    try/rollback (functionCall=functionCall arrayIndex=arrayIndexSpecifier*)
0657    catch (baseVariable=baseVariable)
0658 -> baseVariableWithFunctionCalls ;;
0659 
0660    LBRACKET (expr=expr | 0) RBRACKET
0661 -> arrayIndexSpecifier ;;
0662 
0663    LBRACKET (expr=expr) RBRACKET
0664 -> stringIndexSpecifier ;;
0665 
0666     stringFunctionNameOrClass=namespacedIdentifier (
0667         LPAREN stringParameterList=functionCallParameterList RPAREN
0668       | PAAMAYIM_NEKUDOTAYIM
0669         (
0670             stringFunctionName=semiReservedIdentifier LPAREN stringParameterList=functionCallParameterList RPAREN
0671             | varFunctionName=variableWithoutObjects LPAREN stringParameterList=functionCallParameterList RPAREN
0672             | LBRACE (expr=expr) RBRACE LPAREN stringParameterList=functionCallParameterList RPAREN
0673         )
0674     )
0675   | varFunctionName=variableWithoutObjects LPAREN varParameterList=functionCallParameterList RPAREN
0676 -> functionCall ;;
0677 
0678     var=compoundVariableWithSimpleIndirectReference #offsetItems=dimListItem*
0679   | staticMember=staticMember
0680 -> baseVariable ;;
0681 
0682     variable=variableIdentifier
0683   | DOLLAR LBRACE expr=expr RBRACE
0684 -> compoundVariable ;;
0685 
0686   ( DOLLAR ( DOLLAR+ | 0 ) ( indirectVariable=variableIdentifier | LBRACE expr=expr RBRACE ) | variable=variableIdentifier )
0687 -> compoundVariableWithSimpleIndirectReference ;;
0688 
0689     className=namespacedIdentifier staticProperty=staticProperty
0690 -> staticMember ;;
0691 
0692     LBRACE try/recover(statements=innerStatementList) RBRACE
0693   | IF LPAREN ifExpr=expr RPAREN
0694       (   COLON statements=innerStatementList newElseifList newElseSingle ENDIF semicolonOrCloseTag
0695         | ifStatement=statement elseifList=elseifList elseSingle=elseSingle
0696       )
0697   | WHILE LPAREN whileExpr=expr RPAREN whileStatement=whileStatement
0698   | FOR LPAREN forExpr1=forExpr SEMICOLON forExpr2=forExpr
0699     SEMICOLON forExpr3=forExpr RPAREN forStatement=forStatement
0700   | SWITCH LPAREN swtichExpr=expr RPAREN switchCaseList=switchCaseList
0701 
0702   | FOREACH LPAREN (
0703             -- allow $var as &$i and not expr() as &$i
0704         try/rollback(foreachVar=variable AS foreachVarAsVar=foreachVariable)
0705         catch(foreachExpr=expr AS foreachExprAsVar=variable))
0706         (DOUBLE_ARROW foreachVariable=foreachVariable | 0) RPAREN
0707         foreachStatement=foreachStatement
0708   | DECLARE LPAREN declareItem=declareItem @ COMMA RPAREN declareStatement
0709   | SEMICOLON     -- empty statement
0710   | TRY  LBRACE try/recover(statements=innerStatementList) RBRACE
0711     #catches=catchItem*
0712     (FINALLY LBRACE finallyBody=innerStatementList RBRACE | 0)
0713   | UNSET LPAREN #unsetVariables=variable @ COMMA RPAREN semicolonOrCloseTag
0714   -- fix first/follow with goto target
0715   | ( ?[: LA(1).kind != Token_STRING || LA(2).kind != Token_COLON :] expr=expr semicolonOrCloseTag )
0716   | DO doStatement=statement WHILE LPAREN whileExpr=expr RPAREN semicolonOrCloseTag
0717   | BREAK (breakExpr=expr | 0) semicolonOrCloseTag
0718   | CONTINUE (continueExpr=expr | 0) semicolonOrCloseTag
0719   | RETURN (returnExpr=expr | 0) semicolonOrCloseTag
0720   | GLOBAL #globalVars=globalVar @ COMMA semicolonOrCloseTag
0721   | STATIC #staticVars=staticVar @ COMMA semicolonOrCloseTag
0722   | ECHO #echoExprs=expr @ COMMA semicolonOrCloseTag
0723   | THROW throwExpr=expr semicolonOrCloseTag
0724   -- throws error in zend parser, so ignored | USE use_filename  semicolonOrCloseTag
0725 
0726   | CLOSE_TAG
0727   | OPEN_TAG
0728   | OPEN_TAG_WITH_ECHO expr=expr semicolonOrCloseTag
0729   | INLINE_HTML
0730   | CONST #consts=constantDeclaration @ COMMA SEMICOLON
0731   | USE useStatement=useStatement
0732   | GOTO gotoLabel=STRING SEMICOLON
0733   | gotoTarget=STRING COLON
0734 -> statement ;;
0735 
0736     ( useFunction=FUNCTION [: m_useImportType = FunctionImport; :]
0737     | useConst=CONST [: m_useImportType = ConstantImport; :]
0738     | 0 [: m_useImportType = NamespaceOrClassImport; :]
0739     ) #useNamespace=useNamespaceOrUseGroupedNamespace @ COMMA SEMICOLON
0740 -> useStatement ;;
0741 
0742    [: (*yynode)->useImportType = (UseImportType)(int)m_useImportType; :]
0743    identifier=namespacedIdentifierBeforeGroupedNamespace
0744    (AS aliasIdentifier=identifier | compoundNamespace=compoundNamespace | 0)
0745 -> useNamespaceOrUseGroupedNamespace [
0746      member variable useImportType: UseImportType;
0747 ] ;;
0748 
0749     LBRACE
0750         #compoundNamespaceStatement=compoundNamespaceStatement
0751         -- break because "use Foo\{bar1,}" is allowed (solves FIRST/FOLLOW conflict)
0752         @ (COMMA [: if (yytoken == Token_RBRACE) { break; } :] )
0753     RBRACE
0754 -> compoundNamespace ;;
0755 
0756     ( useFunction=FUNCTION [: m_useCompoundImportType = FunctionImport; :]
0757     | useConst=CONST [: m_useCompoundImportType = ConstantImport; :]
0758     | 0 [: m_useCompoundImportType = NamespaceOrClassImport; :]
0759     )
0760     [:
0761         if (m_useImportType != NamespaceOrClassImport && m_useCompoundImportType != NamespaceOrClassImport)
0762         {
0763             reportProblem(Error, QStringLiteral("Can't use mixed import."), -2);
0764         }
0765     :]
0766     #useNamespace=innerUseNamespace
0767 -> compoundNamespaceStatement ;;
0768 
0769    [:
0770         if (m_useCompoundImportType != NamespaceOrClassImport) {
0771             (*yynode)->useImportType = (UseImportType)(int)m_useCompoundImportType;
0772         } else {
0773             (*yynode)->useImportType = (UseImportType)(int)m_useImportType;
0774         }
0775    :]
0776     #namespaceName=identifier+ @ BACKSLASH
0777     (AS aliasIdentifier=identifier | 0)
0778 -> innerUseNamespace [
0779      member variable useImportType: UseImportType;
0780 ] ;;
0781 
0782     identifier=identifier ASSIGN scalar=expr
0783 -> constantDeclaration ;;
0784 
0785     identifier=semiReservedIdentifier ASSIGN scalar=expr
0786 -> classConstantDeclaration ;;
0787 
0788    SEMICOLON | CLOSE_TAG
0789 -> semicolonOrCloseTag ;;
0790 
0791     LBRACE (SEMICOLON | 0) try/recover(caseList=caseList) RBRACE
0792   | COLON (SEMICOLON | 0) caseList=caseList ENDSWITCH semicolonOrCloseTag
0793 -> switchCaseList ;;
0794 
0795     #caseItems=case_item*
0796 -> caseList ;;
0797 
0798     CASE expr=expr (COLON | SEMICOLON) statements=innerStatementList
0799   | def=DEFAULT (COLON | SEMICOLON) statements=innerStatementList
0800 -> case_item ;;
0801 
0802     CATCH LPAREN #catchClass=namespacedIdentifier @ BIT_OR var=variableIdentifier RPAREN
0803     LBRACE try/recover(statements=innerStatementList) RBRACE
0804 -> catchItem ;;
0805 
0806     statement=statement
0807   | COLON statements=innerStatementList ENDDECLARE semicolonOrCloseTag
0808 -> declareStatement ;;
0809 
0810     STRING ASSIGN scalar=staticScalar
0811 -> declareItem ;;
0812 
0813     (BIT_AND | 0) variable=variable
0814 -> foreachVariable ;;
0815 
0816     statement=statement
0817   | COLON statements=innerStatementList ENDFOREACH semicolonOrCloseTag
0818 -> foreachStatement ;;
0819 
0820   var=variableIdentifier (ASSIGN value=staticScalar | 0)
0821 -> staticVar ;;
0822 
0823     var=variableIdentifier
0824   | DOLLAR (dollarVar=variable | LBRACE expr=expr RBRACE)
0825 -> globalVar ;;
0826 
0827     #exprs=expr @ COMMA | 0
0828 -> forExpr ;;
0829 
0830     statement=statement
0831   | COLON statements=innerStatementList ENDFOR semicolonOrCloseTag
0832 -> forStatement ;;
0833 
0834     statement=statement
0835   | COLON statements=innerStatementList ENDWHILE semicolonOrCloseTag
0836 -> whileStatement ;;
0837 
0838     --first/follow conflict; todo check if this is a problem
0839     #elseifListItem=elseifListItem*
0840 -> elseifList ;;
0841 
0842     ELSEIF LPAREN expr=expr RPAREN statement=statement
0843 -> elseifListItem ;;
0844 
0845     ELSE statement=statement | 0
0846 -> elseSingle ;;
0847 
0848     #newElseifListItem=newelseifListItem*
0849 -> newElseifList ;;
0850 
0851     ELSEIF LPAREN expr=expr RPAREN COLON statements=innerStatementList
0852 -> newelseifListItem ;;
0853 
0854     ELSE COLON statements=innerStatementList | 0
0855 -> newElseSingle ;;
0856 
0857     className=className (staticProperty=staticProperty #properties=classProperty* | 0)
0858   | baseVariable=variableWithoutObjects #properties=classProperty*
0859 -> classNameReference ;;
0860 
0861     identifier=namespacedIdentifier
0862   | staticIdentifier = STATIC
0863 -> className ;;
0864 
0865     PAAMAYIM_NEKUDOTAYIM staticProperty=compoundVariableWithSimpleIndirectReference #offsetItems=dimListItem*
0866 -> staticProperty ;;
0867 
0868    (staticProperty=staticProperty | OBJECT_OPERATOR property=objectProperty)
0869 -> classProperty ;;
0870 
0871     objectDimList=objectDimList
0872   | variableWithoutObjects=variableWithoutObjects
0873 -> objectProperty ;;
0874 
0875     variableName=variableName #offsetItems=dimListItem*
0876 -> objectDimList ;;
0877 
0878   variable=compoundVariableWithSimpleIndirectReference #offsetItems=dimListItem*
0879 -> variableWithoutObjects ;;
0880 
0881 arrayIndex=arrayIndexSpecifier | LBRACE expr=expr RBRACE
0882 -> dimListItem ;;
0883 
0884     name=identifier
0885   | LBRACE expr=expr RBRACE
0886 -> variableName ;;
0887 
0888     commonScalar=commonScalar
0889   | constantOrClassConst=constantOrClassConst #offsetItem=dimListItem*
0890   | varname=STRING_VARNAME
0891   | DOUBLE_QUOTE encapsList=encapsList DOUBLE_QUOTE stringIndex=stringIndexSpecifier*
0892   | START_HEREDOC encapsList=encapsList END_HEREDOC
0893 -> scalar ;;
0894 
0895   constant=namespacedIdentifier
0896   ( PAAMAYIM_NEKUDOTAYIM classConstant=classConstant | 0 )
0897 -> constantOrClassConst ;;
0898 
0899   semiReservedIdentifier
0900 -> classConstant ;;
0901 
0902     #encaps=encaps*
0903 -> encapsList ;;
0904 
0905     var=encapsVar | value=ENCAPSED_AND_WHITESPACE
0906 -> encaps ;;
0907 
0908      -- first/first conflict resolved by LA(2)
0909      --(expr allows STRING_VARNAME too - but without [expr])
0910     DOLLAR_OPEN_CURLY_BRACES ( ?[: LA(2).kind == Token_LBRACKET:] STRING_VARNAME arrayIndex=arrayIndexSpecifier RBRACE
0911       | expr=expr RBRACE )
0912   | variable=variableIdentifier (OBJECT_OPERATOR propertyIdentifier=identifier | LBRACKET offset=encapsVarOffset RBRACKET | 0)
0913   | CURLY_OPEN expr=expr RBRACE
0914 -> encapsVar ;;
0915 
0916     STRING
0917   | NUM_STRING
0918   | variableIdentifier
0919 -> encapsVarOffset ;;
0920 
0921 
0922     LNUMBER                  [: (*yynode)->scalarType = ScalarTypeInt; :]
0923   | DNUMBER                  [: (*yynode)->scalarType = ScalarTypeFloat; :]
0924   | string=CONSTANT_ENCAPSED_STRING [: (*yynode)->scalarType = ScalarTypeString; :] stringIndex=stringIndexSpecifier*
0925   | LINE                     [: (*yynode)->scalarType = ScalarTypeInt; :]
0926   | DIR                      [: (*yynode)->scalarType = ScalarTypeString; :]
0927   | FILE                     [: (*yynode)->scalarType = ScalarTypeString; :]
0928   | CLASS_C                  [: (*yynode)->scalarType = ScalarTypeString; :]
0929   | TRAIT_C                  [: (*yynode)->scalarType = ScalarTypeString; :]
0930   | METHOD_C                 [: (*yynode)->scalarType = ScalarTypeString; :]
0931   | FUNC_C                   [: (*yynode)->scalarType = ScalarTypeString; :]
0932   | NAMESPACE_C              [: (*yynode)->scalarType = ScalarTypeString; :]
0933   | START_NOWDOC STRING END_NOWDOC [: (*yynode)->scalarType = ScalarTypeString; :]
0934 -> commonScalar [
0935      member variable scalarType: ScalarTypes;
0936 ] ;;
0937 
0938     FUNCTION (BIT_AND | 0) functionName=identifier
0939     LPAREN parameters=parameterList RPAREN (COLON returnType=returnType | 0)
0940     LBRACE try/recover(functionBody=innerStatementList) RBRACE
0941 -> functionDeclarationStatement ;;
0942 
0943     (#parameters=parameter
0944              -- break because (1,) is allowed
0945           @ (COMMA [: if (yytoken == Token_RPAREN) { break; } :] ) | 0)
0946 -> parameterList ;;
0947 
0948 (parameterType=parameterType | 0) (isRef=BIT_AND | 0)
0949     (isVariadic=ELLIPSIS | 0) variable=variableIdentifier (ASSIGN defaultValue=expr | 0)
0950 -> parameter ;;
0951 
0952     genericType=namespacedIdentifier
0953   | arrayType=ARRAY
0954 -> genericTypeHint ;;
0955 
0956     (isNullable=QUESTION | 0) (
0957         genericType=genericTypeHint
0958       | callableType=CALLABLE
0959     )
0960   [: (*yynode)->voidType = -1; :]
0961 -> parameterTypeHint[
0962      member variable voidType: int;
0963 ] ;;
0964 
0965     (isNullable=QUESTION | 0) (
0966         genericType=genericTypeHint
0967       | callableType=CALLABLE
0968       | voidType=VOID
0969     )
0970 -> returnTypeHint ;;
0971 
0972     (isNullable=QUESTION | 0)
0973     genericType=genericTypeHint
0974   [: (*yynode)->callableType = -1; :]
0975   [: (*yynode)->voidType = -1; :]
0976 -> propertyTypeHint[
0977      member variable callableType: int;
0978      member variable voidType: int;
0979 ] ;;
0980 
0981     #unionType=parameterTypeHint @ BIT_OR
0982 -> unionParameterType ;;
0983 
0984     typehint=unionParameterType
0985 -> parameterType ;;
0986 
0987     #unionType=returnTypeHint @ BIT_OR
0988 -> unionReturnType ;;
0989 
0990     typehint=unionReturnType
0991 -> returnType ;;
0992 
0993     #unionType=propertyTypeHint @ BIT_OR
0994 -> unionPropertyType ;;
0995 
0996     typehint=unionPropertyType
0997 -> propertyType ;;
0998 
0999     value=commonScalar
1000   | constantOrClassConst=constantOrClassConst
1001   | PLUS plusValue=staticScalar
1002   | MINUS minusValue=staticScalar
1003   | array=ARRAY LPAREN
1004         (#arrayValues=staticArrayPairValue
1005              -- break because array(1,) is allowed
1006           @ (COMMA [: if (yytoken == Token_RPAREN) { break; } :] ) | 0)
1007     RPAREN
1008   | array=LBRACKET
1009         (#arrayValues=staticArrayPairValue
1010              -- break because [1,] is allowed
1011           @ (COMMA [: if (yytoken == Token_RBRACKET) { break; } :] ) | 0)
1012     RBRACKET
1013 -> staticScalar ;;
1014 
1015     #val1=staticScalar (DOUBLE_ARROW #val2=staticScalar | 0)
1016 -> staticArrayPairValue ;;
1017 
1018    (isGlobal=BACKSLASH | 0)
1019    #namespaceName=identifier+ @ BACKSLASH
1020 -> namespacedIdentifier ;;
1021 
1022    (isGlobal=BACKSLASH | 0)
1023    #namespaceName=identifier+ @ ( BACKSLASH [: if (yytoken == Token_LBRACE) { break; } :] ) 
1024 -> namespacedIdentifierBeforeGroupedNamespace ;;
1025 
1026      string=STRING
1027 -> identifier ;;
1028 
1029       INCLUDE | INCLUDE_ONCE | EVAL | REQUIRE | REQUIRE_ONCE | LOGICAL_OR | LOGICAL_XOR | LOGICAL_AND
1030     | INSTANCEOF | NEW | CLONE | EXIT | IF | ELSEIF | ELSE | ENDIF | ECHO | DO | WHILE | ENDWHILE
1031     | FOR | ENDFOR | FOREACH | ENDFOREACH | DECLARE | ENDDECLARE | AS | TRY | CATCH | FINALLY
1032     | THROW | USE | INSTEADOF | GLOBAL | VAR | UNSET | ISSET | EMPTY | CONTINUE | GOTO
1033     | FUNCTION | CONST | RETURN | PRINT | YIELD | LIST | SWITCH | ENDSWITCH | CASE | DEFAULT | BREAK
1034     | ARRAY | CALLABLE | EXTENDS | IMPLEMENTS | NAMESPACE | TRAIT | INTERFACE | CLASS
1035     | CLASS_C | TRAIT_C | FUNC_C | METHOD_C | LINE | FILE | DIR | NAMESPACE_C
1036 -> reservedNonModifiers ;;
1037 
1038       reservedNonModifiers
1039     | STATIC | ABSTRACT | FINAL | PRIVATE | PROTECTED | PUBLIC
1040 -> semiReserved ;;
1041 
1042       identifier
1043 [:
1044     qint64 index = tokenStream->index() - 2;
1045     (*yynode)->string = index;
1046 :]
1047     | semiReserved
1048 [:
1049     qint64 index = tokenStream->index() - 2;
1050     (*yynode)->string = index;
1051 :]
1052 -> semiReservedIdentifier [
1053      member variable string: qint64;
1054 ] ;;
1055 
1056       identifier
1057 [:
1058     qint64 index = tokenStream->index() - 2;
1059     (*yynode)->string = index;
1060 :]
1061     | reservedNonModifiers
1062 [:
1063     qint64 index = tokenStream->index() - 2;
1064     (*yynode)->string = index;
1065 :]
1066 -> reservedNonModifierIdentifier [
1067      member variable string: qint64;
1068 ] ;;
1069 
1070      variable=VARIABLE
1071 -> variableIdentifier ;;
1072 
1073     NAMESPACE #namespaceName=identifier* @ BACKSLASH
1074     (
1075         -- the semicolon case needs at least one namespace identifier, the {...} case not...
1076         SEMICOLON [: if (!(*yynode)->namespaceNameSequence) { reportProblem(Error, QStringLiteral("Missing namespace identifier."), -2); } :]
1077     | LBRACE try/recover(body=innerStatementList) RBRACE )
1078 -> namespaceDeclarationStatement ;;
1079 
1080     INTERFACE interfaceName=identifier (EXTENDS extends=classImplements | 0)
1081     LBRACE try/recover(body=classBody) RBRACE
1082 -> interfaceDeclarationStatement ;;
1083 
1084     TRAIT traitName=identifier
1085     LBRACE body=classBody RBRACE
1086 -> traitDeclarationStatement ;;
1087 
1088     modifier=optionalClassModifier CLASS className=identifier
1089         (EXTENDS extends=classExtends | 0)
1090         (IMPLEMENTS implements=classImplements | 0)
1091     LBRACE body=classBody RBRACE
1092 -> classDeclarationStatement ;;
1093 
1094 identifier=namespacedIdentifier
1095 -> classExtends ;;
1096 
1097 #implements=namespacedIdentifier @ COMMA
1098 -> classImplements ;;
1099 
1100 -- error recovery, to understand it you probably have to look at the generated code ;-)
1101 [: bool reported = false; while ( true ) { :]
1102 try/recover(#classStatements=classStatement)*
1103 [: if (yytoken != Token_RBRACE && yytoken != Token_EOF && yytoken != Token_CLOSE_TAG) {
1104         if (!reported) {
1105             reportProblem(Error, QStringLiteral("Unexpected token in class context."));
1106             reported = true;
1107         }
1108         yylex();
1109    } else {
1110         break;
1111    }
1112 } :]
1113  RBRACE [: rewind(tokenStream->index() - 2); :]
1114 -> classBody ;;
1115 
1116     VAR variable=classVariableDeclaration SEMICOLON
1117   | modifiers=optionalModifiers
1118     ( (propertyType=propertyType | 0) variable=classVariableDeclaration SEMICOLON
1119       | FUNCTION (BIT_AND | 0) methodName=semiReservedIdentifier LPAREN parameters=parameterList RPAREN
1120         ( COLON returnType=returnType | 0)
1121         methodBody=methodBody
1122       | CONST #consts=classConstantDeclaration @ COMMA SEMICOLON
1123     )
1124   | USE #traits=namespacedIdentifier @ COMMA (imports=traitAliasDeclaration|SEMICOLON)
1125 -> classStatement ;;
1126 
1127     LBRACE #statements=traitAliasStatement
1128         @ (SEMICOLON [: if (yytoken == Token_RBRACE) { break; } :]) RBRACE
1129 -> traitAliasDeclaration ;;
1130 
1131     importIdentifier=traitAliasIdentifier
1132 -- first/first conflict resolved by LA(2)
1133 -- We can either have a single token (modifier or identifier), or a combination
1134     ( AS (?[: LA(2).kind == Token_SEMICOLON :]
1135         (modifiers=traitVisibilityModifiers | aliasNonModifierIdentifier=reservedNonModifierIdentifier)
1136         | modifiers=traitVisibilityModifiers aliasIdentifier=semiReservedIdentifier
1137       )
1138       | INSTEADOF #conflictIdentifier=namespacedIdentifier @ COMMA
1139     )
1140 -> traitAliasStatement ;;
1141 
1142     identifier=namespacedIdentifier PAAMAYIM_NEKUDOTAYIM methodIdentifier=semiReservedIdentifier
1143 -> traitAliasIdentifier ;;
1144 
1145     SEMICOLON -- abstract method
1146  |  LBRACE try/recover(statements=innerStatementList) RBRACE
1147 -> methodBody ;;
1148 
1149 #vars=classVariable @ COMMA
1150 -> classVariableDeclaration ;;
1151 
1152     variable=variableIdentifier (ASSIGN value=staticScalar | 0)
1153 -> classVariable ;;
1154 
1155     PUBLIC     [: (*yynode)->modifiers |= ModifierPublic;     :]
1156   | PROTECTED  [: (*yynode)->modifiers |= ModifierProtected;  :]
1157   | PRIVATE    [: (*yynode)->modifiers |= ModifierPrivate;    :]
1158   | STATIC     [: (*yynode)->modifiers |= ModifierStatic;     :]
1159   | ABSTRACT   [: (*yynode)->modifiers |= ModifierAbstract;   :]
1160   | FINAL      [: (*yynode)->modifiers |= ModifierFinal;      :]
1161 -> traitVisibilityModifiers[
1162      member variable modifiers: unsigned int;
1163 ] ;;
1164 
1165   (
1166     PUBLIC     [: (*yynode)->modifiers |= ModifierPublic;      :]
1167   | PROTECTED  [: (*yynode)->modifiers |= ModifierProtected;      :]
1168   | PRIVATE    [: (*yynode)->modifiers |= ModifierPrivate;      :]
1169   | STATIC     [: (*yynode)->modifiers |= ModifierStatic;      :]
1170   | ABSTRACT   [: (*yynode)->modifiers |= ModifierAbstract;      :]
1171   | FINAL      [: (*yynode)->modifiers |= ModifierFinal;      :]
1172   | 0
1173   )*
1174 -> optionalModifiers[
1175      member variable modifiers: unsigned int;
1176 ] ;;
1177 
1178   (
1179     ABSTRACT   [: (*yynode)->modifier = AbstractClass; :]
1180   | FINAL      [: (*yynode)->modifier = FinalClass;    :]
1181   | 0
1182   )
1183 -> optionalClassModifier[
1184      member variable modifier: ClassModifier;
1185 ] ;;
1186 
1187 
1188 
1189 
1190 
1191 -----------------------------------------------------------------
1192 -- Code segments copied to the implementation (.cpp) file.
1193 -- If existent, kdevelop-pg's current syntax requires this block
1194 -- to occur at the end of the file.
1195 -----------------------------------------------------------------
1196 
1197 [:
1198 
1199 #include <QtCore/QDebug>
1200 #include <language/editor/documentrange.h>
1201 
1202 namespace Php
1203 {
1204 
1205 void Parser::tokenize(const QString& contents, int initialState)
1206 {
1207     m_contents = contents;
1208     Lexer lexer(tokenStream, contents, initialState);
1209     int kind = Parser::Token_EOF;
1210     int lastDocCommentBegin;
1211     int lastDocCommentEnd;
1212 
1213     do
1214     {
1215         lastDocCommentBegin = 0;
1216         lastDocCommentEnd = 0;
1217         kind = lexer.nextTokenKind();
1218         while (kind == Parser::Token_WHITESPACE || kind == Parser::Token_COMMENT || kind == Parser::Token_DOC_COMMENT) {
1219             if (kind == Parser::Token_COMMENT || kind == Parser::Token_DOC_COMMENT) {
1220                 extractTodosFromComment(tokenText(lexer.tokenBegin(), lexer.tokenEnd()), lexer.tokenBegin());
1221             }
1222             if (kind == Parser::Token_DOC_COMMENT) {
1223                 lastDocCommentBegin = lexer.tokenBegin();
1224                 lastDocCommentEnd = lexer.tokenEnd();
1225             }
1226             kind = lexer.nextTokenKind();
1227         }
1228         if ( !kind ) // when the lexer returns 0, the end of file is reached
1229         {
1230             kind = Parser::Token_EOF;
1231         }
1232         Parser::Token &t = tokenStream->push();
1233         t.begin = lexer.tokenBegin();
1234         t.end = lexer.tokenEnd();
1235         t.kind = kind;
1236         t.docCommentBegin = lastDocCommentBegin;
1237         t.docCommentEnd = lastDocCommentEnd;
1238         //if ( m_debug ) qDebug() << kind << tokenText(t.begin,t.end) << t.begin << t.end;
1239     }
1240     while ( kind != Parser::Token_EOF );
1241 
1242     yylex(); // produce the look ahead token
1243 }
1244 
1245 void Parser::extractTodosFromComment(const QString& comment, qint64 startPosition)
1246 {
1247     auto i = m_todoMarkers.globalMatch(comment);
1248     while (i.hasNext()) {
1249         auto match = i.next();
1250         auto p = reportProblem(Todo, match.captured(1), 0);
1251         if (!p) {
1252             continue;
1253         }
1254 
1255         qint64 line = 0;
1256         qint64 column = 0;
1257         tokenStream->locationTable()->positionAt(startPosition, &line, &column);
1258 
1259         auto location = p->finalLocation();
1260         location.setStart(KTextEditor::Cursor(line, column + match.capturedStart(1)));
1261         location.setEnd(KTextEditor::Cursor(line, column + match.capturedEnd(1)));
1262         p->setFinalLocation(location);
1263     };
1264 }
1265 
1266 void Parser::setTodoMarkers(const QStringList& markers)
1267 {
1268     QString pattern = QStringLiteral("^(?:[/\\*\\s]*)(.*(?:");
1269     bool first = true;
1270     foreach(const QString& marker, markers) {
1271         if (!first) {
1272             pattern += '|';
1273         }
1274         pattern += QRegularExpression::escape(marker);
1275         first = false;
1276     }
1277     pattern += QStringLiteral(").*?)(?:[/\\*\\s]*)$");
1278     m_todoMarkers.setPatternOptions(QRegularExpression::MultilineOption);
1279     m_todoMarkers.setPattern(pattern);
1280 }
1281 
1282 QString Parser::tokenText(qint64 begin, qint64 end)
1283 {
1284     return m_contents.mid(begin,end-begin+1);
1285 }
1286 
1287 
1288 KDevelop::ProblemPointer Parser::reportProblem( Parser::ProblemType type, const QString& message, int offset )
1289 {
1290     qint64 sLine;
1291     qint64 sCol;
1292     qint64 index = tokenStream->index() + offset;
1293     if (index >= tokenStream->size()) {
1294         return {};
1295     }
1296     tokenStream->startPosition(index, &sLine, &sCol);
1297     qint64 eLine;
1298     qint64 eCol;
1299     tokenStream->endPosition(index, &eLine, &eCol);
1300     auto p = KDevelop::ProblemPointer(new KDevelop::Problem());
1301     p->setSource(KDevelop::IProblem::Parser);
1302     switch ( type ) {
1303         case Error:
1304             p->setSeverity(KDevelop::IProblem::Error);
1305             break;
1306         case Warning:
1307             p->setSeverity(KDevelop::IProblem::Warning);
1308             break;
1309         case Info:
1310             p->setSeverity(KDevelop::IProblem::Hint);
1311             break;
1312         case Todo:
1313             p->setSeverity(KDevelop::IProblem::Hint);
1314             p->setSource(KDevelop::IProblem::ToDo);
1315             break;
1316     }
1317     p->setDescription(message);
1318     KTextEditor::Range range(sLine, sCol, eLine, eCol + 1);
1319     p->setFinalLocation(KDevelop::DocumentRange(m_currentDocument, range));
1320     m_problems << p;
1321     return p;
1322 }
1323 
1324 
1325 // custom error recovery
1326 void Parser::expectedToken(int /*expected*/, qint64 /*where*/, const QString& name)
1327 {
1328     reportProblem( Parser::Error, QStringLiteral("Expected token \"%1\"").arg(name));
1329 }
1330 
1331 void Parser::expectedSymbol(int /*expectedSymbol*/, const QString& name)
1332 {
1333     qint64 line;
1334     qint64 col;
1335     qint64 index = tokenStream->index()-1;
1336     Token &token = tokenStream->at(index);
1337     qCDebug(PARSER) << "token starts at:" << token.begin;
1338     qCDebug(PARSER) << "index is:" << index;
1339     tokenStream->startPosition(index, &line, &col);
1340     QString tokenValue = tokenText(token.begin, token.end);
1341     qint64 eLine;
1342     qint64 eCol;
1343     tokenStream->endPosition(index, &eLine, &eCol);
1344     reportProblem( Parser::Error,
1345                    QStringLiteral("Expected symbol \"%1\" (current token: \"%2\" [%3] at %4:%5 - %6:%7)")
1346                   .arg(name,
1347                        token.kind != 0 ? tokenValue : QStringLiteral("EOF"))
1348                   .arg(token.kind)
1349                   .arg(line)
1350                   .arg(col)
1351                   .arg(eLine)
1352                   .arg(eCol));
1353 }
1354 
1355 void Parser::setDebug( bool debug )
1356 {
1357     m_debug = debug;
1358 }
1359 
1360 void Parser::setCurrentDocument(KDevelop::IndexedString url)
1361 {
1362     m_currentDocument = url;
1363 }
1364 
1365 
1366 Parser::ParserState *Parser::copyCurrentState()
1367 {
1368     ParserState *state = new ParserState();
1369     state->varExpressionState = m_state.varExpressionState;
1370     state->varExpressionIsVariable = m_state.varExpressionIsVariable;
1371     return state;
1372 }
1373 
1374 void Parser::restoreState( Parser::ParserState* state)
1375 {
1376     m_state.varExpressionState = state->varExpressionState;
1377     m_state.varExpressionIsVariable = state->varExpressionIsVariable;
1378 }
1379 
1380 } // end of namespace Php
1381 
1382 :]
1383 
1384 -- kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on; auto-insert-doxygen on; mode KDevelop-PG[-Qt]