updated backend

This commit is contained in:
Torsten 2020-01-17 10:58:01 +01:00
parent 1fea0f4fe7
commit 11521c2339
3459 changed files with 72735 additions and 168535 deletions

View file

@ -11,7 +11,7 @@ What do all those files mean?
.phpy pseudo language
=====================
The `.y` file is a normal grammer in `kmyacc` (`yacc`) style, with some transformations
The `.y` file is a normal grammar in `kmyacc` (`yacc`) style, with some transformations
applied to it:
* Nodes are created using the syntax `Name[..., ...]`. This is transformed into
@ -21,8 +21,10 @@ applied to it:
Building the parser
===================
In order to rebuild the parser, you need [moriyoshi's fork of kmyacc](https://github.com/moriyoshi/kmyacc-forked).
After you compiled/installed it, run the `rebuildParsers.php` script.
Run `php grammar/rebuildParsers.php` to rebuild the parsers. Additional options:
By default only the `Parser.php` is built. If you want to additionally emit debug symbols and create `y.output`, run the
script with `--debug`. If you want to retain the preprocessed grammar pass `--keep-tmp-grammar`.
* The `KMYACC` environment variable can be used to specify an alternative `kmyacc` binary.
By default the `phpyacc` dev dependency will be used. To use the original `kmyacc`, you
need to compile [moriyoshi's fork](https://github.com/moriyoshi/kmyacc-forked).
* The `--debug` option enables emission of debug symbols and creates the `y.output` file.
* The `--keep-tmp-grammar` option preserves the preprocessed grammar file.

View file

@ -2,8 +2,8 @@
$meta #
#semval($) $this->semValue
#semval($,%t) $this->semValue
#semval(%n) $this->stackPos-(%l-%n)
#semval(%n,%t) $this->stackPos-(%l-%n)
#semval(%n) $stackPos-(%l-%n)
#semval(%n,%t) $stackPos-(%l-%n)
namespace PhpParser\Parser;
@ -32,8 +32,8 @@ class #(-p) extends \PhpParser\ParserAbstract
protected $defaultAction = #(YYDEFAULT);
protected $unexpectedTokenRule = #(YYUNEXPECTED);
protected $YY2TBLSTATE = #(YY2TBLSTATE);
protected $YYNLSTATES = #(YYNLSTATES);
protected $YY2TBLSTATE = #(YY2TBLSTATE);
protected $numNonLeafStates = #(YYNLSTATES);
protected $symbolToName = array(
#listvar terminals
@ -88,16 +88,19 @@ class #(-p) extends \PhpParser\ParserAbstract
#production-strings;
);
#endif
protected function initReduceCallbacks() {
$this->reduceCallbacks = [
#reduce
protected function reduceRule%n() {
%b
}
%n => function ($stackPos) {
%b
},
#noact
protected function reduceRule%n() {
$this->semValue = $this->semStack[$this->stackPos];
}
%n => function ($stackPos) {
$this->semValue = $this->semStack[$stackPos];
},
#endreduce
];
}
}
#tailcode;

View file

@ -16,7 +16,7 @@ top_statement_list_ex:
top_statement_list:
top_statement_list_ex
{ makeNop($nop, $this->lookaheadStartAttributes);
{ makeZeroLengthNop($nop, $this->lookaheadStartAttributes);
if ($nop !== null) { $1[] = $nop; } $$ = $1; }
;
@ -27,7 +27,7 @@ reserved_non_modifiers:
| T_FINALLY | T_THROW | T_USE | T_INSTEADOF | T_GLOBAL | T_VAR | T_UNSET | T_ISSET | T_EMPTY | T_CONTINUE | T_GOTO
| T_FUNCTION | T_CONST | T_RETURN | T_PRINT | T_YIELD | T_LIST | T_SWITCH | T_ENDSWITCH | T_CASE | T_DEFAULT
| T_BREAK | T_ARRAY | T_CALLABLE | T_EXTENDS | T_IMPLEMENTS | T_NAMESPACE | T_TRAIT | T_INTERFACE | T_CLASS
| T_CLASS_C | T_TRAIT_C | T_FUNC_C | T_METHOD_C | T_LINE | T_FILE | T_DIR | T_NS_C | T_HALT_COMPILER
| T_CLASS_C | T_TRAIT_C | T_FUNC_C | T_METHOD_C | T_LINE | T_FILE | T_DIR | T_NS_C | T_HALT_COMPILER | T_FN
;
semi_reserved:
@ -35,9 +35,17 @@ semi_reserved:
| T_STATIC | T_ABSTRACT | T_FINAL | T_PRIVATE | T_PROTECTED | T_PUBLIC
;
identifier_ex:
T_STRING { $$ = Node\Identifier[$1]; }
| semi_reserved { $$ = Node\Identifier[$1]; }
;
identifier:
T_STRING { $$ = $1; }
| semi_reserved { $$ = $1; }
T_STRING { $$ = Node\Identifier[$1]; }
;
reserved_non_modifiers_identifier:
reserved_non_modifiers { $$ = Node\Identifier[$1]; }
;
namespace_name_parts:
@ -49,6 +57,10 @@ namespace_name:
namespace_name_parts { $$ = Name[$1]; }
;
plain_variable:
T_VARIABLE { $$ = Expr\Variable[parseVar($1)]; }
;
top_statement:
statement { $$ = $1; }
| function_declaration_statement { $$ = $1; }
@ -109,7 +121,7 @@ inline_use_declarations:
unprefixed_use_declaration:
namespace_name
{ $$ = Stmt\UseUse[$1, null, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #1); }
| namespace_name T_AS T_STRING
| namespace_name T_AS identifier
{ $$ = Stmt\UseUse[$1, $3, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #3); }
;
@ -129,7 +141,7 @@ constant_declaration_list:
;
constant_declaration:
T_STRING '=' static_scalar { $$ = Node\Const_[$1, $3]; }
identifier '=' static_scalar { $$ = Node\Const_[$1, $3]; }
;
class_const_list:
@ -138,7 +150,7 @@ class_const_list:
;
class_const:
identifier '=' static_scalar { $$ = Node\Const_[$1, $3]; }
identifier_ex '=' static_scalar { $$ = Node\Const_[$1, $3]; }
;
inner_statement_list_ex:
@ -148,7 +160,7 @@ inner_statement_list_ex:
inner_statement_list:
inner_statement_list_ex
{ makeNop($nop, $this->lookaheadStartAttributes);
{ makeZeroLengthNop($nop, $this->lookaheadStartAttributes);
if ($nop !== null) { $1[] = $nop; } $$ = $1; }
;
@ -166,7 +178,7 @@ non_empty_statement:
if ($2) {
$$ = $2; prependLeadingComments($$);
} else {
makeNop($$, $this->startAttributeStack[#1]);
makeNop($$, $this->startAttributeStack[#1], $this->endAttributes);
if (null === $$) { $$ = array(); }
}
}
@ -185,12 +197,12 @@ non_empty_statement:
| T_CONTINUE expr ';' { $$ = Stmt\Continue_[$2]; }
| T_RETURN ';' { $$ = Stmt\Return_[null]; }
| T_RETURN expr ';' { $$ = Stmt\Return_[$2]; }
| yield_expr ';' { $$ = $1; }
| T_GLOBAL global_var_list ';' { $$ = Stmt\Global_[$2]; }
| T_STATIC static_var_list ';' { $$ = Stmt\Static_[$2]; }
| T_ECHO expr_list ';' { $$ = Stmt\Echo_[$2]; }
| T_INLINE_HTML { $$ = Stmt\InlineHTML[$1]; }
| expr ';' { $$ = $1; }
| yield_expr ';' { $$ = Stmt\Expression[$1]; }
| expr ';' { $$ = Stmt\Expression[$1]; }
| T_UNSET '(' variables_list ')' ';' { $$ = Stmt\Unset_[$3]; }
| T_FOREACH '(' expr T_AS foreach_variable ')' foreach_statement
{ $$ = Stmt\Foreach_[$3, $5[0], ['keyVar' => null, 'byRef' => $5[1], 'stmts' => $7]]; }
@ -200,16 +212,16 @@ non_empty_statement:
| T_TRY '{' inner_statement_list '}' catches optional_finally
{ $$ = Stmt\TryCatch[$3, $5, $6]; $this->checkTryCatch($$); }
| T_THROW expr ';' { $$ = Stmt\Throw_[$2]; }
| T_GOTO T_STRING ';' { $$ = Stmt\Goto_[$2]; }
| T_STRING ':' { $$ = Stmt\Label[$1]; }
| expr error { $$ = $1; }
| T_GOTO identifier ';' { $$ = Stmt\Goto_[$2]; }
| identifier ':' { $$ = Stmt\Label[$1]; }
| expr error { $$ = Stmt\Expression[$1]; }
| error { $$ = array(); /* means: no statement */ }
;
statement:
non_empty_statement { $$ = $1; }
| ';'
{ makeNop($$, $this->startAttributeStack[#1]);
{ makeNop($$, $this->startAttributeStack[#1], $this->endAttributes);
if ($$ === null) $$ = array(); /* means: no statement */ }
;
@ -219,8 +231,8 @@ catches:
;
catch:
T_CATCH '(' name T_VARIABLE ')' '{' inner_statement_list '}'
{ $$ = Stmt\Catch_[array($3), parseVar($4), $7]; }
T_CATCH '(' name plain_variable ')' '{' inner_statement_list '}'
{ $$ = Stmt\Catch_[array($3), $4, $7]; }
;
optional_finally:
@ -244,18 +256,18 @@ optional_ellipsis:
;
function_declaration_statement:
T_FUNCTION optional_ref T_STRING '(' parameter_list ')' optional_return_type '{' inner_statement_list '}'
T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type '{' inner_statement_list '}'
{ $$ = Stmt\Function_[$3, ['byRef' => $2, 'params' => $5, 'returnType' => $7, 'stmts' => $9]]; }
;
class_declaration_statement:
class_entry_type T_STRING extends_from implements_list '{' class_statement_list '}'
class_entry_type identifier extends_from implements_list '{' class_statement_list '}'
{ $$ = Stmt\Class_[$2, ['type' => $1, 'extends' => $3, 'implements' => $4, 'stmts' => $6]];
$this->checkClass($$, #2); }
| T_INTERFACE T_STRING interface_extends_list '{' class_statement_list '}'
| T_INTERFACE identifier interface_extends_list '{' class_statement_list '}'
{ $$ = Stmt\Interface_[$2, ['extends' => $3, 'stmts' => $5]];
$this->checkInterface($$, #2); }
| T_TRAIT T_STRING '{' class_statement_list '}'
| T_TRAIT identifier '{' class_statement_list '}'
{ $$ = Stmt\Trait_[$2, ['stmts' => $4]]; }
;
@ -307,7 +319,7 @@ declare_list:
;
declare_list_element:
T_STRING '=' static_scalar { $$ = Stmt\DeclareDeclare[$1, $3]; }
identifier '=' static_scalar { $$ = Stmt\DeclareDeclare[$1, $3]; }
;
switch_case_list:
@ -382,16 +394,16 @@ non_empty_parameter_list:
;
parameter:
optional_param_type optional_ref optional_ellipsis T_VARIABLE
{ $$ = Node\Param[parseVar($4), null, $1, $2, $3]; $this->checkParam($$); }
| optional_param_type optional_ref optional_ellipsis T_VARIABLE '=' static_scalar
{ $$ = Node\Param[parseVar($4), $6, $1, $2, $3]; $this->checkParam($$); }
optional_param_type optional_ref optional_ellipsis plain_variable
{ $$ = Node\Param[$4, null, $1, $2, $3]; $this->checkParam($$); }
| optional_param_type optional_ref optional_ellipsis plain_variable '=' static_scalar
{ $$ = Node\Param[$4, $6, $1, $2, $3]; $this->checkParam($$); }
;
type:
name { $$ = $1; }
| T_ARRAY { $$ = 'array'; }
| T_CALLABLE { $$ = 'callable'; }
| T_ARRAY { $$ = Node\Identifier['array']; }
| T_CALLABLE { $$ = Node\Identifier['callable']; }
;
optional_param_type:
@ -427,7 +439,7 @@ global_var_list:
;
global_var:
T_VARIABLE { $$ = Expr\Variable[parseVar($1)]; }
plain_variable { $$ = $1; }
| '$' variable { $$ = Expr\Variable[$2]; }
| '$' '{' expr '}' { $$ = Expr\Variable[$3]; }
;
@ -438,20 +450,26 @@ static_var_list:
;
static_var:
T_VARIABLE { $$ = Stmt\StaticVar[parseVar($1), null]; }
| T_VARIABLE '=' static_scalar { $$ = Stmt\StaticVar[parseVar($1), $3]; }
plain_variable { $$ = Stmt\StaticVar[$1, null]; }
| plain_variable '=' static_scalar { $$ = Stmt\StaticVar[$1, $3]; }
;
class_statement_list_ex:
class_statement_list_ex class_statement { if ($2 !== null) { push($1, $2); } }
| /* empty */ { init(); }
;
class_statement_list:
class_statement_list class_statement { push($1, $2); }
| /* empty */ { init(); }
class_statement_list_ex
{ makeZeroLengthNop($nop, $this->lookaheadStartAttributes);
if ($nop !== null) { $1[] = $nop; } $$ = $1; }
;
class_statement:
variable_modifiers property_declaration_list ';'
{ $$ = Stmt\Property[$1, $2]; $this->checkProperty($$, #1); }
| T_CONST class_const_list ';' { $$ = Stmt\ClassConst[$2, 0]; }
| method_modifiers T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type method_body
| method_modifiers T_FUNCTION optional_ref identifier_ex '(' parameter_list ')' optional_return_type method_body
{ $$ = Stmt\ClassMethod[$4, ['type' => $1, 'byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9]];
$this->checkClassMethod($$, #1); }
| T_USE class_name_list trait_adaptations { $$ = Stmt\TraitUse[$2, $3]; }
@ -470,22 +488,22 @@ trait_adaptation_list:
trait_adaptation:
trait_method_reference_fully_qualified T_INSTEADOF class_name_list ';'
{ $$ = Stmt\TraitUseAdaptation\Precedence[$1[0], $1[1], $3]; }
| trait_method_reference T_AS member_modifier identifier ';'
| trait_method_reference T_AS member_modifier identifier_ex ';'
{ $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], $3, $4]; }
| trait_method_reference T_AS member_modifier ';'
{ $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], $3, null]; }
| trait_method_reference T_AS T_STRING ';'
| trait_method_reference T_AS identifier ';'
{ $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], null, $3]; }
| trait_method_reference T_AS reserved_non_modifiers ';'
| trait_method_reference T_AS reserved_non_modifiers_identifier ';'
{ $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], null, $3]; }
;
trait_method_reference_fully_qualified:
name T_PAAMAYIM_NEKUDOTAYIM identifier { $$ = array($1, $3); }
name T_PAAMAYIM_NEKUDOTAYIM identifier_ex { $$ = array($1, $3); }
;
trait_method_reference:
trait_method_reference_fully_qualified { $$ = $1; }
| identifier { $$ = array(null, $1); }
| identifier_ex { $$ = array(null, $1); }
;
method_body:
@ -522,9 +540,13 @@ property_declaration_list:
| property_declaration_list ',' property_declaration { push($1, $3); }
;
property_decl_name:
T_VARIABLE { $$ = Node\VarLikeIdentifier[parseVar($1)]; }
;
property_declaration:
T_VARIABLE { $$ = Stmt\PropertyProperty[parseVar($1), null]; }
| T_VARIABLE '=' static_scalar { $$ = Stmt\PropertyProperty[parseVar($1), $3]; }
property_decl_name { $$ = Stmt\PropertyProperty[$1, null]; }
| property_decl_name '=' static_scalar { $$ = Stmt\PropertyProperty[$1, $3]; }
;
expr_list:
@ -557,6 +579,7 @@ expr:
| variable T_SL_EQUAL expr { $$ = Expr\AssignOp\ShiftLeft [$1, $3]; }
| variable T_SR_EQUAL expr { $$ = Expr\AssignOp\ShiftRight[$1, $3]; }
| variable T_POW_EQUAL expr { $$ = Expr\AssignOp\Pow [$1, $3]; }
| variable T_COALESCE_EQUAL expr { $$ = Expr\AssignOp\Coalesce [$1, $3]; }
| variable T_INC { $$ = Expr\PostInc[$1]; }
| T_INC variable { $$ = Expr\PreInc [$2]; }
| variable T_DEC { $$ = Expr\PostDec[$1]; }
@ -606,7 +629,10 @@ expr:
| T_REQUIRE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_REQUIRE]; }
| T_REQUIRE_ONCE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_REQUIRE_ONCE]; }
| T_INT_CAST expr { $$ = Expr\Cast\Int_ [$2]; }
| T_DOUBLE_CAST expr { $$ = Expr\Cast\Double [$2]; }
| T_DOUBLE_CAST expr
{ $attrs = attributes();
$attrs['kind'] = $this->getFloatCastKind($1);
$$ = new Expr\Cast\Double($2, $attrs); }
| T_STRING_CAST expr { $$ = Expr\Cast\String_ [$2]; }
| T_ARRAY_CAST expr { $$ = Expr\Cast\Array_ [$2]; }
| T_OBJECT_CAST expr { $$ = Expr\Cast\Object_ [$2]; }
@ -665,6 +691,7 @@ anonymous_class:
T_CLASS ctor_arguments extends_from implements_list '{' class_statement_list '}'
{ $$ = array(Stmt\Class_[null, ['type' => 0, 'extends' => $3, 'implements' => $4, 'stmts' => $6]], $2);
$this->checkClass($$[0], -1); }
;
new_expr:
T_NEW class_name_reference ctor_arguments { $$ = Expr\New_[$2, $3]; }
@ -683,30 +710,17 @@ lexical_var_list:
;
lexical_var:
optional_ref T_VARIABLE { $$ = Expr\ClosureUse[parseVar($2), $1]; }
optional_ref plain_variable { $$ = Expr\ClosureUse[$2, $1]; }
;
function_call:
name argument_list { $$ = Expr\FuncCall[$1, $2]; }
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier argument_list
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier_ex argument_list
{ $$ = Expr\StaticCall[$1, $3, $4]; }
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '{' expr '}' argument_list
{ $$ = Expr\StaticCall[$1, $4, $6]; }
| static_property argument_list {
if ($1 instanceof Node\Expr\StaticPropertyFetch) {
$$ = Expr\StaticCall[$1->class, Expr\Variable[$1->name], $2];
} elseif ($1 instanceof Node\Expr\ArrayDimFetch) {
$tmp = $1;
while ($tmp->var instanceof Node\Expr\ArrayDimFetch) {
$tmp = $tmp->var;
}
$$ = Expr\StaticCall[$tmp->var->class, $1, $2];
$tmp->var = Expr\Variable[$tmp->var->name];
} else {
throw new \Exception;
}
}
| static_property argument_list
{ $$ = $this->fixupPhp5StaticPropCall($1, $2, attributes()); }
| variable_without_objects argument_list
{ $$ = Expr\FuncCall[$1, $2]; }
| function_call '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
@ -781,16 +795,14 @@ common_scalar:
| T_FUNC_C { $$ = Scalar\MagicConst\Function_[]; }
| T_NS_C { $$ = Scalar\MagicConst\Namespace_[]; }
| T_START_HEREDOC T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC
{ $attrs = attributes(); setDocStringAttrs($attrs, $1);
$$ = new Scalar\String_(Scalar\String_::parseDocString($1, $2, false), $attrs); }
{ $$ = $this->parseDocString($1, $2, $3, attributes(), stackAttributes(#3), false); }
| T_START_HEREDOC T_END_HEREDOC
{ $attrs = attributes(); setDocStringAttrs($attrs, $1);
$$ = new Scalar\String_('', $attrs); }
{ $$ = $this->parseDocString($1, '', $2, attributes(), stackAttributes(#2), false); }
;
static_scalar:
common_scalar { $$ = $1; }
| class_name T_PAAMAYIM_NEKUDOTAYIM identifier { $$ = Expr\ClassConstFetch[$1, $3]; }
| class_name T_PAAMAYIM_NEKUDOTAYIM identifier_ex { $$ = Expr\ClassConstFetch[$1, $3]; }
| name { $$ = Expr\ConstFetch[$1]; }
| T_ARRAY '(' static_array_pair_list ')' { $$ = Expr\Array_[$3]; }
| '[' static_array_pair_list ']' { $$ = Expr\Array_[$2]; }
@ -835,7 +847,7 @@ static_operation:
constant:
name { $$ = Expr\ConstFetch[$1]; }
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier_ex
{ $$ = Expr\ClassConstFetch[$1, $3]; }
;
@ -846,8 +858,7 @@ scalar:
{ $attrs = attributes(); $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED;
parseEncapsed($2, '"', true); $$ = new Scalar\Encapsed($2, $attrs); }
| T_START_HEREDOC encaps_list T_END_HEREDOC
{ $attrs = attributes(); setDocStringAttrs($attrs, $1);
parseEncapsedDoc($2, true); $$ = new Scalar\Encapsed($2, $attrs); }
{ $$ = $this->parseDocString($1, $2, $3, attributes(), stackAttributes(#3), true); }
;
static_array_pair_list:
@ -914,9 +925,14 @@ static_property:
| static_property_with_arrays { $$ = $1; }
;
static_property_simple_name:
T_VARIABLE
{ $var = parseVar($1); $$ = \is_string($var) ? Node\VarLikeIdentifier[$var] : $var; }
;
static_property_with_arrays:
class_name_or_var T_PAAMAYIM_NEKUDOTAYIM T_VARIABLE
{ $$ = Expr\StaticPropertyFetch[$1, parseVar($3)]; }
class_name_or_var T_PAAMAYIM_NEKUDOTAYIM static_property_simple_name
{ $$ = Expr\StaticPropertyFetch[$1, $3]; }
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '$' '{' expr '}'
{ $$ = Expr\StaticPropertyFetch[$1, $5]; }
| static_property_with_arrays '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
@ -926,7 +942,7 @@ static_property_with_arrays:
reference_variable:
reference_variable '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
| reference_variable '{' expr '}' { $$ = Expr\ArrayDimFetch[$1, $3]; }
| T_VARIABLE { $$ = Expr\Variable[parseVar($1)]; }
| plain_variable { $$ = $1; }
| '$' '{' expr '}' { $$ = Expr\Variable[$3]; }
;
@ -936,7 +952,7 @@ dim_offset:
;
object_property:
T_STRING { $$ = $1; }
identifier { $$ = $1; }
| '{' expr '}' { $$ = $2; }
| variable_without_objects { $$ = $1; }
| error { $$ = Expr\Error[]; $this->errorState = 2; }
@ -972,6 +988,7 @@ array_pair:
| expr { $$ = Expr\ArrayItem[$1, null, false]; }
| expr T_DOUBLE_ARROW '&' variable { $$ = Expr\ArrayItem[$4, $1, true]; }
| '&' variable { $$ = Expr\ArrayItem[$2, null, true]; }
| T_ELLIPSIS expr { $$ = Expr\ArrayItem[$2, null, false, attributes(), true]; }
;
encaps_list:
@ -985,25 +1002,25 @@ encaps_string_part:
T_ENCAPSED_AND_WHITESPACE { $$ = Scalar\EncapsedStringPart[$1]; }
;
encaps_base_var:
T_VARIABLE { $$ = Expr\Variable[parseVar($1)]; }
encaps_str_varname:
T_STRING_VARNAME { $$ = Expr\Variable[$1]; }
;
encaps_var:
encaps_base_var { $$ = $1; }
| encaps_base_var '[' encaps_var_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
| encaps_base_var T_OBJECT_OPERATOR T_STRING { $$ = Expr\PropertyFetch[$1, $3]; }
plain_variable { $$ = $1; }
| plain_variable '[' encaps_var_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
| plain_variable T_OBJECT_OPERATOR identifier { $$ = Expr\PropertyFetch[$1, $3]; }
| T_DOLLAR_OPEN_CURLY_BRACES expr '}' { $$ = Expr\Variable[$2]; }
| T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '}' { $$ = Expr\Variable[$2]; }
| T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '[' expr ']' '}'
{ $$ = Expr\ArrayDimFetch[Expr\Variable[$2], $4]; }
| T_DOLLAR_OPEN_CURLY_BRACES encaps_str_varname '[' expr ']' '}'
{ $$ = Expr\ArrayDimFetch[$2, $4]; }
| T_CURLY_OPEN variable '}' { $$ = $2; }
;
encaps_var_offset:
T_STRING { $$ = Scalar\String_[$1]; }
| T_NUM_STRING { $$ = $this->parseNumString($1, attributes()); }
| T_VARIABLE { $$ = Expr\Variable[parseVar($1)]; }
| plain_variable { $$ = $1; }
;
%%

View file

@ -16,7 +16,7 @@ top_statement_list_ex:
top_statement_list:
top_statement_list_ex
{ makeNop($nop, $this->lookaheadStartAttributes);
{ makeZeroLengthNop($nop, $this->lookaheadStartAttributes);
if ($nop !== null) { $1[] = $nop; } $$ = $1; }
;
@ -27,7 +27,7 @@ reserved_non_modifiers:
| T_FINALLY | T_THROW | T_USE | T_INSTEADOF | T_GLOBAL | T_VAR | T_UNSET | T_ISSET | T_EMPTY | T_CONTINUE | T_GOTO
| T_FUNCTION | T_CONST | T_RETURN | T_PRINT | T_YIELD | T_LIST | T_SWITCH | T_ENDSWITCH | T_CASE | T_DEFAULT
| T_BREAK | T_ARRAY | T_CALLABLE | T_EXTENDS | T_IMPLEMENTS | T_NAMESPACE | T_TRAIT | T_INTERFACE | T_CLASS
| T_CLASS_C | T_TRAIT_C | T_FUNC_C | T_METHOD_C | T_LINE | T_FILE | T_DIR | T_NS_C | T_HALT_COMPILER
| T_CLASS_C | T_TRAIT_C | T_FUNC_C | T_METHOD_C | T_LINE | T_FILE | T_DIR | T_NS_C | T_HALT_COMPILER | T_FN
;
semi_reserved:
@ -35,9 +35,17 @@ semi_reserved:
| T_STATIC | T_ABSTRACT | T_FINAL | T_PRIVATE | T_PROTECTED | T_PUBLIC
;
identifier_ex:
T_STRING { $$ = Node\Identifier[$1]; }
| semi_reserved { $$ = Node\Identifier[$1]; }
;
identifier:
T_STRING { $$ = $1; }
| semi_reserved { $$ = $1; }
T_STRING { $$ = Node\Identifier[$1]; }
;
reserved_non_modifiers_identifier:
reserved_non_modifiers { $$ = Node\Identifier[$1]; }
;
namespace_name_parts:
@ -49,6 +57,10 @@ namespace_name:
namespace_name_parts { $$ = Name[$1]; }
;
plain_variable:
T_VARIABLE { $$ = Expr\Variable[parseVar($1)]; }
;
semi:
';' { /* nothing */ }
| error { /* nothing */ }
@ -136,7 +148,7 @@ non_empty_inline_use_declarations:
unprefixed_use_declaration:
namespace_name
{ $$ = Stmt\UseUse[$1, null, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #1); }
| namespace_name T_AS T_STRING
| namespace_name T_AS identifier
{ $$ = Stmt\UseUse[$1, $3, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #3); }
;
@ -161,7 +173,7 @@ non_empty_constant_declaration_list:
;
constant_declaration:
T_STRING '=' expr { $$ = Node\Const_[$1, $3]; }
identifier '=' expr { $$ = Node\Const_[$1, $3]; }
;
class_const_list:
@ -174,7 +186,7 @@ non_empty_class_const_list:
;
class_const:
identifier '=' expr { $$ = Node\Const_[$1, $3]; }
identifier_ex '=' expr { $$ = Node\Const_[$1, $3]; }
;
inner_statement_list_ex:
@ -184,7 +196,7 @@ inner_statement_list_ex:
inner_statement_list:
inner_statement_list_ex
{ makeNop($nop, $this->lookaheadStartAttributes);
{ makeZeroLengthNop($nop, $this->lookaheadStartAttributes);
if ($nop !== null) { $1[] = $nop; } $$ = $1; }
;
@ -202,7 +214,7 @@ non_empty_statement:
if ($2) {
$$ = $2; prependLeadingComments($$);
} else {
makeNop($$, $this->startAttributeStack[#1]);
makeNop($$, $this->startAttributeStack[#1], $this->endAttributes);
if (null === $$) { $$ = array(); }
}
}
@ -222,25 +234,27 @@ non_empty_statement:
| T_STATIC static_var_list semi { $$ = Stmt\Static_[$2]; }
| T_ECHO expr_list semi { $$ = Stmt\Echo_[$2]; }
| T_INLINE_HTML { $$ = Stmt\InlineHTML[$1]; }
| expr semi { $$ = $1; }
| expr semi { $$ = Stmt\Expression[$1]; }
| T_UNSET '(' variables_list ')' semi { $$ = Stmt\Unset_[$3]; }
| T_FOREACH '(' expr T_AS foreach_variable ')' foreach_statement
{ $$ = Stmt\Foreach_[$3, $5[0], ['keyVar' => null, 'byRef' => $5[1], 'stmts' => $7]]; }
| T_FOREACH '(' expr T_AS variable T_DOUBLE_ARROW foreach_variable ')' foreach_statement
{ $$ = Stmt\Foreach_[$3, $7[0], ['keyVar' => $5, 'byRef' => $7[1], 'stmts' => $9]]; }
| T_FOREACH '(' expr error ')' foreach_statement
{ $$ = Stmt\Foreach_[$3, new Expr\Error(stackAttributes(#4)), ['stmts' => $6]]; }
| T_DECLARE '(' declare_list ')' declare_statement { $$ = Stmt\Declare_[$3, $5]; }
| T_TRY '{' inner_statement_list '}' catches optional_finally
{ $$ = Stmt\TryCatch[$3, $5, $6]; $this->checkTryCatch($$); }
| T_THROW expr semi { $$ = Stmt\Throw_[$2]; }
| T_GOTO T_STRING semi { $$ = Stmt\Goto_[$2]; }
| T_STRING ':' { $$ = Stmt\Label[$1]; }
| T_GOTO identifier semi { $$ = Stmt\Goto_[$2]; }
| identifier ':' { $$ = Stmt\Label[$1]; }
| error { $$ = array(); /* means: no statement */ }
;
statement:
non_empty_statement { $$ = $1; }
| ';'
{ makeNop($$, $this->startAttributeStack[#1]);
{ makeNop($$, $this->startAttributeStack[#1], $this->endAttributes);
if ($$ === null) $$ = array(); /* means: no statement */ }
;
@ -255,8 +269,8 @@ name_union:
;
catch:
T_CATCH '(' name_union T_VARIABLE ')' '{' inner_statement_list '}'
{ $$ = Stmt\Catch_[$3, parseVar($4), $7]; }
T_CATCH '(' name_union plain_variable ')' '{' inner_statement_list '}'
{ $$ = Stmt\Catch_[$3, $4, $7]; }
;
optional_finally:
@ -265,7 +279,7 @@ optional_finally:
;
variables_list:
non_empty_variables_list no_comma { $$ = $1; }
non_empty_variables_list optional_comma { $$ = $1; }
;
non_empty_variables_list:
@ -283,19 +297,24 @@ optional_ellipsis:
| T_ELLIPSIS { $$ = true; }
;
block_or_error:
'{' inner_statement_list '}' { $$ = $2; }
| error { $$ = []; }
;
function_declaration_statement:
T_FUNCTION optional_ref T_STRING '(' parameter_list ')' optional_return_type '{' inner_statement_list '}'
{ $$ = Stmt\Function_[$3, ['byRef' => $2, 'params' => $5, 'returnType' => $7, 'stmts' => $9]]; }
T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type block_or_error
{ $$ = Stmt\Function_[$3, ['byRef' => $2, 'params' => $5, 'returnType' => $7, 'stmts' => $8]]; }
;
class_declaration_statement:
class_entry_type T_STRING extends_from implements_list '{' class_statement_list '}'
class_entry_type identifier extends_from implements_list '{' class_statement_list '}'
{ $$ = Stmt\Class_[$2, ['type' => $1, 'extends' => $3, 'implements' => $4, 'stmts' => $6]];
$this->checkClass($$, #2); }
| T_INTERFACE T_STRING interface_extends_list '{' class_statement_list '}'
| T_INTERFACE identifier interface_extends_list '{' class_statement_list '}'
{ $$ = Stmt\Interface_[$2, ['extends' => $3, 'stmts' => $5]];
$this->checkInterface($$, #2); }
| T_TRAIT T_STRING '{' class_statement_list '}'
| T_TRAIT identifier '{' class_statement_list '}'
{ $$ = Stmt\Trait_[$2, ['stmts' => $4]]; }
;
@ -355,7 +374,7 @@ non_empty_declare_list:
;
declare_list_element:
T_STRING '=' expr { $$ = Stmt\DeclareDeclare[$1, $3]; }
identifier '=' expr { $$ = Stmt\DeclareDeclare[$1, $3]; }
;
switch_case_list:
@ -431,24 +450,32 @@ non_empty_parameter_list:
;
parameter:
optional_param_type optional_ref optional_ellipsis T_VARIABLE
{ $$ = Node\Param[parseVar($4), null, $1, $2, $3]; $this->checkParam($$); }
| optional_param_type optional_ref optional_ellipsis T_VARIABLE '=' expr
{ $$ = Node\Param[parseVar($4), $6, $1, $2, $3]; $this->checkParam($$); }
optional_type optional_ref optional_ellipsis plain_variable
{ $$ = Node\Param[$4, null, $1, $2, $3]; $this->checkParam($$); }
| optional_type optional_ref optional_ellipsis plain_variable '=' expr
{ $$ = Node\Param[$4, $6, $1, $2, $3]; $this->checkParam($$); }
| optional_type optional_ref optional_ellipsis error
{ $$ = Node\Param[Expr\Error[], null, $1, $2, $3]; }
;
type_expr:
type { $$ = $1; }
| '?' type { $$ = Node\NullableType[$2]; }
| union_type { $$ = Node\UnionType[$1]; }
;
type:
name { $$ = $this->handleBuiltinTypes($1); }
| T_ARRAY { $$ = 'array'; }
| T_CALLABLE { $$ = 'callable'; }
| T_ARRAY { $$ = Node\Identifier['array']; }
| T_CALLABLE { $$ = Node\Identifier['callable']; }
;
optional_param_type:
union_type:
type '|' type { init($1, $3); }
| union_type '|' type { push($1, $3); }
;
optional_type:
/* empty */ { $$ = null; }
| type_expr { $$ = $1; }
;
@ -456,11 +483,12 @@ optional_param_type:
optional_return_type:
/* empty */ { $$ = null; }
| ':' type_expr { $$ = $2; }
| ':' error { $$ = null; }
;
argument_list:
'(' ')' { $$ = array(); }
| '(' non_empty_argument_list no_comma ')' { $$ = $2; }
| '(' non_empty_argument_list optional_comma ')' { $$ = $2; }
;
non_empty_argument_list:
@ -497,24 +525,32 @@ non_empty_static_var_list:
;
static_var:
T_VARIABLE { $$ = Stmt\StaticVar[parseVar($1), null]; }
| T_VARIABLE '=' expr { $$ = Stmt\StaticVar[parseVar($1), $3]; }
plain_variable { $$ = Stmt\StaticVar[$1, null]; }
| plain_variable '=' expr { $$ = Stmt\StaticVar[$1, $3]; }
;
class_statement_list:
class_statement_list class_statement { push($1, $2); }
class_statement_list_ex:
class_statement_list_ex class_statement { if ($2 !== null) { push($1, $2); } }
| /* empty */ { init(); }
;
class_statement_list:
class_statement_list_ex
{ makeZeroLengthNop($nop, $this->lookaheadStartAttributes);
if ($nop !== null) { $1[] = $nop; } $$ = $1; }
;
class_statement:
variable_modifiers property_declaration_list ';'
{ $$ = Stmt\Property[$1, $2]; $this->checkProperty($$, #1); }
variable_modifiers optional_type property_declaration_list ';'
{ $attrs = attributes();
$$ = new Stmt\Property($1, $3, $attrs, $2); $this->checkProperty($$, #1); }
| method_modifiers T_CONST class_const_list ';'
{ $$ = Stmt\ClassConst[$3, $1]; $this->checkClassConst($$, #1); }
| method_modifiers T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type method_body
| method_modifiers T_FUNCTION optional_ref identifier_ex '(' parameter_list ')' optional_return_type method_body
{ $$ = Stmt\ClassMethod[$4, ['type' => $1, 'byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9]];
$this->checkClassMethod($$, #1); }
| T_USE class_name_list trait_adaptations { $$ = Stmt\TraitUse[$2, $3]; }
| error { $$ = null; /* will be skipped */ }
;
trait_adaptations:
@ -530,27 +566,27 @@ trait_adaptation_list:
trait_adaptation:
trait_method_reference_fully_qualified T_INSTEADOF class_name_list ';'
{ $$ = Stmt\TraitUseAdaptation\Precedence[$1[0], $1[1], $3]; }
| trait_method_reference T_AS member_modifier identifier ';'
| trait_method_reference T_AS member_modifier identifier_ex ';'
{ $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], $3, $4]; }
| trait_method_reference T_AS member_modifier ';'
{ $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], $3, null]; }
| trait_method_reference T_AS T_STRING ';'
| trait_method_reference T_AS identifier ';'
{ $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], null, $3]; }
| trait_method_reference T_AS reserved_non_modifiers ';'
| trait_method_reference T_AS reserved_non_modifiers_identifier ';'
{ $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], null, $3]; }
;
trait_method_reference_fully_qualified:
name T_PAAMAYIM_NEKUDOTAYIM identifier { $$ = array($1, $3); }
name T_PAAMAYIM_NEKUDOTAYIM identifier_ex { $$ = array($1, $3); }
;
trait_method_reference:
trait_method_reference_fully_qualified { $$ = $1; }
| identifier { $$ = array(null, $1); }
| identifier_ex { $$ = array(null, $1); }
;
method_body:
';' /* abstract method */ { $$ = null; }
| '{' inner_statement_list '}' { $$ = $2; }
| block_or_error { $$ = $1; }
;
variable_modifiers:
@ -587,9 +623,13 @@ non_empty_property_declaration_list:
{ push($1, $3); }
;
property_decl_name:
T_VARIABLE { $$ = Node\VarLikeIdentifier[parseVar($1)]; }
;
property_declaration:
T_VARIABLE { $$ = Stmt\PropertyProperty[parseVar($1), null]; }
| T_VARIABLE '=' expr { $$ = Stmt\PropertyProperty[parseVar($1), $3]; }
property_decl_name { $$ = Stmt\PropertyProperty[$1, null]; }
| property_decl_name '=' expr { $$ = Stmt\PropertyProperty[$1, $3]; }
;
expr_list:
@ -626,6 +666,7 @@ expr:
| variable T_SL_EQUAL expr { $$ = Expr\AssignOp\ShiftLeft [$1, $3]; }
| variable T_SR_EQUAL expr { $$ = Expr\AssignOp\ShiftRight[$1, $3]; }
| variable T_POW_EQUAL expr { $$ = Expr\AssignOp\Pow [$1, $3]; }
| variable T_COALESCE_EQUAL expr { $$ = Expr\AssignOp\Coalesce [$1, $3]; }
| variable T_INC { $$ = Expr\PostInc[$1]; }
| T_INC variable { $$ = Expr\PreInc [$2]; }
| variable T_DEC { $$ = Expr\PostDec[$1]; }
@ -673,7 +714,10 @@ expr:
| T_REQUIRE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_REQUIRE]; }
| T_REQUIRE_ONCE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_REQUIRE_ONCE]; }
| T_INT_CAST expr { $$ = Expr\Cast\Int_ [$2]; }
| T_DOUBLE_CAST expr { $$ = Expr\Cast\Double [$2]; }
| T_DOUBLE_CAST expr
{ $attrs = attributes();
$attrs['kind'] = $this->getFloatCastKind($1);
$$ = new Expr\Cast\Double($2, $attrs); }
| T_STRING_CAST expr { $$ = Expr\Cast\String_ [$2]; }
| T_ARRAY_CAST expr { $$ = Expr\Cast\Array_ [$2]; }
| T_OBJECT_CAST expr { $$ = Expr\Cast\Object_ [$2]; }
@ -691,18 +735,25 @@ expr:
| T_YIELD expr { $$ = Expr\Yield_[$2, null]; }
| T_YIELD expr T_DOUBLE_ARROW expr { $$ = Expr\Yield_[$4, $2]; }
| T_YIELD_FROM expr { $$ = Expr\YieldFrom[$2]; }
| T_FN optional_ref '(' parameter_list ')' optional_return_type T_DOUBLE_ARROW expr
{ $$ = Expr\ArrowFunction[['static' => false, 'byRef' => $2, 'params' => $4, 'returnType' => $6, 'expr' => $8]]; }
| T_STATIC T_FN optional_ref '(' parameter_list ')' optional_return_type T_DOUBLE_ARROW expr
{ $$ = Expr\ArrowFunction[['static' => true, 'byRef' => $3, 'params' => $5, 'returnType' => $7, 'expr' => $9]]; }
| T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type
'{' inner_statement_list '}'
{ $$ = Expr\Closure[['static' => false, 'byRef' => $2, 'params' => $4, 'uses' => $6, 'returnType' => $7, 'stmts' => $9]]; }
block_or_error
{ $$ = Expr\Closure[['static' => false, 'byRef' => $2, 'params' => $4, 'uses' => $6, 'returnType' => $7, 'stmts' => $8]]; }
| T_STATIC T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type
'{' inner_statement_list '}'
{ $$ = Expr\Closure[['static' => true, 'byRef' => $3, 'params' => $5, 'uses' => $7, 'returnType' => $8, 'stmts' => $10]]; }
block_or_error
{ $$ = Expr\Closure[['static' => true, 'byRef' => $3, 'params' => $5, 'uses' => $7, 'returnType' => $8, 'stmts' => $9]]; }
;
anonymous_class:
T_CLASS ctor_arguments extends_from implements_list '{' class_statement_list '}'
{ $$ = array(Stmt\Class_[null, ['type' => 0, 'extends' => $3, 'implements' => $4, 'stmts' => $6]], $2);
$this->checkClass($$[0], -1); }
;
new_expr:
T_NEW class_name_reference ctor_arguments { $$ = Expr\New_[$2, $3]; }
@ -725,7 +776,7 @@ non_empty_lexical_var_list:
;
lexical_var:
optional_ref T_VARIABLE { $$ = Expr\ClosureUse[parseVar($2), $1]; }
optional_ref plain_variable { $$ = Expr\ClosureUse[$2, $1]; }
;
function_call:
@ -776,7 +827,7 @@ ctor_arguments:
constant:
name { $$ = Expr\ConstFetch[$1]; }
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier_ex
{ $$ = Expr\ClassConstFetch[$1, $3]; }
/* We interpret and isolated FOO:: as an unfinished class constant fetch. It could also be
an unfinished static property fetch or unfinished scoped call. */
@ -814,17 +865,14 @@ scalar:
| dereferencable_scalar { $$ = $1; }
| constant { $$ = $1; }
| T_START_HEREDOC T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC
{ $attrs = attributes(); setDocStringAttrs($attrs, $1);
$$ = new Scalar\String_(Scalar\String_::parseDocString($1, $2), $attrs); }
{ $$ = $this->parseDocString($1, $2, $3, attributes(), stackAttributes(#3), true); }
| T_START_HEREDOC T_END_HEREDOC
{ $attrs = attributes(); setDocStringAttrs($attrs, $1);
$$ = new Scalar\String_('', $attrs); }
{ $$ = $this->parseDocString($1, '', $2, attributes(), stackAttributes(#2), true); }
| '"' encaps_list '"'
{ $attrs = attributes(); $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED;
parseEncapsed($2, '"', true); $$ = new Scalar\Encapsed($2, $attrs); }
| T_START_HEREDOC encaps_list T_END_HEREDOC
{ $attrs = attributes(); setDocStringAttrs($attrs, $1);
parseEncapsedDoc($2, true); $$ = new Scalar\Encapsed($2, $attrs); }
{ $$ = $this->parseDocString($1, $2, $3, attributes(), stackAttributes(#3), true); }
;
optional_expr:
@ -867,8 +915,13 @@ simple_variable:
| '$' error { $$ = Expr\Error[]; $this->errorState = 2; }
;
static_member_prop_name:
simple_variable
{ $var = $1; $$ = \is_string($var) ? Node\VarLikeIdentifier[$var] : $var; }
;
static_member:
class_name_or_var T_PAAMAYIM_NEKUDOTAYIM simple_variable
class_name_or_var T_PAAMAYIM_NEKUDOTAYIM static_member_prop_name
{ $$ = Expr\StaticPropertyFetch[$1, $3]; }
;
@ -877,18 +930,20 @@ new_variable:
| new_variable '[' optional_expr ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
| new_variable '{' expr '}' { $$ = Expr\ArrayDimFetch[$1, $3]; }
| new_variable T_OBJECT_OPERATOR property_name { $$ = Expr\PropertyFetch[$1, $3]; }
| class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable { $$ = Expr\StaticPropertyFetch[$1, $3]; }
| new_variable T_PAAMAYIM_NEKUDOTAYIM simple_variable { $$ = Expr\StaticPropertyFetch[$1, $3]; }
| class_name T_PAAMAYIM_NEKUDOTAYIM static_member_prop_name
{ $$ = Expr\StaticPropertyFetch[$1, $3]; }
| new_variable T_PAAMAYIM_NEKUDOTAYIM static_member_prop_name
{ $$ = Expr\StaticPropertyFetch[$1, $3]; }
;
member_name:
identifier { $$ = $1; }
identifier_ex { $$ = $1; }
| '{' expr '}' { $$ = $2; }
| simple_variable { $$ = Expr\Variable[$1]; }
;
property_name:
T_STRING { $$ = $1; }
identifier { $$ = $1; }
| '{' expr '}' { $$ = $2; }
| simple_variable { $$ = Expr\Variable[$1]; }
| error { $$ = Expr\Error[]; $this->errorState = 2; }
@ -905,19 +960,27 @@ list_expr_elements:
list_expr_element:
variable { $$ = Expr\ArrayItem[$1, null, false]; }
| '&' variable { $$ = Expr\ArrayItem[$2, null, true]; }
| list_expr { $$ = Expr\ArrayItem[$1, null, false]; }
| expr T_DOUBLE_ARROW variable { $$ = Expr\ArrayItem[$3, $1, false]; }
| expr T_DOUBLE_ARROW '&' variable { $$ = Expr\ArrayItem[$4, $1, true]; }
| expr T_DOUBLE_ARROW list_expr { $$ = Expr\ArrayItem[$3, $1, false]; }
| /* empty */ { $$ = null; }
;
array_pair_list:
inner_array_pair_list
{ $$ = $1; $end = count($$)-1; if ($$[$end] === null) unset($$[$end]); }
{ $$ = $1; $end = count($$)-1; if ($$[$end] === null) array_pop($$); }
;
comma_or_error:
','
| error
{ /* do nothing -- prevent default action of $$=$1. See #551. */ }
;
inner_array_pair_list:
inner_array_pair_list ',' array_pair { push($1, $3); }
inner_array_pair_list comma_or_error array_pair { push($1, $3); }
| array_pair { init($1); }
;
@ -926,6 +989,7 @@ array_pair:
| expr { $$ = Expr\ArrayItem[$1, null, false]; }
| expr T_DOUBLE_ARROW '&' variable { $$ = Expr\ArrayItem[$4, $1, true]; }
| '&' variable { $$ = Expr\ArrayItem[$2, null, true]; }
| T_ELLIPSIS expr { $$ = Expr\ArrayItem[$2, null, false, attributes(), true]; }
| /* empty */ { $$ = null; }
;
@ -940,18 +1004,18 @@ encaps_string_part:
T_ENCAPSED_AND_WHITESPACE { $$ = Scalar\EncapsedStringPart[$1]; }
;
encaps_base_var:
T_VARIABLE { $$ = Expr\Variable[parseVar($1)]; }
encaps_str_varname:
T_STRING_VARNAME { $$ = Expr\Variable[$1]; }
;
encaps_var:
encaps_base_var { $$ = $1; }
| encaps_base_var '[' encaps_var_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
| encaps_base_var T_OBJECT_OPERATOR T_STRING { $$ = Expr\PropertyFetch[$1, $3]; }
plain_variable { $$ = $1; }
| plain_variable '[' encaps_var_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
| plain_variable T_OBJECT_OPERATOR identifier { $$ = Expr\PropertyFetch[$1, $3]; }
| T_DOLLAR_OPEN_CURLY_BRACES expr '}' { $$ = Expr\Variable[$2]; }
| T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '}' { $$ = Expr\Variable[$2]; }
| T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '[' expr ']' '}'
{ $$ = Expr\ArrayDimFetch[Expr\Variable[$2], $4]; }
| T_DOLLAR_OPEN_CURLY_BRACES encaps_str_varname '[' expr ']' '}'
{ $$ = Expr\ArrayDimFetch[$2, $4]; }
| T_CURLY_OPEN variable '}' { $$ = $2; }
;
@ -959,7 +1023,7 @@ encaps_var_offset:
T_STRING { $$ = Scalar\String_[$1]; }
| T_NUM_STRING { $$ = $this->parseNumString($1, attributes()); }
| '-' T_NUM_STRING { $$ = $this->parseNumString('-' . $2, attributes()); }
| T_VARIABLE { $$ = Expr\Variable[parseVar($1)]; }
| plain_variable { $$ = $1; }
;
%%

View file

@ -13,10 +13,10 @@ $tmpResultFile = __DIR__ . '/tmp_parser.php';
$resultDir = __DIR__ . '/../lib/PhpParser/Parser';
$tokensResultsFile = $resultDir . '/Tokens.php';
// check for kmyacc.exe binary in this directory, otherwise fall back to global name
$kmyacc = __DIR__ . '/kmyacc.exe';
if (!file_exists($kmyacc)) {
$kmyacc = 'kmyacc';
$kmyacc = getenv('KMYACC');
if (!$kmyacc) {
// Use phpyacc from dev dependencies by default.
$kmyacc = PHP_BINARY . ' ' . __DIR__ . '/../vendor/bin/phpyacc';
}
$options = array_flip($argv);
@ -59,8 +59,7 @@ foreach ($grammarFileToName as $grammarFile => $name) {
$additionalArgs = $optionDebug ? '-t -v' : '';
echo "Building $name parser.\n";
$output = trim(shell_exec("$kmyacc $additionalArgs -l -m $skeletonFile -p $name $tmpGrammarFile 2>&1"));
echo "Output: \"$output\"\n";
$output = execCmd("$kmyacc $additionalArgs -m $skeletonFile -p $name $tmpGrammarFile");
$resultCode = file_get_contents($tmpResultFile);
$resultCode = removeTrailingWhitespace($resultCode);
@ -70,8 +69,7 @@ foreach ($grammarFileToName as $grammarFile => $name) {
unlink($tmpResultFile);
echo "Building token definition.\n";
$output = trim(shell_exec("$kmyacc -l -m $tokensTemplate $tmpGrammarFile 2>&1"));
assert($output === '');
$output = execCmd("$kmyacc -m $tokensTemplate $tmpGrammarFile");
rename($tmpResultFile, $tokensResultsFile);
if (!$optionKeepTmpGrammar) {
@ -166,24 +164,24 @@ function resolveMacros($code) {
. ' $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, ' . $args[1] . ', ' . $args[2] . '); } }';
}
if ('parseEncapsedDoc' == $name) {
assertArgs(2, $args, $name);
return 'foreach (' . $args[0] . ' as $s) { if ($s instanceof Node\Scalar\EncapsedStringPart) {'
. ' $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, null, ' . $args[1] . '); } }'
. ' $s->value = preg_replace(\'~(\r\n|\n|\r)\z~\', \'\', $s->value);'
. ' if (\'\' === $s->value) array_pop(' . $args[0] . ');';
}
if ('makeNop' == $name) {
assertArgs(2, $args, $name);
assertArgs(3, $args, $name);
return '$startAttributes = ' . $args[1] . ';'
. ' if (isset($startAttributes[\'comments\']))'
. ' { ' . $args[0] . ' = new Stmt\Nop([\'comments\' => $startAttributes[\'comments\']]); }'
. ' { ' . $args[0] . ' = new Stmt\Nop($startAttributes + ' . $args[2] . '); }'
. ' else { ' . $args[0] . ' = null; }';
}
if ('makeZeroLengthNop' == $name) {
assertArgs(2, $args, $name);
return '$startAttributes = ' . $args[1] . ';'
. ' if (isset($startAttributes[\'comments\']))'
. ' { ' . $args[0] . ' = new Stmt\Nop($this->createZeroLengthAttributes($startAttributes)); }'
. ' else { ' . $args[0] . ' = null; }';
}
if ('strKind' == $name) {
assertArgs(1, $args, $name);
@ -192,15 +190,6 @@ function resolveMacros($code) {
. '? Scalar\String_::KIND_SINGLE_QUOTED : Scalar\String_::KIND_DOUBLE_QUOTED)';
}
if ('setDocStringAttrs' == $name) {
assertArgs(2, $args, $name);
return $args[0] . '[\'kind\'] = strpos(' . $args[1] . ', "\'") === false '
. '? Scalar\String_::KIND_HEREDOC : Scalar\String_::KIND_NOWDOC; '
. 'preg_match(\'/\A[bB]?<<<[ \t]*[\\\'"]?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)[\\\'"]?(?:\r\n|\n|\r)\z/\', ' . $args[1] . ', $matches); '
. $args[0] . '[\'docLabel\'] = $matches[1];';
}
if ('prependLeadingComments' == $name) {
assertArgs(1, $args, $name);
@ -240,6 +229,15 @@ function ensureDirExists($dir) {
}
}
function execCmd($cmd) {
$output = trim(shell_exec("$cmd 2>&1"));
if ($output !== "") {
echo "> " . $cmd . "\n";
echo $output;
}
return $output;
}
//////////////////////////////
/// Regex helper functions ///
//////////////////////////////

View file

@ -10,7 +10,7 @@
%right T_YIELD
%right T_DOUBLE_ARROW
%right T_YIELD_FROM
%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 T_POW_EQUAL
%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 T_POW_EQUAL T_COALESCE_EQUAL
%left '?' ':'
%right T_COALESCE
%left T_BOOLEAN_OR
@ -64,6 +64,7 @@
%token T_CONTINUE
%token T_GOTO
%token T_FUNCTION
%token T_FN
%token T_CONST
%token T_RETURN
%token T_TRY