1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-12-18 03:20:59 +01:00
phorge-arcanist/support/xhpast/parser.y
epriestley a1ee2ab931 Fix improper XHPAST parsing of namespace grammar like "use x as private;"
Summary:
Depends on D21067. Ref T13492. Converting unit tests to be readable exposed this error in the grammar.

Normally, "grammar_rule" rules emit a standalone Node. In this case, the bottom-level grammar rule is a collection of trivial rules and the callers configure the Node. Wrap the bottom-level rule in a configuration rule so the node is configured correctly and consistently, in exactly one place.

Test Plan: Ran unit tests.

Maniphest Tasks: T13492

Differential Revision: https://secure.phabricator.com/D21068
2020-04-07 14:35:42 -07:00

2790 lines
60 KiB
Text

%{
/*
* If you modify this grammar, please update the version number in
* ./xhpast.cpp and libphutil/src/parser/xhpast/bin/xhpast_parse.php
*/
#include "ast.hpp"
#include "node_names.hpp"
// PHP's if/else rules use right reduction rather than left reduction which
// means while parsing nested if/else's the stack grows until it the last
// statement is read. This is annoying, particularly because of a quirk in
// bison.
// http://www.gnu.org/software/bison/manual/html_node/Memory-Management.html
// Apparently if you compile a bison parser with g++ it can no longer grow
// the stack. The work around is to just make your initial stack ridiculously
// large. Unfortunately that increases memory usage while parsing which is
// dumb. Anyway, putting a TODO here to fix PHP's if/else grammar.
#define YYINITDEPTH 500
%}
%{
#undef yyextra
#define yyextra static_cast<yy_extra_type*>(xhpastget_extra(yyscanner))
#undef yylineno
#define yylineno yyextra->first_lineno
#define push_state(s) xhp_new_push_state(s, (struct yyguts_t*) yyscanner)
#define pop_state() xhp_new_pop_state((struct yyguts_t*) yyscanner)
#define set_state(s) xhp_set_state(s, (struct yyguts_t*) yyscanner)
#define NNEW(t) \
(new xhpast::Node(t))
#define NTYPE(n, type) \
((n)->setType(type))
#define NMORE(n, end) \
((n)->expandRange(end))
#define NSPAN(n, type, end) \
(NMORE(NTYPE((n), type), end))
#define NEXPAND(l, n, r) \
((n)->expandRange(l)->expandRange(r))
using namespace std;
static void yyerror(void* yyscanner, void* _, const char* error) {
if (yyextra->terminated) {
return;
}
yyextra->terminated = true;
yyextra->error = error;
}
%}
%expect 5
// 2: PHP's if/else grammar
// 7: expr '[' dim_offset ']' -- shift will default to first grammar
%pure-parser
%parse-param { void* yyscanner }
%parse-param { xhpast::Node** root }
%lex-param { void* yyscanner }
%error-verbose
%left T_INCLUDE T_INCLUDE_ONCE T_EVAL T_REQUIRE T_REQUIRE_ONCE
%left ','
%left T_LOGICAL_OR
%left T_LOGICAL_XOR
%left T_LOGICAL_AND
%right T_PRINT
%left '=' T_PLUS_EQUAL
T_MINUS_EQUAL
T_MUL_EQUAL
T_DIV_EQUAL
T_CONCAT_EQUAL
T_MOD_EQUAL
T_AND_EQUAL
T_OR_EQUAL
T_XOR_EQUAL
T_SL_EQUAL
T_SR_EQUAL
%left '?' ':'
%right T_COALESCE
%left T_BOOLEAN_OR
%left T_BOOLEAN_AND
%left '|'
%left '^'
%left '&'
%nonassoc T_IS_EQUAL T_IS_NOT_EQUAL T_IS_IDENTICAL T_IS_NOT_IDENTICAL
T_SPACESHIP
%nonassoc '<' T_IS_SMALLER_OR_EQUAL '>' T_IS_GREATER_OR_EQUAL
%left T_SL T_SR
%left '+' '-' '.'
%left '*' '/' '%'
%right '!'
%nonassoc T_INSTANCEOF
%right '~' T_INC
T_DEC
T_INT_CAST
T_DOUBLE_CAST
T_STRING_CAST
T_UNICODE_CAST
T_BINARY_CAST
T_ARRAY_CAST
T_OBJECT_CAST
T_BOOL_CAST
T_UNSET_CAST
'@'
%right '['
%nonassoc T_NEW T_CLONE
%token T_EXIT
%token T_IF
%left T_ELSEIF
%left T_ELSE
%left T_ENDIF
%token T_LNUMBER
%token T_DNUMBER
%token T_STRING
%token T_STRING_VARNAME /* unused in XHP: `foo` in `"$foo"` */
%token T_VARIABLE
%token T_NUM_STRING /* unused in XHP: `0` in `"$foo[0]"` */
%token T_INLINE_HTML
%token T_CHARACTER /* unused in vanilla PHP */
%token T_BAD_CHARACTER /* unused in vanilla PHP */
%token T_ENCAPSED_AND_WHITESPACE /* unused in XHP: ` ` in `" "` */
%token T_CONSTANT_ENCAPSED_STRING /* overloaded in XHP;
replaces '"' encaps_list '"' */
%token T_BACKTICKS_EXPR /* new in XHP; replaces '`' backticks_expr '`' */
%token T_ECHO
%token T_DO
%token T_WHILE
%token T_ENDWHILE
%token T_FOR
%token T_ENDFOR
%token T_FOREACH
%token T_ENDFOREACH
%token T_DECLARE
%token T_ENDDECLARE
%token T_AS
%token T_SWITCH
%token T_ENDSWITCH
%token T_CASE
%token T_DEFAULT
%token T_BREAK
%token T_CONTINUE
%token T_GOTO
%token T_FUNCTION
%token T_CONST
%token T_RETURN
%token T_TRY
%token T_CATCH
%token T_THROW
%token T_USE
%token T_GLOBAL
%right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC
%token T_VAR
%token T_UNSET
%token T_ISSET
%token T_EMPTY
%token T_HALT_COMPILER
%token T_CLASS
%token T_INTERFACE
%token T_EXTENDS
%token T_IMPLEMENTS
%token T_OBJECT_OPERATOR
%token T_DOUBLE_ARROW
%token T_LIST
%token T_ARRAY
%token T_CLASS_C
%token T_METHOD_C
%token T_FUNC_C
%token T_LINE
%token T_FILE
%token T_COMMENT
%token T_DOC_COMMENT
%token T_OPEN_TAG
%token T_OPEN_TAG_WITH_ECHO
%token T_OPEN_TAG_FAKE
%token T_CLOSE_TAG
%token T_WHITESPACE
%token T_START_HEREDOC /* unused in XHP; replaced with T_HEREDOC */
%token T_END_HEREDOC /* unused in XHP; replaced with T_HEREDOC */
%token T_HEREDOC /* new in XHP;
replaces start_heredoc encaps_list T_END_HEREDOC */
%token T_DOLLAR_OPEN_CURLY_BRACES /* unused in XHP: `${` in `"${foo}"` */
%token T_CURLY_OPEN /* unused in XHP: `{$` in `"{$foo}"` */
%token T_PAAMAYIM_NEKUDOTAYIM
%token T_BINARY_DOUBLE /* unsused in XHP: `b"` in `b"foo"` */
%token T_BINARY_HEREDOC /* unsused in XHP: `b<<<` in `b<<<FOO` */
%token T_NAMESPACE
%token T_NS_C
%token T_DIR
%token T_NS_SEPARATOR
%token T_INSTEADOF
%token T_CALLABLE
%token T_TRAIT
%token T_TRAIT_C
%token T_YIELD
%token T_FINALLY
%token T_ELLIPSIS
%%
start:
top_statement_list {
*root = NNEW(n_PROGRAM)->appendChild($1);
}
;
top_statement_list:
top_statement_list top_statement {
$$ = $1->appendChild($2);
}
| /* empty */ {
$$ = NNEW(n_STATEMENT_LIST);
}
;
namespace_name:
T_STRING {
$$ = NTYPE($1, n_SYMBOL_NAME);
}
| namespace_name T_NS_SEPARATOR T_STRING {
$$ = NMORE($1, $3);
}
;
top_statement:
statement
| function_declaration_statement
| class_declaration_statement
| T_HALT_COMPILER '(' ')' ';' {
$1 = NSPAN($1, n_HALT_COMPILER, $3);
$$ = NNEW(n_STATEMENT)->appendChild($1);
NMORE($$, $4);
}
| T_NAMESPACE namespace_name ';' {
NSPAN($1, n_NAMESPACE, $2);
$1->appendChild($2);
$1->appendChild(NNEW(n_EMPTY));
$$ = NNEW(n_STATEMENT)->appendChild($1);
NMORE($$, $3);
}
| T_NAMESPACE namespace_name '{' top_statement_list '}' {
NSPAN($1, n_NAMESPACE, $5);
$1->appendChild($2);
$1->appendChild(NEXPAND($3, $4, $5));
$$ = NNEW(n_STATEMENT)->appendChild($1);
}
| T_NAMESPACE '{' top_statement_list '}' {
NSPAN($1, n_NAMESPACE, $4);
$1->appendChild(NNEW(n_EMPTY));
NMORE($3, $4);
NMORE($3, $2);
$1->appendChild($3);
$$ = NNEW(n_STATEMENT)->appendChild($1);
}
| T_USE use_declarations ';' {
NMORE($2, $1);
$$ = NNEW(n_STATEMENT)->appendChild($2);
NMORE($$, $3);
}
| constant_declaration ';' {
$$ = NNEW(n_STATEMENT)->appendChild($1);
NMORE($$, $2);
}
;
use_declarations:
use_declarations ',' use_declaration {
$$ = $1->appendChild($3);
}
| use_declaration {
$$ = NNEW(n_USE_LIST);
$$->appendChild($1);
}
;
use_declaration:
namespace_name {
$$ = NNEW(n_USE);
$$->appendChild($1);
$$->appendChild(NNEW(n_EMPTY));
}
| namespace_name T_AS T_STRING {
$$ = NNEW(n_USE);
$$->appendChild($1);
NTYPE($3, n_STRING);
$$->appendChild($3);
}
| T_NS_SEPARATOR namespace_name {
$$ = NNEW(n_USE);
NMORE($2, $1);
$$->appendChild($2);
$$->appendChild(NNEW(n_EMPTY));
}
| T_NS_SEPARATOR namespace_name T_AS T_STRING {
$$ = NNEW(n_USE);
NMORE($2, $1);
$$->appendChild($2);
NTYPE($4, n_STRING);
$$->appendChild($4);
}
;
constant_declaration:
constant_declaration ',' T_STRING '=' static_scalar {
NMORE($$, $5);
$$->appendChild(
NNEW(n_CONSTANT_DECLARATION)
->appendChild(NTYPE($3, n_STRING))
->appendChild($5));
}
| T_CONST T_STRING '=' static_scalar {
NSPAN($$, n_CONSTANT_DECLARATION_LIST, $4);
$$->appendChild(
NNEW(n_CONSTANT_DECLARATION)
->appendChild(NTYPE($2, n_STRING))
->appendChild($4));
}
;
inner_statement_list:
inner_statement_list inner_statement {
$$ = $1->appendChild($2);
}
| /* empty */ {
$$ = NNEW(n_STATEMENT_LIST);
}
;
inner_statement:
statement
| function_declaration_statement
| class_declaration_statement
| T_HALT_COMPILER '(' ')' ';' {
$1 = NSPAN($1, n_HALT_COMPILER, $3);
$$ = NNEW(n_STATEMENT)->appendChild($1);
NMORE($$, $4);
}
;
statement:
unticked_statement
| T_STRING ':' {
NTYPE($1, n_STRING);
$$ = NNEW(n_LABEL);
$$->appendChild($1);
NMORE($$, $2);
}
| T_OPEN_TAG {
$$ = NTYPE($1, n_OPEN_TAG);
}
| T_OPEN_TAG_WITH_ECHO {
$$ = NTYPE($1, n_OPEN_TAG);
}
| T_CLOSE_TAG {
$$ = NTYPE($1, n_CLOSE_TAG);
}
;
unticked_statement:
'{' inner_statement_list '}' {
$$ = NEXPAND($1, $2, $3);
}
| T_IF '(' expr ')' statement elseif_list else_single {
$$ = NNEW(n_CONDITION_LIST);
$1 = NTYPE($1, n_IF);
$1->appendChild(NSPAN($2, n_CONTROL_CONDITION, $4)->appendChild($3));
$1->appendChild($5);
$$->appendChild($1);
$$->appendChildren($6);
// Hacks: merge a list of if (x) { } else if (y) { } into a single condition
// list instead of a condition tree.
if ($7->type == n_EMPTY) {
// Ignore.
} else if ($7->type == n_ELSE) {
xhpast::Node *stype = $7->firstChild()->firstChild();
if (stype && stype->type == n_CONDITION_LIST) {
NTYPE(stype->firstChild(), n_ELSEIF);
stype->firstChild()->l_tok = $7->l_tok;
$$->appendChildren(stype);
} else {
$$->appendChild($7);
}
} else {
$$->appendChild($7);
}
$$ = NNEW(n_STATEMENT)->appendChild($$);
}
| T_IF '(' expr ')' ':'
inner_statement_list
new_elseif_list
new_else_single
T_ENDIF ';' {
$$ = NNEW(n_CONDITION_LIST);
NTYPE($1, n_IF);
$1->appendChild(NSPAN($2, n_CONTROL_CONDITION, $4)->appendChild($3));
$1->appendChild($6);
$$->appendChild($1);
$$->appendChildren($7);
$$->appendChild($8);
NMORE($$, $9);
$$ = NNEW(n_STATEMENT)->appendChild($$);
NMORE($$, $10);
}
| T_WHILE '(' expr ')' while_statement {
NTYPE($1, n_WHILE);
$1->appendChild(NSPAN($2, n_CONTROL_CONDITION, $4)->appendChild($3));
$1->appendChild($5);
$$ = NNEW(n_STATEMENT)->appendChild($1);
}
| T_DO statement T_WHILE '(' expr ')' ';' {
NTYPE($1, n_DO_WHILE);
$1->appendChild($2);
$1->appendChild(NSPAN($4, n_CONTROL_CONDITION, $6)->appendChild($5));
$$ = NNEW(n_STATEMENT)->appendChild($1);
NMORE($$, $7);
}
| T_FOR '(' for_expr ';' for_expr ';' for_expr ')' for_statement {
NTYPE($1, n_FOR);
NSPAN($2, n_FOR_EXPRESSION, $8)
->appendChild($3)
->appendChild($5)
->appendChild($7);
$1->appendChild($2);
$1->appendChild($9);
$$ = NNEW(n_STATEMENT)->appendChild($1);
}
| T_SWITCH '(' expr ')' switch_case_list {
NTYPE($1, n_SWITCH);
$1->appendChild(NSPAN($2, n_CONTROL_CONDITION, $4)->appendChild($3));
$1->appendChild($5);
$$ = NNEW(n_STATEMENT)->appendChild($1);
}
| T_BREAK ';' {
NTYPE($1, n_BREAK);
$1->appendChild(NNEW(n_EMPTY));
$$ = NNEW(n_STATEMENT)->appendChild($1);
NMORE($$, $2);
}
| T_BREAK expr ';' {
NTYPE($1, n_BREAK);
$1->appendChild($2);
$$ = NNEW(n_STATEMENT)->appendChild($1);
NMORE($$, $3);
}
| T_CONTINUE ';' {
NTYPE($1, n_CONTINUE);
$1->appendChild(NNEW(n_EMPTY));
$$ = NNEW(n_STATEMENT)->appendChild($1);
NMORE($$, $2);
}
| T_CONTINUE expr ';' {
NTYPE($1, n_CONTINUE);
$1->appendChild($2);
$$ = NNEW(n_STATEMENT)->appendChild($1);
NMORE($$, $3);
}
| T_RETURN ';' {
NTYPE($1, n_RETURN);
$1->appendChild(NNEW(n_EMPTY));
$$ = NNEW(n_STATEMENT)->appendChild($1);
NMORE($$, $2);
}
| T_RETURN expr_without_variable ';' {
NTYPE($1, n_RETURN);
$1->appendChild($2);
$$ = NNEW(n_STATEMENT)->appendChild($1);
NMORE($$, $3);
}
| T_RETURN variable ';' {
NTYPE($1, n_RETURN);
$1->appendChild($2);
$$ = NNEW(n_STATEMENT)->appendChild($1);
NMORE($$, $3);
}
| T_GLOBAL global_var_list ';' {
NMORE($2, $1);
$$ = NNEW(n_STATEMENT)->appendChild($2);
NMORE($$, $3);
}
| T_STATIC static_var_list ';' {
NMORE($2, $1);
$$ = NNEW(n_STATEMENT)->appendChild($2);
NMORE($$, $3);
}
| T_ECHO echo_expr_list ';' {
NMORE($2, $1);
$$ = NNEW(n_STATEMENT)->appendChild($2);
NMORE($$, $3);
}
| T_INLINE_HTML {
NTYPE($1, n_INLINE_HTML);
$$ = $1;
}
| expr ';' {
$$ = NNEW(n_STATEMENT)->appendChild($1);
NMORE($$, $2);
}
| yield_expr ';' {
$$ = NNEW(n_STATEMENT)->appendChild($1);
NMORE($$, $2);
}
| T_UNSET '(' unset_variables ')' ';' {
NMORE($3, $4);
NMORE($3, $1);
$$ = NNEW(n_STATEMENT)->appendChild($3);
NMORE($$, $5);
}
| T_FOREACH '(' variable T_AS foreach_variable foreach_optional_arg ')'
foreach_statement {
NTYPE($1, n_FOREACH);
NSPAN($2, n_FOREACH_EXPRESSION, $7);
$2->appendChild($3);
if ($6->type == n_EMPTY) {
$2->appendChild($6);
$2->appendChild($5);
} else {
$2->appendChild($5);
$2->appendChild($6);
}
$1->appendChild($2);
$1->appendChild($8);
$$ = NNEW(n_STATEMENT)->appendChild($1);
}
| T_FOREACH '(' expr_without_variable T_AS variable foreach_optional_arg ')'
foreach_statement {
NTYPE($1, n_FOREACH);
NSPAN($2, n_FOREACH_EXPRESSION, $7);
$2->appendChild($3);
if ($6->type == n_EMPTY) {
$2->appendChild($6);
$2->appendChild($5);
} else {
$2->appendChild($5);
$2->appendChild($6);
}
$1->appendChild($2);
$1->appendChild($8);
$$ = NNEW(n_STATEMENT)->appendChild($1);
}
| T_DECLARE '(' declare_list ')' declare_statement {
NTYPE($1, n_DECLARE);
$1->appendChild($3);
$1->appendChild($5);
$$ = NNEW(n_STATEMENT)->appendChild($1);
}
| ';' /* empty statement */ {
$$ = NNEW(n_STATEMENT)->appendChild(NNEW(n_EMPTY));
NMORE($$, $1);
}
| T_TRY '{' inner_statement_list '}' catch_list finally_statement {
NTYPE($1, n_TRY);
$1->appendChild(NEXPAND($2, $3, $4));
$1->appendChild($5);
$1->appendChild($6);
$$ = NNEW(n_STATEMENT)->appendChild($1);
}
| T_TRY '{' inner_statement_list '}' non_empty_finally_statement {
NTYPE($1, n_TRY);
$1->appendChild(NEXPAND($2, $3, $4));
$1->appendChild(NNEW(n_CATCH_LIST));
$1->appendChild($5);
$$ = NNEW(n_STATEMENT)->appendChild($1);
}
| T_THROW expr ';' {
NTYPE($1, n_THROW);
$1->appendChild($2);
$$ = NNEW(n_STATEMENT)->appendChild($1);
NMORE($$, $3);
}
| T_GOTO T_STRING ';' {
NTYPE($1, n_GOTO);
NTYPE($2, n_STRING);
$1->appendChild($2);
$$ = NNEW(n_STATEMENT)->appendChild($1);
NMORE($$, $3);
}
;
catch_list:
catch_list catch {
$1->appendChild($2);
$$ = $1;
}
| catch {
$$ = NNEW(n_CATCH_LIST);
$$->appendChild($1);
}
catch:
T_CATCH '(' fully_qualified_class_name T_VARIABLE ')'
'{' inner_statement_list '}' {
NTYPE($1, n_CATCH);
$1->appendChild($3);
$1->appendChild(NTYPE($4, n_VARIABLE));
$1->appendChild(NEXPAND($6, $7, $8));
NMORE($1, $8);
$$ = $1;
}
;
finally_statement:
/* empty */ {
$$ = NNEW(n_EMPTY);
}
| non_empty_finally_statement
;
non_empty_finally_statement:
T_FINALLY '{' inner_statement_list '}' {
NTYPE($1, n_FINALLY);
$1->appendChild($3);
NMORE($1, $4);
$$ = $1;
}
;
unset_variables:
unset_variable {
$$ = NNEW(n_UNSET_LIST);
$$->appendChild($1);
}
| unset_variables ',' unset_variable {
$1->appendChild($3);
$$ = $1;
}
;
unset_variable:
variable
;
function_declaration_statement:
unticked_function_declaration_statement
;
class_declaration_statement:
unticked_class_declaration_statement
;
is_reference:
/* empty */ {
$$ = NNEW(n_EMPTY);
}
| '&' {
$$ = NTYPE($1, n_REFERENCE);
}
;
unticked_function_declaration_statement:
function is_reference T_STRING
'(' parameter_list ')' return_type '{' inner_statement_list '}' {
NSPAN($1, n_FUNCTION_DECLARATION, $9);
$1->appendChild(NNEW(n_EMPTY));
$1->appendChild($2);
$1->appendChild(NTYPE($3, n_STRING));
$1->appendChild(NEXPAND($4, $5, $6));
$1->appendChild(NNEW(n_EMPTY));
$1->appendChild($7);
$1->appendChild(NEXPAND($8, $9, $10));
$$ = NNEW(n_STATEMENT)->appendChild($1);
}
;
unticked_class_declaration_statement:
class_entry_type T_STRING extends_from implements_list
'{' class_statement_list '}' {
$$ = NNEW(n_CLASS_DECLARATION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_CLASS_NAME));
$$->appendChild($3);
$$->appendChild($4);
$$->appendChild(NEXPAND($5, $6, $7));
NMORE($$, $7);
$$ = NNEW(n_STATEMENT)->appendChild($$);
}
| interface_entry T_STRING interface_extends_list '{' class_statement_list '}' {
$$ = NNEW(n_INTERFACE_DECLARATION);
$$->appendChild(NNEW(n_CLASS_ATTRIBUTES));
NMORE($$, $1);
$$->appendChild(NTYPE($2, n_CLASS_NAME));
$$->appendChild($3);
$$->appendChild(NNEW(n_EMPTY));
$$->appendChild(NEXPAND($4, $5, $6));
NMORE($$, $6);
$$ = NNEW(n_STATEMENT)->appendChild($$);
}
;
class_entry_type:
T_CLASS {
NTYPE($1, n_CLASS_ATTRIBUTES);
$$ = $1;
}
| T_ABSTRACT T_CLASS {
NTYPE($2, n_CLASS_ATTRIBUTES);
NMORE($2, $1);
$2->appendChild(NTYPE($1, n_STRING));
$$ = $2;
}
| T_FINAL T_CLASS {
NTYPE($2, n_CLASS_ATTRIBUTES);
NMORE($2, $1);
$2->appendChild(NTYPE($1, n_STRING));
$$ = $2;
}
| T_TRAIT {
$$ = NNEW(n_CLASS_ATTRIBUTES);
$$->appendChild(NTYPE($1, n_STRING));
}
;
extends_from:
/* empty */ {
$$ = NNEW(n_EMPTY);
}
| T_EXTENDS fully_qualified_class_name {
$$ = NTYPE($1, n_EXTENDS_LIST)->appendChild($2);
}
;
interface_entry:
T_INTERFACE
;
interface_extends_list:
/* empty */ {
$$ = NNEW(n_EMPTY);
}
| T_EXTENDS interface_list {
NTYPE($1, n_EXTENDS_LIST);
$1->appendChildren($2);
$$ = $1;
}
;
implements_list:
/* empty */ {
$$ = NNEW(n_EMPTY);
}
| T_IMPLEMENTS interface_list {
NTYPE($1, n_IMPLEMENTS_LIST);
$1->appendChildren($2);
$$ = $1;
}
;
interface_list:
fully_qualified_class_name {
$$ = NNEW(n_IMPLEMENTS_LIST)->appendChild($1);
}
| interface_list ',' fully_qualified_class_name {
$$ = $1->appendChild($3);
}
;
foreach_optional_arg:
/* empty */ {
$$ = NNEW(n_EMPTY);
}
| T_DOUBLE_ARROW foreach_variable {
$$ = $2;
}
;
foreach_variable:
variable
| '&' variable {
NTYPE($1, n_VARIABLE_REFERENCE);
$1->appendChild($2);
$$ = $1;
}
;
for_statement:
statement
| ':' inner_statement_list T_ENDFOR ';' {
NMORE($2, $1);
NMORE($2, $4);
$$ = $2;
}
;
foreach_statement:
statement
| ':' inner_statement_list T_ENDFOREACH ';' {
NMORE($2, $1);
NMORE($2, $4);
$$ = $2;
}
;
declare_statement:
statement
| ':' inner_statement_list T_ENDDECLARE ';' {
NMORE($2, $1);
NMORE($2, $4);
$$ = $2;
}
;
declare_list:
T_STRING '=' static_scalar {
$$ = NNEW(n_DECLARE_DECLARATION);
$$->appendChild(NTYPE($1, n_STRING));
$$->appendChild($3);
$$ = NNEW(n_DECLARE_DECLARATION_LIST)->appendChild($$);
}
| declare_list ',' T_STRING '=' static_scalar {
$$ = NNEW(n_DECLARE_DECLARATION);
$$->appendChild(NTYPE($3, n_STRING));
$$->appendChild($5);
$1->appendChild($$);
$$ = $1;
}
;
switch_case_list:
'{' case_list '}' {
$$ = NEXPAND($1, $2, $3);
}
| '{' ';' case_list '}' {
// ...why does this rule exist?
NTYPE($2, n_STATEMENT);
$1->appendChild(NNEW(n_EMPTY));
$$ = NNEW(n_STATEMENT_LIST)->appendChild($2);
$$->appendChildren($3);
NEXPAND($1, $$, $4);
}
| ':' case_list T_ENDSWITCH ';' {
NMORE($2, $4);
NMORE($2, $1);
$$ = $2;
}
| ':' ';' case_list T_ENDSWITCH ';' {
NTYPE($2, n_STATEMENT);
$1->appendChild(NNEW(n_EMPTY));
$$ = NNEW(n_STATEMENT_LIST)->appendChild($2);
$$->appendChildren($3);
NMORE($$, $5);
NMORE($$, $1);
}
;
case_list:
/* empty */ {
$$ = NNEW(n_STATEMENT_LIST);
}
| case_list T_CASE expr case_separator inner_statement_list {
NTYPE($2, n_CASE);
$2->appendChild($3);
$2->appendChild($5);
$1->appendChild($2);
$$ = $1;
}
| case_list T_DEFAULT case_separator inner_statement_list {
NTYPE($2, n_DEFAULT);
$2->appendChild($4);
$1->appendChild($2);
$$ = $1;
}
;
case_separator:
':'
| ';'
;
while_statement:
statement
| ':' inner_statement_list T_ENDWHILE ';' {
NMORE($2, $4);
NMORE($2, $1);
$$ = $2;
}
;
elseif_list:
/* empty */ {
$$ = NNEW(n_CONDITION_LIST);
}
| elseif_list T_ELSEIF '(' expr ')' statement {
NTYPE($2, n_ELSEIF);
$2->appendChild(NSPAN($3, n_CONTROL_CONDITION, $5)->appendChild($4));
$2->appendChild($6);
$$ = $1->appendChild($2);
}
;
new_elseif_list:
/* empty */ {
$$ = NNEW(n_CONDITION_LIST);
}
| new_elseif_list T_ELSEIF '(' expr ')' ':' inner_statement_list {
NTYPE($2, n_ELSEIF);
$2->appendChild($4);
$2->appendChild($7);
$$ = $1->appendChild($2);
}
;
else_single:
/* empty */ {
$$ = NNEW(n_EMPTY);
}
| T_ELSE statement {
NTYPE($1, n_ELSE);
$1->appendChild($2);
$$ = $1;
}
;
new_else_single:
/* empty */ {
$$ = NNEW(n_EMPTY);
}
| T_ELSE ':' inner_statement_list {
NTYPE($1, n_ELSE);
$1->appendChild($3);
$$ = $1;
}
;
parameter_list:
non_empty_parameter_list
| /* empty */ {
$$ = NNEW(n_DECLARATION_PARAMETER_LIST);
}
;
non_empty_parameter_list:
optional_type parameter {
$$ = NNEW(n_DECLARATION_PARAMETER);
$$->appendChild($1);
$$->appendChild($2);
$$->appendChild(NNEW(n_EMPTY));
$$ = NNEW(n_DECLARATION_PARAMETER_LIST)->appendChild($$);
}
| optional_type '&' parameter {
$$ = NNEW(n_DECLARATION_PARAMETER);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_VARIABLE_REFERENCE));
$2->appendChild($3);
$$->appendChild(NNEW(n_EMPTY));
$$ = NNEW(n_DECLARATION_PARAMETER_LIST)->appendChild($$);
}
| optional_type '&' parameter '=' static_scalar {
$$ = NNEW(n_DECLARATION_PARAMETER);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_VARIABLE_REFERENCE));
$2->appendChild($3);
$$->appendChild($5);
$$ = NNEW(n_DECLARATION_PARAMETER_LIST)->appendChild($$);
}
| optional_type parameter '=' static_scalar {
$$ = NNEW(n_DECLARATION_PARAMETER);
$$->appendChild($1);
$$->appendChild($2);
$$->appendChild($4);
$$ = NNEW(n_DECLARATION_PARAMETER_LIST)->appendChild($$);
}
| non_empty_parameter_list ',' optional_type parameter {
$$ = NNEW(n_DECLARATION_PARAMETER);
$$->appendChild($3);
$$->appendChild($4);
$$->appendChild(NNEW(n_EMPTY));
$$ = $1->appendChild($$);
}
| non_empty_parameter_list ',' optional_type '&' parameter {
$$ = NNEW(n_DECLARATION_PARAMETER);
$$->appendChild($3);
$$->appendChild(NTYPE($4, n_VARIABLE_REFERENCE));
$4->appendChild($5);
$$->appendChild(NNEW(n_EMPTY));
$$ = $1->appendChild($$);
}
| non_empty_parameter_list ',' optional_type '&'
parameter '=' static_scalar {
$$ = NNEW(n_DECLARATION_PARAMETER);
$$->appendChild($3);
$$->appendChild(NTYPE($4, n_VARIABLE_REFERENCE));
$4->appendChild($5);
$$->appendChild($7);
$$ = $1->appendChild($$);
}
| non_empty_parameter_list ',' optional_type
parameter '=' static_scalar {
$$ = NNEW(n_DECLARATION_PARAMETER);
$$->appendChild($3);
$$->appendChild($4);
$$->appendChild($6);
$$ = $1->appendChild($$);
}
;
parameter:
T_ELLIPSIS T_VARIABLE {
NTYPE($1, n_UNPACK);
$$ = $1->appendChild(NTYPE($2, n_VARIABLE));
}
| T_VARIABLE {
$$ = NTYPE($1, n_VARIABLE);
}
;
optional_type:
/* empty */ {
$$ = NNEW(n_EMPTY);
}
| type
| '?' type {
$$ = NNEW(n_NULLABLE_TYPE);
$$->appendChild($2);
}
;
type:
fully_qualified_class_name {
$$ = $1;
}
| T_ARRAY {
$$ = NTYPE($1, n_TYPE_NAME);
}
| T_CALLABLE {
$$ = NTYPE($1, n_TYPE_NAME);
}
;
return_type:
/* empty */ {
$$ = NNEW(n_EMPTY);
}
| ':' optional_type {
$$ = NNEW(n_DECLARATION_RETURN);
$$->appendChild($2);
}
;
function_call_parameter_list:
non_empty_function_call_parameter_list
| /* empty */ {
$$ = NNEW(n_CALL_PARAMETER_LIST);
}
;
non_empty_function_call_parameter_list:
argument {
$$ = NNEW(n_CALL_PARAMETER_LIST)->appendChild($1);
}
| non_empty_function_call_parameter_list ',' argument {
$$ = $1->appendChild($3);
}
;
argument:
expr
| T_ELLIPSIS expr {
NTYPE($1, n_UNPACK);
$$ = $1->appendChild($2);
}
| '&' w_variable {
NTYPE($1, n_VARIABLE_REFERENCE);
$$ = $1->appendChild($2);
}
;
global_var_list:
global_var_list ',' global_var {
$1->appendChild($3);
$$ = $1;
}
| global_var {
$$ = NNEW(n_GLOBAL_DECLARATION_LIST);
$$->appendChild($1);
}
;
global_var:
T_VARIABLE {
$$ = NTYPE($1, n_VARIABLE);
}
| '$' r_variable {
$$ = NTYPE($1, n_VARIABLE_VARIABLE);
$$->appendChild($2);
}
| '$' '{' expr '}' {
$$ = NTYPE($1, n_VARIABLE_VARIABLE);
$$->appendChild($3);
}
;
static_var_list:
static_var_list ',' T_VARIABLE {
NTYPE($3, n_VARIABLE);
$$ = NNEW(n_STATIC_DECLARATION);
$$->appendChild($3);
$$->appendChild(NNEW(n_EMPTY));
$$ = $1->appendChild($$);
}
| static_var_list ',' T_VARIABLE '=' static_scalar {
NTYPE($3, n_VARIABLE);
$$ = NNEW(n_STATIC_DECLARATION);
$$->appendChild($3);
$$->appendChild($5);
$$ = $1->appendChild($$);
}
| T_VARIABLE {
NTYPE($1, n_VARIABLE);
$$ = NNEW(n_STATIC_DECLARATION);
$$->appendChild($1);
$$->appendChild(NNEW(n_EMPTY));
$$ = NNEW(n_STATIC_DECLARATION_LIST)->appendChild($$);
}
| T_VARIABLE '=' static_scalar {
NTYPE($1, n_VARIABLE);
$$ = NNEW(n_STATIC_DECLARATION);
$$->appendChild($1);
$$->appendChild($3);
$$ = NNEW(n_STATIC_DECLARATION_LIST)->appendChild($$);
}
;
class_statement_list:
class_statement_list class_statement {
$$ = $1->appendChild($2);
}
| /* empty */ {
$$ = NNEW(n_STATEMENT_LIST);
}
;
class_statement:
variable_modifiers class_variable_declaration ';' {
$$ = NNEW(n_CLASS_MEMBER_DECLARATION_LIST);
$$->appendChild($1);
$$->appendChildren($2);
$$ = NNEW(n_STATEMENT)->appendChild($$);
NMORE($$, $3);
}
| class_constant_declaration ';' {
$$ = NNEW(n_STATEMENT)->appendChild($1);
NMORE($$, $2);
}
| trait_use_statement {
$$ = $1;
}
| method_modifiers function {
/* empty */
} is_reference T_STRING '(' parameter_list ')' return_type method_body {
$$ = NNEW(n_METHOD_DECLARATION);
NMORE($$, $2);
$$->appendChild($1);
$$->appendChild($4);
$$->appendChild(NTYPE($5, n_STRING));
$$->appendChild(NEXPAND($6, $7, $8));
$$->appendChild(NNEW(n_EMPTY));
$$->appendChild($9);
$$->appendChild($10);
$$ = NNEW(n_STATEMENT)->appendChild($$);
}
;
trait_use_statement:
T_USE trait_list trait_adaptations {
$$ = NTYPE($1, n_TRAIT_USE);
$$->appendChildren($2);
$$->appendChild($3);
}
;
trait_list:
fully_qualified_class_name {
$$ = NNEW(n_TRAIT_USE_LIST)->appendChild($1);
}
| trait_list ',' fully_qualified_class_name {
$$ = $1->appendChild($3);
}
;
trait_adaptations:
';' {
$$ = NNEW(n_EMPTY);
}
| '{' trait_adaptation_list '}' {
$$ = NEXPAND($1, $2, $3);
}
;
trait_adaptation_list:
/* empty */ {
$$ = NNEW(n_TRAIT_ADAPTATION_LIST);
}
| non_empty_trait_adaptation_list {
$$ = $1;
}
;
non_empty_trait_adaptation_list:
trait_adaptation_statement {
$$ = NNEW(n_TRAIT_ADAPTATION_LIST);
$$->appendChild($1);
}
| non_empty_trait_adaptation_list trait_adaptation_statement {
$1->appendChild($2);
$$ = $1;
}
;
trait_adaptation_statement:
trait_precedence ';' {
$$ = NMORE($1, $2);
}
| trait_alias ';' {
$$ = NMORE($1, $2);
}
;
trait_precedence:
trait_method_reference_fully_qualified T_INSTEADOF trait_reference_list {
$$ = NNEW(n_TRAIT_INSTEADOF);
$$->appendChild($1);
$$->appendChild($3);
}
;
trait_reference_list:
fully_qualified_class_name {
$$ = NNEW(n_TRAIT_REFERENCE_LIST);
$$->appendChild($1);
}
| trait_reference_list ',' fully_qualified_class_name {
$1->appendChild($3);
$$ = $1;
}
;
trait_method_reference:
T_STRING {
$$ = NNEW(n_TRAIT_METHOD_REFERENCE);
$$->appendChild(NTYPE($1, n_STRING));
}
| trait_method_reference_fully_qualified {
$$ = $1;
}
;
trait_method_reference_fully_qualified:
fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING {
NTYPE($2, n_TRAIT_METHOD_REFERENCE);
NEXPAND($1, $2, NTYPE($3, n_STRING));
$$ = $2;
}
;
trait_alias:
trait_method_reference T_AS trait_modifiers T_STRING {
$$ = NNEW(n_TRAIT_AS);
$$->appendChild($1);
$$->appendChild($3);
$$->appendChild(NTYPE($4, n_STRING));
}
| trait_method_reference T_AS member_modifier {
$$ = NNEW(n_TRAIT_AS);
$$->appendChild($1);
$$->appendChild($3);
$$->appendChild(NNEW(n_EMPTY));
}
;
trait_modifiers:
/* empty */ {
$$ = NNEW(n_EMPTY);
}
| member_modifier {
$$ = NNEW(n_METHOD_MODIFIER_LIST);
$$->appendChild($1);
}
;
method_body:
';' /* abstract method */ {
$$ = NNEW(n_EMPTY);
}
| '{' inner_statement_list '}' {
$$ = NEXPAND($1, $2, $3);
}
;
variable_modifiers:
non_empty_member_modifiers
| T_VAR {
$$ = NNEW(n_CLASS_MEMBER_MODIFIER_LIST);
$$->appendChild(NTYPE($1, n_STRING));
}
;
method_modifiers:
/* empty */ {
$$ = NNEW(n_METHOD_MODIFIER_LIST);
}
| non_empty_member_modifiers {
NTYPE($1, n_METHOD_MODIFIER_LIST);
$$ = $1;
}
;
non_empty_member_modifiers:
member_modifier {
$$ = NNEW(n_CLASS_MEMBER_MODIFIER_LIST);
$$->appendChild($1);
}
| non_empty_member_modifiers member_modifier {
$$ = $1->appendChild($2);
}
;
member_modifier:
basic_member_modifier {
$$ = NTYPE($1, n_STRING);
}
;
basic_member_modifier:
T_PUBLIC
| T_PROTECTED
| T_PRIVATE
| T_STATIC
| T_ABSTRACT
| T_FINAL
;
class_variable_declaration:
class_variable_declaration ',' T_VARIABLE {
$$ = NNEW(n_CLASS_MEMBER_DECLARATION);
$$->appendChild(NTYPE($3, n_VARIABLE));
$$->appendChild(NNEW(n_EMPTY));
$$ = $1->appendChild($$);
}
| class_variable_declaration ',' T_VARIABLE '=' static_scalar {
$$ = NNEW(n_CLASS_MEMBER_DECLARATION);
$$->appendChild(NTYPE($3, n_VARIABLE));
$$->appendChild($5);
$$ = $1->appendChild($$);
}
| T_VARIABLE {
$$ = NNEW(n_CLASS_MEMBER_DECLARATION);
$$->appendChild(NTYPE($1, n_VARIABLE));
$$->appendChild(NNEW(n_EMPTY));
$$ = NNEW(n_CLASS_MEMBER_DECLARATION_LIST)->appendChild($$);
}
| T_VARIABLE '=' static_scalar {
$$ = NNEW(n_CLASS_MEMBER_DECLARATION);
$$->appendChild(NTYPE($1, n_VARIABLE));
$$->appendChild($3);
$$ = NNEW(n_CLASS_MEMBER_DECLARATION_LIST)->appendChild($$);
}
;
class_constant_declaration:
class_constant_declaration ',' T_STRING '=' static_scalar {
$$ = NNEW(n_CLASS_CONSTANT_DECLARATION);
$$->appendChild(NTYPE($3, n_STRING));
$$->appendChild($5);
$1->appendChild($$);
$$ = $1;
}
| T_CONST T_STRING '=' static_scalar {
NTYPE($1, n_CLASS_CONSTANT_DECLARATION_LIST);
$$ = NNEW(n_CLASS_CONSTANT_DECLARATION);
$$->appendChild(NTYPE($2, n_STRING));
$$->appendChild($4);
$1->appendChild($$);
$$ = $1;
}
;
echo_expr_list:
echo_expr_list ',' expr {
$1->appendChild($3);
}
| expr {
$$ = NNEW(n_ECHO_LIST);
$$->appendChild($1);
}
;
for_expr:
/* empty */ {
$$ = NNEW(n_EMPTY);
}
| non_empty_for_expr
;
non_empty_for_expr:
non_empty_for_expr ',' expr {
$1->appendChild($3);
}
| expr {
$$ = NNEW(n_EXPRESSION_LIST);
$$->appendChild($1);
}
;
expr_without_variable:
T_LIST '(' assignment_list ')' '=' expr {
NTYPE($1, n_LIST);
$1->appendChild(NEXPAND($2, $3, $4));
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($5, n_OPERATOR));
$$->appendChild($6);
}
| variable '=' expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| variable '=' '&' variable {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
NTYPE($3, n_VARIABLE_REFERENCE);
$3->appendChild($4);
$$->appendChild($3);
}
| variable '=' '&' T_NEW class_name_reference ctor_arguments {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
NTYPE($4, n_NEW);
$4->appendChild($5);
$4->appendChild($6);
NTYPE($3, n_VARIABLE_REFERENCE);
$3->appendChild($4);
$$->appendChild($3);
}
| T_CLONE expr {
$$ = NNEW(n_UNARY_PREFIX_EXPRESSION);
$$->appendChild(NTYPE($1, n_OPERATOR));
$$->appendChild($2);
}
| variable T_PLUS_EQUAL expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| variable T_MINUS_EQUAL expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| variable T_MUL_EQUAL expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| variable T_DIV_EQUAL expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| variable T_CONCAT_EQUAL expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| variable T_MOD_EQUAL expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| variable T_AND_EQUAL expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| variable T_OR_EQUAL expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| variable T_XOR_EQUAL expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| variable T_SL_EQUAL expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| variable T_SR_EQUAL expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| rw_variable T_INC {
$$ = NNEW(n_UNARY_POSTFIX_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
}
| T_INC rw_variable {
$$ = NNEW(n_UNARY_PREFIX_EXPRESSION);
$$->appendChild(NTYPE($1, n_OPERATOR));
$$->appendChild($2);
}
| rw_variable T_DEC {
$$ = NNEW(n_UNARY_POSTFIX_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
}
| T_DEC rw_variable {
$$ = NNEW(n_UNARY_PREFIX_EXPRESSION);
$$->appendChild(NTYPE($1, n_OPERATOR));
$$->appendChild($2);
}
| expr T_BOOLEAN_OR expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr T_BOOLEAN_AND expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr T_LOGICAL_OR expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr T_LOGICAL_AND expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr T_LOGICAL_XOR expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr '|' expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr '&' expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr '^' expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr '.' expr {
/* The concatenation operator generates n_CONCATENATION_LIST instead of
n_BINARY_EXPRESSION because we tend to run into stack depth issues in a
lot of real-world cases otherwise (e.g., in PHP and JSON decoders). */
if ($1->type == n_CONCATENATION_LIST && $3->type == n_CONCATENATION_LIST) {
$1->appendChild(NTYPE($2, n_OPERATOR));
$1->appendChildren($3);
$$ = $1;
} else if ($1->type == n_CONCATENATION_LIST) {
$1->appendChild(NTYPE($2, n_OPERATOR));
$1->appendChild($3);
$$ = $1;
} else if ($3->type == n_CONCATENATION_LIST) {
$$ = NNEW(n_CONCATENATION_LIST);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChildren($3);
} else {
$$ = NNEW(n_CONCATENATION_LIST);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
}
| expr '+' expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr '-' expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr '*' expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr '/' expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr '%' expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr T_SL expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr T_SR expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| '+' expr %prec T_INC {
$$ = NNEW(n_UNARY_PREFIX_EXPRESSION);
$$->appendChild(NTYPE($1, n_OPERATOR));
$$->appendChild($2);
}
| '-' expr %prec T_INC {
$$ = NNEW(n_UNARY_PREFIX_EXPRESSION);
$$->appendChild(NTYPE($1, n_OPERATOR));
$$->appendChild($2);
}
| '!' expr {
$$ = NNEW(n_UNARY_PREFIX_EXPRESSION);
$$->appendChild(NTYPE($1, n_OPERATOR));
$$->appendChild($2);
}
| '~' expr {
$$ = NNEW(n_UNARY_PREFIX_EXPRESSION);
$$->appendChild(NTYPE($1, n_OPERATOR));
$$->appendChild($2);
}
| expr T_IS_IDENTICAL expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr T_IS_NOT_IDENTICAL expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr T_IS_EQUAL expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr T_IS_NOT_EQUAL expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr '<' expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr T_IS_SMALLER_OR_EQUAL expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr '>' expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr T_IS_GREATER_OR_EQUAL expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr T_SPACESHIP expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| expr T_INSTANCEOF class_name_reference {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| parenthesis_expr
| new_expr
| expr '?' expr ':' expr {
$$ = NNEW(n_TERNARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
$$->appendChild(NTYPE($4, n_OPERATOR));
$$->appendChild($5);
}
| expr '?' ':' expr {
$$ = NNEW(n_TERNARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild(NNEW(n_EMPTY));
$$->appendChild(NTYPE($3, n_OPERATOR));
$$->appendChild($4);
}
| expr T_COALESCE expr {
$$ = NNEW(n_BINARY_EXPRESSION);
$$->appendChild($1);
$$->appendChild(NTYPE($2, n_OPERATOR));
$$->appendChild($3);
}
| internal_functions_in_yacc
| T_INT_CAST expr {
$$ = NNEW(n_CAST_EXPRESSION);
$$->appendChild(NTYPE($1, n_CAST));
$$->appendChild($2);
}
| T_DOUBLE_CAST expr {
$$ = NNEW(n_CAST_EXPRESSION);
$$->appendChild(NTYPE($1, n_CAST));
$$->appendChild($2);
}
| T_STRING_CAST expr {
$$ = NNEW(n_CAST_EXPRESSION);
$$->appendChild(NTYPE($1, n_CAST));
$$->appendChild($2);
}
| T_ARRAY_CAST expr {
$$ = NNEW(n_CAST_EXPRESSION);
$$->appendChild(NTYPE($1, n_CAST));
$$->appendChild($2);
}
| T_OBJECT_CAST expr {
$$ = NNEW(n_CAST_EXPRESSION);
$$->appendChild(NTYPE($1, n_CAST));
$$->appendChild($2);
}
| T_BOOL_CAST expr {
$$ = NNEW(n_CAST_EXPRESSION);
$$->appendChild(NTYPE($1, n_CAST));
$$->appendChild($2);
}
| T_UNSET_CAST expr {
$$ = NNEW(n_CAST_EXPRESSION);
$$->appendChild(NTYPE($1, n_CAST));
$$->appendChild($2);
}
| T_EXIT exit_expr {
$$ = NNEW(n_UNARY_PREFIX_EXPRESSION);
$$->appendChild(NTYPE($1, n_OPERATOR));
$$->appendChild($2);
}
| '@' expr {
$$ = NNEW(n_UNARY_PREFIX_EXPRESSION);
$$->appendChild(NTYPE($1, n_OPERATOR));
$$->appendChild($2);
}
| T_BACKTICKS_EXPR {
NTYPE($1, n_BACKTICKS_EXPRESSION);
$$ = $1;
}
| scalar
| combined_scalar_offset
| combined_scalar
| T_PRINT expr {
$$ = NNEW(n_UNARY_PREFIX_EXPRESSION);
$$->appendChild(NTYPE($1, n_OPERATOR));
$$->appendChild($2);
}
| T_YIELD {
NTYPE($1, n_YIELD);
$1->appendChild(NNEW(n_EMPTY));
$1->appendChild(NNEW(n_EMPTY));
$$ = $1;
}
| function is_reference
'(' parameter_list ')'
lexical_vars return_type
'{' inner_statement_list '}' {
NSPAN($1, n_FUNCTION_DECLARATION, $9);
$1->appendChild(NNEW(n_EMPTY));
$1->appendChild($2);
$1->appendChild(NNEW(n_EMPTY));
$1->appendChild(NEXPAND($3, $4, $5));
$1->appendChild($6);
$1->appendChild($7);
$1->appendChild(NEXPAND($8, $9, $10));
$$ = $1;
}
| T_STATIC function is_reference
'(' parameter_list ')'
lexical_vars return_type
'{' inner_statement_list '}' {
NSPAN($2, n_FUNCTION_DECLARATION, $10);
NMORE($2, $1);
$$ = NNEW(n_FUNCTION_MODIFIER_LIST);
$$->appendChild(NTYPE($1, n_STRING));
$2->appendChild($1);
$2->appendChild(NNEW(n_EMPTY));
$2->appendChild($3);
$2->appendChild(NNEW(n_EMPTY));
$2->appendChild(NEXPAND($4, $5, $6));
$2->appendChild($7);
$2->appendChild($8);
$2->appendChild(NEXPAND($9, $10, $11));
$$ = $2;
}
;
yield_expr:
T_YIELD expr_without_variable {
NTYPE($1, n_YIELD);
$2->appendChild(NNEW(n_EMPTY));
$1->appendChild($2);
$$ = $1;
}
| T_YIELD variable {
NTYPE($1, n_YIELD);
$2->appendChild(NNEW(n_EMPTY));
$1->appendChild($2);
$$ = $1;
}
| T_YIELD expr T_DOUBLE_ARROW expr_without_variable {
NTYPE($1, n_YIELD);
$1->appendChild($2);
$1->appendChild($4);
$$ = $1;
}
| T_YIELD expr T_DOUBLE_ARROW variable {
NTYPE($1, n_YIELD);
$1->appendChild($2);
$1->appendChild($4);
$$ = $1;
}
;
function:
T_FUNCTION
;
lexical_vars:
/* empty */ {
$$ = NNEW(n_EMPTY);
}
| T_USE '(' lexical_var_list ')' {
NTYPE($1, n_LEXICAL_VARIABLE_LIST);
$1->appendChildren($3);
$$ = $1;
}
;
lexical_var_list:
lexical_var_list ',' T_VARIABLE {
$$ = $1->appendChild(NTYPE($3, n_VARIABLE));
}
| lexical_var_list ',' '&' T_VARIABLE {
NTYPE($3, n_VARIABLE_REFERENCE);
$3->appendChild(NTYPE($4, n_VARIABLE));
$$ = $1->appendChild($3);
}
| T_VARIABLE {
$$ = NNEW(n_LEXICAL_VARIABLE_LIST);
$$->appendChild(NTYPE($1, n_VARIABLE));
}
| '&' T_VARIABLE {
NTYPE($1, n_VARIABLE_REFERENCE);
$1->appendChild(NTYPE($2, n_VARIABLE));
$$ = NNEW(n_LEXICAL_VARIABLE_LIST);
$$->appendChild($1);
}
;
function_call:
namespace_name '(' function_call_parameter_list ')' {
$$ = NNEW(n_FUNCTION_CALL);
$$->appendChild($1);
$$->appendChild(NEXPAND($2, $3, $4));
}
| T_NAMESPACE T_NS_SEPARATOR namespace_name
'(' function_call_parameter_list ')' {
NMORE($3, $1);
$$ = NNEW(n_FUNCTION_CALL);
$$->appendChild($3);
$$->appendChild(NEXPAND($4, $5, $6));
}
| T_NS_SEPARATOR namespace_name '(' function_call_parameter_list ')' {
NMORE($2, $1);
$$ = NNEW(n_FUNCTION_CALL);
$$->appendChild($2);
$$->appendChild(NEXPAND($3, $4, $5));
}
| class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING
'(' function_call_parameter_list ')' {
$$ = NNEW(n_CLASS_STATIC_ACCESS);
$$->appendChild($1);
$$->appendChild(NTYPE($3, n_STRING));
$$ = NNEW(n_FUNCTION_CALL)->appendChild($$);
$$->appendChild(NEXPAND($4, $5, $6));
}
| variable_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING
'(' function_call_parameter_list ')' {
$$ = NNEW(n_CLASS_STATIC_ACCESS);
$$->appendChild($1);
$$->appendChild(NTYPE($3, n_STRING));
$$ = NNEW(n_FUNCTION_CALL)->appendChild($$);
$$->appendChild(NEXPAND($4, $5, $6));
}
| variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects
'(' function_call_parameter_list ')' {
$$ = NNEW(n_CLASS_STATIC_ACCESS);
$$->appendChild($1);
$$->appendChild(NTYPE($3, n_STRING));
$$ = NNEW(n_FUNCTION_CALL)->appendChild($$);
$$->appendChild(NEXPAND($4, $5, $6));
}
| class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects
'(' function_call_parameter_list ')' {
$$ = NNEW(n_CLASS_STATIC_ACCESS);
$$->appendChild($1);
$$->appendChild(NTYPE($3, n_STRING));
$$ = NNEW(n_FUNCTION_CALL)->appendChild($$);
$$->appendChild(NEXPAND($4, $5, $6));
}
| variable_without_objects '(' function_call_parameter_list ')' {
$$ = NNEW(n_FUNCTION_CALL);
$$->appendChild($1);
$$->appendChild(NEXPAND($2, $3, $4));
}
;
class_name:
T_STATIC {
$$ = NTYPE($1, n_CLASS_NAME);
}
| namespace_name {
$$ = NTYPE($1, n_CLASS_NAME);
}
| T_NAMESPACE T_NS_SEPARATOR namespace_name {
NMORE($3, $1);
$$ = NTYPE($3, n_CLASS_NAME);
}
| T_NS_SEPARATOR namespace_name {
NMORE($2, $1);
$$ = NTYPE($2, n_CLASS_NAME);
}
;
fully_qualified_class_name:
namespace_name {
$$ = NTYPE($1, n_CLASS_NAME);
}
| T_NAMESPACE T_NS_SEPARATOR namespace_name {
NMORE($3, $1);
$$ = NTYPE($3, n_CLASS_NAME);
}
| T_NS_SEPARATOR namespace_name {
NMORE($2, $1);
$$ = NTYPE($2, n_CLASS_NAME);
}
;
class_name_reference:
class_name
| dynamic_class_name_reference
;
dynamic_class_name_reference:
base_variable
T_OBJECT_OPERATOR
object_property
dynamic_class_name_variable_properties {
$$ = NNEW(n_OBJECT_PROPERTY_ACCESS);
$$->appendChild($1);
$$->appendChild($3);
for (xhpast::node_list_t::iterator ii = $4->children.begin();
ii != $4->children.end();
++ii) {
$$ = NNEW(n_OBJECT_PROPERTY_ACCESS)->appendChild($$);
$$->appendChild(*ii);
}
}
| base_variable
;
dynamic_class_name_variable_properties:
dynamic_class_name_variable_properties dynamic_class_name_variable_property {
$$ = $1->appendChild($2);
}
| /* empty */ {
$$ = NNEW(n_EMPTY);
}
;
dynamic_class_name_variable_property:
T_OBJECT_OPERATOR object_property {
$$ = $2;
}
;
exit_expr:
/* empty */ {
$$ = NNEW(n_EMPTY);
}
| '(' ')' {
NSPAN($1, n_EMPTY, $2);
$$ = $1;
}
| '(' expr ')' {
NSPAN($1, n_PARENTHETICAL_EXPRESSION, $3);
$1->appendChild($2);
$$ = $1;
}
;
ctor_arguments:
/* empty */ {
$$ = NNEW(n_EMPTY);
}
| '(' function_call_parameter_list ')' {
$$ = NEXPAND($1, $2, $3);
}
;
common_scalar:
T_LNUMBER {
$$ = NTYPE($1, n_NUMERIC_SCALAR);
}
| T_DNUMBER {
$$ = NTYPE($1, n_NUMERIC_SCALAR);
}
| T_CONSTANT_ENCAPSED_STRING {
$$ = NTYPE($1, n_STRING_SCALAR);
}
| T_LINE {
$$ = NTYPE($1, n_MAGIC_SCALAR);
}
| T_FILE {
$$ = NTYPE($1, n_MAGIC_SCALAR);
}
| T_DIR {
$$ = NTYPE($1, n_MAGIC_SCALAR);
}
| T_CLASS_C {
$$ = NTYPE($1, n_MAGIC_SCALAR);
}
| T_METHOD_C {
$$ = NTYPE($1, n_MAGIC_SCALAR);
}
| T_TRAIT_C {
$$ = NTYPE($1, n_MAGIC_SCALAR);
}
| T_FUNC_C {
$$ = NTYPE($1, n_MAGIC_SCALAR);
}
| T_NS_C {
$$ = NTYPE($1, n_MAGIC_SCALAR);
}
| T_HEREDOC {
$$ = NTYPE($1, n_HEREDOC);
}
;
static_scalar: /* compile-time evaluated scalars */
common_scalar
| namespace_name
| T_NAMESPACE T_NS_SEPARATOR namespace_name {
NMORE($3, $1);
$$ = $3;
}
| T_NS_SEPARATOR namespace_name {
NMORE($2, $1);
$$ = $2;
}
| '+' static_scalar {
$$ = NNEW(n_UNARY_PREFIX_EXPRESSION);
$$->appendChild(NTYPE($1, n_OPERATOR));
$$->appendChild($2);
}
| '-' static_scalar {
$$ = NNEW(n_UNARY_PREFIX_EXPRESSION);
$$->appendChild(NTYPE($1, n_OPERATOR));
$$->appendChild($2);
}
| T_ARRAY '(' static_array_pair_list ')' {
NTYPE($1, n_ARRAY_LITERAL);
$1->appendChild(NEXPAND($2, $3, $4));
$$ = $1;
}
| '[' static_array_pair_list ']' {
NTYPE($1, n_ARRAY_LITERAL);
$1->appendChild(NEXPAND($1, $2, $3));
$$ = $1;
}
| static_class_constant
;
static_class_constant:
class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING {
$$ = NNEW(n_CLASS_STATIC_ACCESS);
$$->appendChild($1);
$$->appendChild(NTYPE($3, n_STRING));
}
;
scalar:
T_STRING_VARNAME
| class_constant
| namespace_name
| T_NAMESPACE T_NS_SEPARATOR namespace_name {
$$ = NMORE($3, $1);
}
| T_NS_SEPARATOR namespace_name {
$$ = NMORE($2, $1);
}
| common_scalar
;
static_array_pair_list:
/* empty */ {
$$ = NNEW(n_ARRAY_VALUE_LIST);
}
| non_empty_static_array_pair_list possible_comma {
$$ = NMORE($1, $2);
}
;
possible_comma:
/* empty */ {
$$ = NNEW(n_EMPTY);
}
| ','
;
non_empty_static_array_pair_list:
non_empty_static_array_pair_list
','
static_scalar
T_DOUBLE_ARROW
static_scalar {
$$ = NNEW(n_ARRAY_VALUE);
$$->appendChild($3);
$$->appendChild($5);
$$ = $1->appendChild($$);
}
| non_empty_static_array_pair_list ',' static_scalar {
$$ = NNEW(n_ARRAY_VALUE);
$$->appendChild(NNEW(n_EMPTY));
$$->appendChild($3);
$$ = $1->appendChild($$);
}
| static_scalar T_DOUBLE_ARROW static_scalar {
$$ = NNEW(n_ARRAY_VALUE);
$$->appendChild($1);
$$->appendChild($3);
$$ = NNEW(n_ARRAY_VALUE_LIST)->appendChild($$);
}
| static_scalar {
$$ = NNEW(n_ARRAY_VALUE);
$$->appendChild(NNEW(n_EMPTY));
$$->appendChild($1);
$$ = NNEW(n_ARRAY_VALUE_LIST)->appendChild($$);
}
;
expr:
r_variable
| expr_without_variable
;
r_variable:
variable
;
w_variable:
variable
;
rw_variable:
variable
;
variable:
base_variable_with_function_calls
T_OBJECT_OPERATOR
object_property method_or_not
variable_properties {
$$ = NNEW(n_OBJECT_PROPERTY_ACCESS);
$$->appendChild($1);
$$->appendChild($3);
if ($4->type != n_EMPTY) {
$$ = NNEW(n_METHOD_CALL)->appendChild($$);
$$->appendChild($4);
}
for (xhpast::node_list_t::iterator ii = $5->children.begin();
ii != $5->children.end();
++ii) {
if ((*ii)->type == n_CALL_PARAMETER_LIST) {
$$ = NNEW(n_METHOD_CALL)->appendChild($$);
$$->appendChild((*ii));
} else {
$$ = NNEW(n_OBJECT_PROPERTY_ACCESS)->appendChild($$);
$$->appendChild((*ii));
}
}
}
| base_variable_with_function_calls
;
variable_properties:
variable_properties variable_property {
$$ = $1->appendChildren($2);
}
| /* empty */ {
$$ = NNEW(n_EMPTY);
}
;
variable_property:
T_OBJECT_OPERATOR object_property method_or_not {
$$ = NNEW(n_EMPTY);
$$->appendChild($2);
if ($3->type != n_EMPTY) {
$$->appendChild($3);
}
}
;
array_method_dereference:
array_method_dereference '[' dim_offset ']' {
$$ = NNEW(n_INDEX_ACCESS);
$$->appendChild($1);
$$->appendChild($3);
NMORE($$, $4);
}
| method '[' dim_offset ']' {
$$ = NNEW(n_INDEX_ACCESS);
$$->appendChild($1);
$$->appendChild($3);
NMORE($$, $4);
}
;
method:
'(' function_call_parameter_list ')' {
$$ = NEXPAND($1, $2, $3);
}
;
method_or_not:
method
| array_method_dereference
| /* empty */ {
$$ = NNEW(n_EMPTY);
}
;
variable_without_objects:
reference_variable
| simple_indirect_reference reference_variable {
xhpast::Node *last = $1;
NMORE($1, $2);
while (last->firstChild() &&
last->firstChild()->type == n_VARIABLE_VARIABLE) {
NMORE(last, $2);
last = last->firstChild();
}
last->appendChild($2);
$$ = $1;
}
;
static_member:
class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects {
$$ = NNEW(n_CLASS_STATIC_ACCESS);
$$->appendChild($1);
$$->appendChild($3);
}
| variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects {
$$ = NNEW(n_CLASS_STATIC_ACCESS);
$$->appendChild($1);
$$->appendChild($3);
}
;
variable_class_name:
reference_variable
;
array_function_dereference:
array_function_dereference '[' dim_offset ']' {
$$ = NNEW(n_INDEX_ACCESS);
$$->appendChild($1);
$$->appendChild($3);
NMORE($$, $4);
}
| function_call '[' dim_offset ']' {
$$ = NNEW(n_INDEX_ACCESS);
$$->appendChild($1);
$$->appendChild($3);
NMORE($$, $4);
}
;
base_variable_with_function_calls:
base_variable
| array_function_dereference
| function_call
;
base_variable:
reference_variable
| '(' new_expr ')' {
$$ = NEXPAND($1, $2, $3);
}
| simple_indirect_reference reference_variable {
xhpast::Node *last = $1;
NMORE($1, $2);
while (last->firstChild() &&
last->firstChild()->type == n_VARIABLE_VARIABLE) {
NMORE(last, $2);
last = last->firstChild();
}
last->appendChild($2);
$$ = $1;
}
| static_member
;
reference_variable:
reference_variable '[' dim_offset ']' {
$$ = NNEW(n_INDEX_ACCESS);
$$->appendChild($1);
$$->appendChild($3);
NMORE($$, $4);
}
| reference_variable '{' expr '}' {
$$ = NNEW(n_INDEX_ACCESS);
$$->appendChild($1);
$$->appendChild($3);
NMORE($$, $4);
}
| compound_variable
;
compound_variable:
T_VARIABLE {
NTYPE($1, n_VARIABLE);
}
| '$' '{' expr '}' {
NSPAN($1, n_VARIABLE_EXPRESSION, $4);
$1->appendChild($3);
$$ = $1;
}
;
dim_offset:
/* empty */ {
$$ = NNEW(n_EMPTY);
}
| expr {
$$ = $1;
}
;
object_property:
object_dim_list
| variable_without_objects
;
object_dim_list:
object_dim_list '[' dim_offset ']' {
$$ = NNEW(n_INDEX_ACCESS);
$$->appendChild($1);
$$->appendChild($3);
NMORE($$, $4);
}
| object_dim_list '{' expr '}' {
$$ = NNEW(n_INDEX_ACCESS);
$$->appendChild($1);
$$->appendChild($3);
NMORE($$, $4);
}
| variable_name
;
variable_name:
T_STRING {
NTYPE($1, n_STRING);
$$ = $1;
}
| '{' expr '}' {
$$ = NEXPAND($1, $2, $3);
}
;
simple_indirect_reference:
'$' {
$$ = NTYPE($1, n_VARIABLE_VARIABLE);
}
| simple_indirect_reference '$' {
$2 = NTYPE($2, n_VARIABLE_VARIABLE);
xhpast::Node *last = $1;
while (last->firstChild() &&
last->firstChild()->type == n_VARIABLE_VARIABLE) {
last = last->firstChild();
}
last->appendChild($2);
$$ = $1;
}
;
assignment_list:
assignment_list ',' assignment_list_element {
$$ = $1->appendChild($3);
}
| assignment_list_element {
$$ = NNEW(n_ASSIGNMENT_LIST);
$$->appendChild($1);
}
;
assignment_list_element:
variable
| T_LIST '(' assignment_list ')' {
$$ = NNEW(n_LIST);
$$->appendChild(NEXPAND($2, $3, $4));
}
| /* empty */ {
$$ = NNEW(n_EMPTY);
}
;
array_pair_list:
/* empty */ {
$$ = NNEW(n_ARRAY_VALUE_LIST);
}
| non_empty_array_pair_list possible_comma {
$$ = NMORE($1, $2);
}
;
non_empty_array_pair_list:
non_empty_array_pair_list ',' expr T_DOUBLE_ARROW expr {
$$ = NNEW(n_ARRAY_VALUE);
$$->appendChild($3);
$$->appendChild($5);
$$ = $1->appendChild($$);
}
| non_empty_array_pair_list ',' expr {
$$ = NNEW(n_ARRAY_VALUE);
$$->appendChild(NNEW(n_EMPTY));
$$->appendChild($3);
$$ = $1->appendChild($$);
}
| expr T_DOUBLE_ARROW expr {
$$ = NNEW(n_ARRAY_VALUE);
$$->appendChild($1);
$$->appendChild($3);
$$ = NNEW(n_ARRAY_VALUE_LIST)->appendChild($$);
}
| expr {
$$ = NNEW(n_ARRAY_VALUE);
$$->appendChild(NNEW(n_EMPTY));
$$->appendChild($1);
$$ = NNEW(n_ARRAY_VALUE_LIST)->appendChild($$);
}
| non_empty_array_pair_list ',' expr T_DOUBLE_ARROW '&' w_variable {
$$ = NNEW(n_ARRAY_VALUE);
$$->appendChild($3);
$$->appendChild(NTYPE($5, n_VARIABLE_REFERENCE)->appendChild($6));
$$ = $1->appendChild($$);
}
| non_empty_array_pair_list ',' '&' w_variable {
$$ = NNEW(n_ARRAY_VALUE);
$$->appendChild(NNEW(n_EMPTY));
$$->appendChild(NTYPE($3, n_VARIABLE_REFERENCE)->appendChild($4));
$$ = $1->appendChild($$);
}
| expr T_DOUBLE_ARROW '&' w_variable {
$$ = NNEW(n_ARRAY_VALUE);
$$->appendChild($1);
$$->appendChild(NTYPE($3, n_VARIABLE_REFERENCE)->appendChild($4));
$$ = NNEW(n_ARRAY_VALUE_LIST)->appendChild($$);
}
| '&' w_variable {
$$ = NNEW(n_ARRAY_VALUE);
$$->appendChild(NNEW(n_EMPTY));
$$->appendChild(NTYPE($1, n_VARIABLE_REFERENCE)->appendChild($2));
$$ = NNEW(n_ARRAY_VALUE_LIST)->appendChild($$);
}
;
internal_functions_in_yacc:
T_ISSET '(' isset_variables ')' {
NTYPE($1, n_SYMBOL_NAME);
NSPAN($2, n_CALL_PARAMETER_LIST, $4);
$2->appendChildren($3);
$$ = NNEW(n_FUNCTION_CALL);
$$->appendChild($1);
$$->appendChild($2);
}
| T_EMPTY '(' variable ')' {
NTYPE($1, n_SYMBOL_NAME);
NSPAN($2, n_CALL_PARAMETER_LIST, $4);
$2->appendChild($3);
$$ = NNEW(n_FUNCTION_CALL);
$$->appendChild($1);
$$->appendChild($2);
}
| T_INCLUDE expr {
$$ = NTYPE($1, n_INCLUDE_FILE)->appendChild($2);
}
| T_INCLUDE_ONCE expr {
$$ = NTYPE($1, n_INCLUDE_FILE)->appendChild($2);
}
| T_EVAL '(' expr ')' {
NTYPE($1, n_SYMBOL_NAME);
NSPAN($2, n_CALL_PARAMETER_LIST, $4);
$2->appendChild($3);
$$ = NNEW(n_FUNCTION_CALL);
$$->appendChild($1);
$$->appendChild($2);
}
| T_REQUIRE expr {
$$ = NTYPE($1, n_INCLUDE_FILE)->appendChild($2);
}
| T_REQUIRE_ONCE expr {
$$ = NTYPE($1, n_INCLUDE_FILE)->appendChild($2);
}
;
isset_variables:
variable {
$$ = NNEW(n_EMPTY);
$$->appendChild($1);
}
| isset_variables ',' variable {
$$ = $1->appendChild($3);
}
;
parenthesis_expr:
'(' expr ')' {
NSPAN($1, n_PARENTHETICAL_EXPRESSION, $3);
$1->appendChild($2);
$$ = $1;
}
| '(' yield_expr ')' {
$$ = NEXPAND($1, $2, $3);
}
;
combined_scalar_offset:
combined_scalar '[' dim_offset ']' {
$$ = NNEW(n_INDEX_ACCESS);
$$->appendChild($1);
$$->appendChild($3);
NMORE($$, $4);
}
| combined_scalar_offset '[' dim_offset ']' {
$$ = NNEW(n_INDEX_ACCESS);
$$->appendChild($1);
$$->appendChild($3);
NMORE($$, $4);
}
| T_CONSTANT_ENCAPSED_STRING '[' dim_offset ']' {
$$ = NNEW(n_INDEX_ACCESS);
$$->appendChild(NTYPE($1, n_STRING_SCALAR));
$$->appendChild($3);
NMORE($$, $4);
}
| class_constant '[' dim_offset ']' {
$$ = NNEW(n_INDEX_ACCESS);
$$->appendChild($1);
$$->appendChild($3);
NMORE($$, $4);
}
| T_STRING '[' dim_offset ']' {
$$ = NNEW(n_INDEX_ACCESS);
$$->appendChild(NTYPE($1, n_STRING));
$$->appendChild($3);
NMORE($$, $4);
}
;
combined_scalar:
T_ARRAY '(' array_pair_list ')' {
NTYPE($1, n_ARRAY_LITERAL);
$1->appendChild(NEXPAND($2, $3, $4));
$$ = $1;
}
| '[' array_pair_list ']' {
NTYPE($1, n_ARRAY_LITERAL);
$1->appendChild(NEXPAND($1, $2, $3));
$$ = $1;
}
;
new_expr:
T_NEW class_name_reference ctor_arguments {
NTYPE($1, n_NEW);
$1->appendChild($2);
$1->appendChild($3);
$$ = $1;
}
| T_NEW T_CLASS ctor_arguments extends_from implements_list
'{' class_statement_list '}' {
$$ = NNEW(n_CLASS_DECLARATION);
$$->appendChild(NNEW(n_EMPTY));
$$->appendChild(NNEW(n_EMPTY));
$$->appendChild($4);
$$->appendChild($5);
$$->appendChild(NEXPAND($6, $7, $8));
NMORE($$, $8);
NTYPE($1, n_NEW);
$1->appendChild($$);
$1->appendChild($3);
$$ = $1;
}
;
class_constant:
class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING {
$$ = NNEW(n_CLASS_STATIC_ACCESS);
$$->appendChild($1);
$$->appendChild(NTYPE($3, n_STRING));
}
| variable_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING {
$$ = NNEW(n_CLASS_STATIC_ACCESS);
$$->appendChild($1);
$$->appendChild(NTYPE($3, n_STRING));
}
;
%%
const char* yytokname(int tok) {
if (tok < 255) {
return NULL;
}
return yytname[YYTRANSLATE(tok)];
}