* Don't assign to attribute stack on reduce - why was that there
in the first place?
* Assign attributes to the position in the stack where the first
token of the production is, instead of one position earlier.
* Add a comment to clarify why we also assign attributes on read,
instead of just on shift.
Minor performance improvement for parsing, also allows to access
attributes with higher granulity in the parser, though this is not
currently done.
* #n can now be used to access the stack position of a token. $n
is the same as $this->semStack[#n]. (Post-translate $n will
actually be the stack position.)
* $attributeStack is now $this->startAttributeStack and
$endAttributes is now $this->endAttributes.
* Attributes for a node are now computed inside the individual
reduction methods, instead of being passed as a parameter.
Accessible through the attributes() macro.
This fixes the case where the old name is used before the new one
is ever used, e.g. when manually constructing nodes, as opposed to
parsing them.
The previous approach would try to register the alias from OLD to
NEW. This would trigger autoloading on NEW and afterwards it would
register the alias from OLD to NEW. Afterwards the alias registration
which originally triggered the autoload would run, thus redeclaring
the class.
TL;DR aliases suck, closes#192.
Were this library to be fully annotated with scalar types and
return types where possible and were strict types to be enabled
for all files, the test suite would now pass.
Running a .phar or regular PHP executable that requires and includes its own
version of php-parser will cause a "cannot redeclare class" error if said
executable also includes the autoloader of the current working directory.
This adds an additional "returnType" subnode to Stmt\Function_,
Stmt\ClassMethod and Expr\Closure, as well as the corresponding
support in the name resolver and pretty printer.
Instead of storing subnodes in a subNodes dictionary, they are
now stored as simple properties. This requires declarating the
properties, assigning them in the constructor, overriding
the getSubNodeNames() method and passing NULL to the first argument
of the NodeAbstract constructor.
[Deprecated: It's still possible to use the old mode of operation
for custom nodes by passing an array of subnodes to the constructor.]
The only behavior difference this should cause is that getSubNodeNames()
will always return the original subnode names and skip any additional
properties that were dynamically added. E.g. this means that the
"namespacedName" node added by the NameResolver visitor is not treated
as a subnode, but as a dynamic property instead.
This change improves performance and memory usage.
While array (with name components) could technically be allowed (as
they are supported by the Name node itself), more likely than not
an array would due to incorrect usage of the API (e.g. array instead
of variadics).
Also change endFilePos semantics to refer to the last character that
is *included* in the token, rather than one past the last character.
This ensures that all end* attributes have the same semantics.
The lexer can now optionally add startFilePos and endFilePos
attributes, which are offsets in to the lexed code string.
The end offset currently points one past the last character of
the token - this is pending further discussion.
The attributes are not added by default and have to be enabled
using the new 'usedAttributes' lexer option:
$lexer = new Lexer([
'usedAttributes' => [
'comments', 'startLine', 'endLine',
'startFilePos', 'endFilePos'
]
]);
And improve the code a tad bit in general.
I left YY2TBLSTATES and YYNLSTATES around, because I don't fully
understand their role in the action double indexing.