Compare commits

...

17 Commits

Author SHA1 Message Date
a8ffc6fcfc Release PHP-Parser 1.0.2 2014-11-04 23:12:46 +01:00
7fbdb79a08 Fix whitespace when printing trait alias modifiers 2014-11-03 16:16:15 +01:00
6fad8ff32a Make NameResolver resolve trait alias and precedence names 2014-11-03 16:06:43 +01:00
b9a60372f2 Release version 1.0.1 2014-10-14 21:40:07 +02:00
eb20e32914 Update changelog 2014-10-14 21:37:04 +02:00
f41a4c9acb Fix wrong function name in docs 2014-10-14 21:31:29 +02:00
767f23c3a9 Update lexer docs
Remove some very questionable examples for changing startLexing()
to accept a file name.

Add token offset lexer implementation and usage example.
2014-10-11 21:47:11 +02:00
f8678ad7e9 Merge pull request #138 from jbrooksuk/patch-1
Fixed a spelling mistake
2014-10-01 12:18:18 +02:00
63c18b29e4 Fixed a spelling mistake 2014-10-01 09:18:01 +01:00
99df8b86ae Support HHVM T_ONUMBER token 2014-09-30 20:55:58 +02:00
66fd29cb58 Use stricter assertions where possible 2014-09-30 20:38:09 +02:00
3d40e2217d Annotate some APIs as @internal 2014-09-30 20:26:06 +02:00
16dff7c2e6 Add ability to pass code directly to php-parse.php 2014-09-28 13:14:37 +02:00
88e2d42ba4 Fix var_dump truncation with xdebug in php-parse.php 2014-09-28 13:08:59 +02:00
69701430c1 Cover remaining constant scalar expressions 2014-09-28 13:05:23 +02:00
6dc24fa9f5 Fix coverage annotations 2014-09-28 12:49:12 +02:00
3e1665bbbd Disallow new without a class name
Fixes #137.
2014-09-28 12:41:35 +02:00
32 changed files with 681 additions and 461 deletions

View File

@ -1,8 +1,26 @@
Version 1.0.1-dev
Version 1.0.3-dev
-----------------
Nothing yet.
Version 1.0.2 (04.11.2014)
--------------------------
* The `NameResolver` visitor now also resolves names in trait adaptations (aliases and precedence declarations).
* Remove stray whitespace when pretty-printing trait adaptations that only change visibility.
Version 1.0.1 (14.10.2014)
--------------------------
* Disallow `new` expressions without a class name. Previously `new;` was accidentally considered to be valid code.
* Support T_ONUMBER token used by HHVM.
* Add ability to directly pass code to the `php-parse.php` script.
* Prevent truncation of `var_dump()` output in the `php-parse.php` script if XDebug is used.
Version 1.0.0 (12.09.2014)
--------------------------

View File

@ -4,9 +4,10 @@ require __DIR__ . '/../lib/bootstrap.php';
ini_set('xdebug.max_nesting_level', 2000);
/* The fancy var_dump function provided by XDebug will cut off the output way too
* early to be of use. */
ini_set('xdebug.overload_var_dump', 0);
// Disable XDebug var_dump() output truncation
ini_set('xdebug.var_display_max_children', -1);
ini_set('xdebug.var_display_max_data', -1);
ini_set('xdebug.var_display_max_depth', -1);
list($operations, $files) = parseArgs($argv);
@ -28,13 +29,18 @@ $traverser = new PhpParser\NodeTraverser();
$traverser->addVisitor(new PhpParser\NodeVisitor\NameResolver);
foreach ($files as $file) {
if (!file_exists($file)) {
die("File $file does not exist.\n");
if (strpos($file, '<?php') === 0) {
$code = $file;
echo "====> Code $code\n";
} else {
if (!file_exists($file)) {
die("File $file does not exist.\n");
}
$code = file_get_contents($file);
echo "====> File $file:\n";
}
echo "====> File $file:\n";
$code = file_get_contents($file);
try {
$stmts = $parser->parse($code);
} catch (PhpParser\Error $e) {
@ -68,6 +74,10 @@ Usage:
php php-parse.php [operations] file1.php [file2.php ...]
The file arguments can also be replaced with a code string:
php php-parse.php [operations] "<?php code"
Operations is a list of the following options (--dump by default):
--dump -d Dump nodes using NodeDumper

View File

@ -31,7 +31,7 @@ upwards (and maybe older).
As the parser is based on the tokens returned by `token_get_all` (which is only able to lex the PHP
version it runs on), additionally a wrapper for emulating new tokens from 5.3, 5.4, 5.5 and 5.6 is provided.
his allows to parse PHP 5.6 source code running on PHP 5.3, for example. This emulation is very hacky and not
This allows to parse PHP 5.6 source code running on PHP 5.3, for example. This emulation is very hacky and not
perfect, but it should work well on any sane code.
What output does it produce?

View File

@ -10,7 +10,7 @@ Create a `composer.json` file in your project root and use it to define your dep
{
"require": {
"nikic/php-parser": "~1.0.0"
"nikic/php-parser": "~1.0.2"
}
}

View File

@ -7,45 +7,22 @@ newer PHP versions and thus allows parsing of new code on older versions.
A lexer has to define the following public interface:
startLexing($code);
getNextToken(&$value = null, &$startAttributes = null, &$endAttributes = null);
handleHaltCompiler();
void startLexing(string $code);
string handleHaltCompiler();
int getNextToken(string &$value = null, array &$startAttributes = null, array &$endAttributes = null);
startLexing
-----------
The `startLexing()` method is invoked with the source code that is to be lexed (including the opening tag) whenever the
`parse()` method of the parser is called. It can be used to reset state or preprocess the source code or tokens.
The `startLexing` method is invoked when the `parse()` method of the parser is called. It's argument will be whatever
was passed to the `parse()` method.
The `handleHaltCompiler()` method is called whenever a `T_HALT_COMPILER` token is encountered. It has to return the
remaining string after the construct (not including `();`).
Even though `startLexing` is meant to accept a source code string, you could for example overwrite it to accept a file:
The `getNextToken()` method returns the ID of the next token (as defined by the `Parser::T_*` constants). If no more
tokens are available it must return `0`, which is the ID of the `EOF` token. Furthermore the string content of the
token should be written into the by-reference `$value` parameter (which will then be available as `$n` in the parser).
```php
<?php
class FileLexer extends PhpParser\Lexer {
public function startLexing($fileName) {
if (!file_exists($fileName)) {
throw new InvalidArgumentException(sprintf('File "%s" does not exist', $fileName));
}
parent::startLexing(file_get_contents($fileName));
}
}
$parser = new PhpParser\Parser(new FileLexer);
var_dump($parser->parse('someFile.php'));
var_dump($parser->parse('someOtherFile.php'));
```
getNextToken
------------
`getNextToken` returns the ID of the next token and sets some additional information in the three variables which it
accepts by-ref. If no more tokens are available it must return `0`, which is the ID of the `EOF` token.
The first by-ref variable `$value` should contain the textual content of the token. It is what will be available as `$1`
etc in the parser.
Attribute handling
------------------
The other two by-ref variables `$startAttributes` and `$endAttributes` define which attributes will eventually be
assigned to the generated nodes: The parser will take the `$startAttributes` from the first token which is part of the
@ -76,39 +53,71 @@ class LessAttributesLexer extends PhpParser\Lexer {
}
```
You can obviously also add additional attributes. E.g. in conjunction with the above `FileLexer` you might want to add
a `fileName` attribute to all nodes:
Token offset lexer
------------------
A useful application for custom attributes is the token offset lexer, which provides the start and end token for a node
as attributes:
```php
<?php
class FileLexer extends PhpParser\Lexer {
protected $fileName;
public function startLexing($fileName) {
if (!file_exists($fileName)) {
throw new InvalidArgumentException(sprintf('File "%s" does not exist', $fileName));
}
$this->fileName = $fileName;
parent::startLexing(file_get_contents($fileName));
}
class TokenOffsetLexer extends PhpParser\Lexer {
public function getNextToken(&$value = null, &$startAttributes = null, &$endAttributes = null) {
$tokenId = parent::getNextToken($value, $startAttributes, $endAttributes);
// we could use either $startAttributes or $endAttributes here, because the fileName is always the same
// (regardless of whether it is the start or end token). We choose $endAttributes, because it is slightly
// more efficient (as the parser has to keep a stack for the $startAttributes).
$endAttributes['fileName'] = $this->fileName;
$startAttributes['startOffset'] = $endAttributes['endOffset'] = $this->pos;
return $tokenId;
}
public function getTokens() {
return $this->tokens;
}
}
```
handleHaltCompiler
------------------
This information can now be used to examine the exact formatting used for a node. For example the AST does not
distinguish whether a property was declared using `public` or using `var`, but you can retrieve this information based
on the token offset:
The method is invoked whenever a `T_HALT_COMPILER` token is encountered. It has to return the remaining string after the
construct (not including `();`).
```php
function isDeclaredUsingVar(array $tokens, PhpParser\Node\Stmt\Property $prop) {
$i = $prop->getAttribute('startOffset');
return $tokens[$i][0] === T_VAR;
}
```
In order to make use of this function, you will have to provide the tokens from the lexer to your node visitor using
code similar to the following:
```php
class MyNodeVisitor extends PhpParser\NodeVisitorAbstract {
private $tokens;
public function setTokens(array $tokens) {
$this->tokens = $tokens;
}
public function leaveNode(PhpParser\Node $node) {
if ($node instanceof PhpParser\Node\Stmt\Property) {
var_dump(isDeclaredUsingVar($this->tokens, $node));
}
}
}
$lexer = new TokenOffsetLexer();
$parser = new PhpParser\Parser($lexer);
$visitor = new MyNodeVisitor();
$traverser = new PhpParser\NodeTraverser();
$traverser->addVisitor($visitor);
try {
$stmts = $parser->parse($code);
$visitor->setTokens($lexer->getTokens());
$stmts = $traverser->traverse($stmts);
} catch (PhpParser\Error $e) {
echo 'Parse Error: ', $e->getMessage();
}
```
The same approach can also be used to perform specific modifications in the code, without changing the formatting in
other places (which is the case when using the pretty printer).

View File

@ -705,7 +705,7 @@ class_name_or_var:
;
object_access_for_dcnr:
| base_variable T_OBJECT_OPERATOR object_property
base_variable T_OBJECT_OPERATOR object_property
{ $$ = Expr\PropertyFetch[$1, $3]; }
| object_access_for_dcnr T_OBJECT_OPERATOR object_property
{ $$ = Expr\PropertyFetch[$1, $3]; }

View File

@ -194,6 +194,11 @@ class Lexer
}
}
// HHVM uses a special token for numbers that overflow to double
if (defined('T_ONUMBER')) {
$tokenMap[T_ONUMBER] = Parser::T_DNUMBER;
}
return $tokenMap;
}
}

View File

@ -25,6 +25,8 @@ class DNumber extends Scalar
}
/**
* @internal
*
* Parses a DNUMBER token like PHP would.
*
* @param string $str A string number

View File

@ -25,6 +25,8 @@ class LNumber extends Scalar
}
/**
* @internal
*
* Parses an LNUMBER token (dec, hex, oct and bin notations) like PHP would.
*
* @param string $str A string number

View File

@ -36,6 +36,8 @@ class String extends Scalar
}
/**
* @internal
*
* Parses a string token.
*
* @param string $str String token content
@ -60,6 +62,8 @@ class String extends Scalar
}
/**
* @internal
*
* Parses escape sequences in strings (all string types apart from single quoted).
*
* @param string $str String without quotes
@ -79,7 +83,7 @@ class String extends Scalar
);
}
public static function parseCallback($matches) {
private static function parseCallback($matches) {
$str = $matches[1];
if (isset(self::$replacements[$str])) {
@ -92,6 +96,8 @@ class String extends Scalar
}
/**
* @internal
*
* Parses a constant doc string.
*
* @param string $startToken Doc string start token content (<<<SMTHG)

View File

@ -83,6 +83,9 @@ class Class_ extends Node\Stmt
return $methods;
}
/**
* @internal
*/
public static function verifyModifier($a, $b) {
if ($a & 7 && $b & 7) {
throw new Error('Multiple access type modifiers are not allowed');

View File

@ -2,8 +2,12 @@
namespace PhpParser\Node\Stmt;
use PhpParser\Node\Stmt;
use PhpParser\Node;
abstract class TraitUseAdaptation extends Stmt
/**
* @property Node\Name $trait Trait name
* @property string $method Method name
*/
abstract class TraitUseAdaptation extends Node\Stmt
{
}

View File

@ -77,6 +77,19 @@ class NameResolver extends NodeVisitorAbstract
foreach ($node->traits as &$trait) {
$trait = $this->resolveClassName($trait);
}
foreach($node->adaptations as $adaptation) {
if (null !== $adaptation->trait) {
$adaptation->trait = $this->resolveClassName($adaptation->trait);
}
if ($adaptation instanceof Stmt\TraitUseAdaptation\Precedence) {
foreach ($adaptation->insteadof as &$insteadof) {
$insteadof = $this->resolveClassName($insteadof);
}
}
}
} elseif ($node instanceof Node\Param
&& $node->type instanceof Name
) {

File diff suppressed because it is too large Load Diff

View File

@ -541,7 +541,7 @@ class Standard extends PrettyPrinterAbstract
public function pStmt_TraitUseAdaptation_Alias(Stmt\TraitUseAdaptation\Alias $node) {
return (null !== $node->trait ? $this->p($node->trait) . '::' : '')
. $node->method . ' as'
. (null !== $node->newModifier ? ' ' . $this->pModifiers($node->newModifier) : '')
. (null !== $node->newModifier ? ' ' . rtrim($this->pModifiers($node->newModifier), ' ') : '')
. (null !== $node->newName ? ' ' . $node->newName : '')
. ';';
}

View File

@ -23,7 +23,7 @@ class InterfaceTest extends \PHPUnit_Framework_TestCase
public function testEmpty() {
$contract = $this->builder->getNode();
$this->assertInstanceOf('PhpParser\Node\Stmt\Interface_', $contract);
$this->assertEquals('Contract', $contract->name);
$this->assertSame('Contract', $contract->name);
}
public function testExtending() {
@ -41,7 +41,7 @@ class InterfaceTest extends \PHPUnit_Framework_TestCase
public function testAddMethod() {
$method = new Stmt\ClassMethod('doSomething');
$contract = $this->builder->addStmt($method)->getNode();
$this->assertEquals(array($method), $contract->stmts);
$this->assertSame(array($method), $contract->stmts);
}
public function testAddConst() {
@ -49,7 +49,7 @@ class InterfaceTest extends \PHPUnit_Framework_TestCase
new Node\Const_('SPEED_OF_LIGHT', new DNumber(299792458))
));
$contract = $this->builder->addStmt($const)->getNode();
$this->assertEquals(299792458, $contract->stmts[0]->consts[0]->value->value);
$this->assertSame(299792458, $contract->stmts[0]->consts[0]->value->value);
}
public function testOrder() {

View File

@ -7,16 +7,16 @@ class CommentTest extends \PHPUnit_Framework_TestCase
public function testGetSet() {
$comment = new Comment('/* Some comment */', 1);
$this->assertEquals('/* Some comment */', $comment->getText());
$this->assertEquals('/* Some comment */', (string) $comment);
$this->assertEquals(1, $comment->getLine());
$this->assertSame('/* Some comment */', $comment->getText());
$this->assertSame('/* Some comment */', (string) $comment);
$this->assertSame(1, $comment->getLine());
$comment->setText('/* Some other comment */');
$comment->setLine(10);
$this->assertEquals('/* Some other comment */', $comment->getText());
$this->assertEquals('/* Some other comment */', (string) $comment);
$this->assertEquals(10, $comment->getLine());
$this->assertSame('/* Some other comment */', $comment->getText());
$this->assertSame('/* Some other comment */', (string) $comment);
$this->assertSame(10, $comment->getLine());
}
/**
@ -24,7 +24,7 @@ class CommentTest extends \PHPUnit_Framework_TestCase
*/
public function testReformatting($commentText, $reformattedText) {
$comment = new Comment($commentText);
$this->assertEquals($reformattedText, $comment->getReformattedText());
$this->assertSame($reformattedText, $comment->getReformattedText());
}
public function provideTestReformatting() {

View File

@ -7,9 +7,9 @@ class ErrorTest extends \PHPUnit_Framework_TestCase
public function testConstruct() {
$error = new Error('Some error', 10);
$this->assertEquals('Some error', $error->getRawMessage());
$this->assertEquals(10, $error->getRawLine());
$this->assertEquals('Some error on line 10', $error->getMessage());
$this->assertSame('Some error', $error->getRawMessage());
$this->assertSame(10, $error->getRawLine());
$this->assertSame('Some error on line 10', $error->getMessage());
return $error;
}
@ -21,15 +21,15 @@ class ErrorTest extends \PHPUnit_Framework_TestCase
$error->setRawMessage('Some other error');
$error->setRawLine(15);
$this->assertEquals('Some other error', $error->getRawMessage());
$this->assertEquals(15, $error->getRawLine());
$this->assertEquals('Some other error on line 15', $error->getMessage());
$this->assertSame('Some other error', $error->getRawMessage());
$this->assertSame(15, $error->getRawLine());
$this->assertSame('Some other error on line 15', $error->getMessage());
}
public function testUnknownLine() {
$error = new Error('Some error');
$this->assertEquals(-1, $error->getRawLine());
$this->assertEquals('Some error on unknown line', $error->getMessage());
$this->assertSame(-1, $error->getRawLine());
$this->assertSame('Some error on unknown line', $error->getMessage());
}
}

View File

@ -19,8 +19,8 @@ class EmulativeTest extends \PHPUnit_Framework_TestCase
public function testReplaceKeywords($keyword, $expectedToken) {
$this->lexer->startLexing('<?php ' . $keyword);
$this->assertEquals($expectedToken, $this->lexer->getNextToken());
$this->assertEquals(0, $this->lexer->getNextToken());
$this->assertSame($expectedToken, $this->lexer->getNextToken());
$this->assertSame(0, $this->lexer->getNextToken());
}
/**
@ -29,9 +29,9 @@ class EmulativeTest extends \PHPUnit_Framework_TestCase
public function testNoReplaceKeywordsAfterObjectOperator($keyword) {
$this->lexer->startLexing('<?php ->' . $keyword);
$this->assertEquals(Parser::T_OBJECT_OPERATOR, $this->lexer->getNextToken());
$this->assertEquals(Parser::T_STRING, $this->lexer->getNextToken());
$this->assertEquals(0, $this->lexer->getNextToken());
$this->assertSame(Parser::T_OBJECT_OPERATOR, $this->lexer->getNextToken());
$this->assertSame(Parser::T_STRING, $this->lexer->getNextToken());
$this->assertSame(0, $this->lexer->getNextToken());
}
public function provideTestReplaceKeywords() {
@ -62,10 +62,10 @@ class EmulativeTest extends \PHPUnit_Framework_TestCase
foreach ($expectedTokens as $expectedToken) {
list($expectedTokenType, $expectedTokenText) = $expectedToken;
$this->assertEquals($expectedTokenType, $this->lexer->getNextToken($text));
$this->assertEquals($expectedTokenText, $text);
$this->assertSame($expectedTokenType, $this->lexer->getNextToken($text));
$this->assertSame($expectedTokenText, $text);
}
$this->assertEquals(0, $this->lexer->getNextToken());
$this->assertSame(0, $this->lexer->getNextToken());
}
/**
@ -75,9 +75,9 @@ class EmulativeTest extends \PHPUnit_Framework_TestCase
$stringifiedToken = '"' . addcslashes($code, '"\\') . '"';
$this->lexer->startLexing('<?php ' . $stringifiedToken);
$this->assertEquals(Parser::T_CONSTANT_ENCAPSED_STRING, $this->lexer->getNextToken($text));
$this->assertEquals($stringifiedToken, $text);
$this->assertEquals(0, $this->lexer->getNextToken());
$this->assertSame(Parser::T_CONSTANT_ENCAPSED_STRING, $this->lexer->getNextToken($text));
$this->assertSame($stringifiedToken, $text);
$this->assertSame(0, $this->lexer->getNextToken());
}
public function provideTestLexNewFeatures() {

View File

@ -18,7 +18,7 @@ class LexerTest extends \PHPUnit_Framework_TestCase
try {
$this->lexer->startLexing($code);
} catch (Error $e) {
$this->assertEquals($message, $e->getMessage());
$this->assertSame($message, $e->getMessage());
return;
}
@ -42,8 +42,8 @@ class LexerTest extends \PHPUnit_Framework_TestCase
while ($id = $this->lexer->getNextToken($value, $startAttributes, $endAttributes)) {
$token = array_shift($tokens);
$this->assertEquals($token[0], $id);
$this->assertEquals($token[1], $value);
$this->assertSame($token[0], $id);
$this->assertSame($token[1], $value);
$this->assertEquals($token[2], $startAttributes);
$this->assertEquals($token[3], $endAttributes);
}
@ -131,8 +131,8 @@ class LexerTest extends \PHPUnit_Framework_TestCase
while (Parser::T_HALT_COMPILER !== $this->lexer->getNextToken());
$this->assertEquals($this->lexer->handleHaltCompiler(), $remaining);
$this->assertEquals(0, $this->lexer->getNextToken());
$this->assertSame($this->lexer->handleHaltCompiler(), $remaining);
$this->assertSame(0, $this->lexer->getNextToken());
}
public function provideTestHaltCompiler() {

View File

@ -6,93 +6,93 @@ class NameTest extends \PHPUnit_Framework_TestCase
{
public function testConstruct() {
$name = new Name(array('foo', 'bar'));
$this->assertEquals(array('foo', 'bar'), $name->parts);
$this->assertSame(array('foo', 'bar'), $name->parts);
$name = new Name('foo\bar');
$this->assertEquals(array('foo', 'bar'), $name->parts);
$this->assertSame(array('foo', 'bar'), $name->parts);
}
public function testGet() {
$name = new Name('foo');
$this->assertEquals('foo', $name->getFirst());
$this->assertEquals('foo', $name->getLast());
$this->assertSame('foo', $name->getFirst());
$this->assertSame('foo', $name->getLast());
$name = new Name('foo\bar');
$this->assertEquals('foo', $name->getFirst());
$this->assertEquals('bar', $name->getLast());
$this->assertSame('foo', $name->getFirst());
$this->assertSame('bar', $name->getLast());
}
public function testToString() {
$name = new Name('foo\bar');
$this->assertEquals('foo\bar', (string) $name);
$this->assertEquals('foo\bar', $name->toString());
$this->assertEquals('foo_bar', $name->toString('_'));
$this->assertSame('foo\bar', (string) $name);
$this->assertSame('foo\bar', $name->toString());
$this->assertSame('foo_bar', $name->toString('_'));
}
public function testSet() {
$name = new Name('foo');
$name->set('foo\bar');
$this->assertEquals('foo\bar', $name->toString());
$this->assertSame('foo\bar', $name->toString());
$name->set(array('foo', 'bar'));
$this->assertEquals('foo\bar', $name->toString());
$this->assertSame('foo\bar', $name->toString());
$name->set(new Name('foo\bar'));
$this->assertEquals('foo\bar', $name->toString());
$this->assertSame('foo\bar', $name->toString());
}
public function testSetFirst() {
$name = new Name('foo');
$name->setFirst('bar');
$this->assertEquals('bar', $name->toString());
$this->assertSame('bar', $name->toString());
$name->setFirst('A\B');
$this->assertEquals('A\B', $name->toString());
$this->assertSame('A\B', $name->toString());
$name->setFirst('C');
$this->assertEquals('C\B', $name->toString());
$this->assertSame('C\B', $name->toString());
$name->setFirst('D\E');
$this->assertEquals('D\E\B', $name->toString());
$this->assertSame('D\E\B', $name->toString());
}
public function testSetLast() {
$name = new Name('foo');
$name->setLast('bar');
$this->assertEquals('bar', $name->toString());
$this->assertSame('bar', $name->toString());
$name->setLast('A\B');
$this->assertEquals('A\B', $name->toString());
$this->assertSame('A\B', $name->toString());
$name->setLast('C');
$this->assertEquals('A\C', $name->toString());
$this->assertSame('A\C', $name->toString());
$name->setLast('D\E');
$this->assertEquals('A\D\E', $name->toString());
$this->assertSame('A\D\E', $name->toString());
}
public function testAppend() {
$name = new Name('foo');
$name->append('bar');
$this->assertEquals('foo\bar', $name->toString());
$this->assertSame('foo\bar', $name->toString());
$name->append('bar\foo');
$this->assertEquals('foo\bar\bar\foo', $name->toString());
$this->assertSame('foo\bar\bar\foo', $name->toString());
}
public function testPrepend() {
$name = new Name('foo');
$name->prepend('bar');
$this->assertEquals('bar\foo', $name->toString());
$this->assertSame('bar\foo', $name->toString());
$name->prepend('foo\bar');
$this->assertEquals('foo\bar\bar\foo', $name->toString());
$this->assertSame('foo\bar\bar\foo', $name->toString());
}
public function testIs() {

View File

@ -8,7 +8,7 @@ class StringTest extends \PHPUnit_Framework_TestCase
* @dataProvider provideTestParseEscapeSequences
*/
public function testParseEscapeSequences($expected, $string, $quote) {
$this->assertEquals(
$this->assertSame(
$expected,
String::parseEscapeSequences($string, $quote)
);
@ -18,7 +18,7 @@ class StringTest extends \PHPUnit_Framework_TestCase
* @dataProvider provideTestParse
*/
public function testCreate($expected, $string) {
$this->assertEquals(
$this->assertSame(
$expected,
String::parse($string)
);

View File

@ -37,6 +37,6 @@ class ClassTest extends \PHPUnit_Framework_TestCase
)
));
$this->assertEquals($methods, $class->getMethods());
$this->assertSame($methods, $class->getMethods());
}
}

View File

@ -25,13 +25,13 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
'PhpParser_Node_Dummy'
);
$this->assertEquals('Dummy', $node->getType());
$this->assertEquals(array('subNode'), $node->getSubNodeNames());
$this->assertEquals(10, $node->getLine());
$this->assertEquals('/** doc comment */', $node->getDocComment());
$this->assertEquals('value', $node->subNode);
$this->assertSame('Dummy', $node->getType());
$this->assertSame(array('subNode'), $node->getSubNodeNames());
$this->assertSame(10, $node->getLine());
$this->assertSame('/** doc comment */', $node->getDocComment()->getText());
$this->assertSame('value', $node->subNode);
$this->assertTrue(isset($node->subNode));
$this->assertEquals($attributes, $node->getAttributes());
$this->assertSame($attributes, $node->getAttributes());
return $node;
}
@ -40,7 +40,7 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
* @depends testConstruct
*/
public function testGetDocComment(Node $node) {
$this->assertEquals('/** doc comment */', $node->getDocComment());
$this->assertSame('/** doc comment */', $node->getDocComment()->getText());
array_pop($node->getAttribute('comments')); // remove doc comment
$this->assertNull($node->getDocComment());
array_pop($node->getAttribute('comments')); // remove comment
@ -53,16 +53,16 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
public function testChange(Node $node) {
// change of line
$node->setLine(15);
$this->assertEquals(15, $node->getLine());
$this->assertSame(15, $node->getLine());
// direct modification
$node->subNode = 'newValue';
$this->assertEquals('newValue', $node->subNode);
$this->assertSame('newValue', $node->subNode);
// indirect modification
$subNode =& $node->subNode;
$subNode = 'newNewValue';
$this->assertEquals('newNewValue', $node->subNode);
$this->assertSame('newNewValue', $node->subNode);
// removal
unset($node->subNode);
@ -77,18 +77,18 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
$node->setAttribute('key', 'value');
$this->assertTrue($node->hasAttribute('key'));
$this->assertEquals('value', $node->getAttribute('key'));
$this->assertSame('value', $node->getAttribute('key'));
$this->assertFalse($node->hasAttribute('doesNotExist'));
$this->assertNull($node->getAttribute('doesNotExist'));
$this->assertEquals('default', $node->getAttribute('doesNotExist', 'default'));
$this->assertSame('default', $node->getAttribute('doesNotExist', 'default'));
$node->setAttribute('null', null);
$this->assertTrue($node->hasAttribute('null'));
$this->assertNull($node->getAttribute('null'));
$this->assertNull($node->getAttribute('null', 'default'));
$this->assertEquals(
$this->assertSame(
array(
'key' => 'value',
'null' => null,

View File

@ -6,12 +6,12 @@ class NodeDumperTest extends \PHPUnit_Framework_TestCase
{
/**
* @dataProvider provideTestDump
* @covers NodeDumper::dump
* @covers PhpParser\NodeDumper::dump
*/
public function testDump($node, $dump) {
$dumper = new NodeDumper;
$this->assertEquals($dump, $dumper->dump($node));
$this->assertSame($dump, $dumper->dump($node));
}
public function provideTestDump() {

View File

@ -11,7 +11,7 @@ use PhpParser\Node\Expr;
class NameResolverTest extends \PHPUnit_Framework_TestCase
{
/**
* @covers NameResolver
* @covers PhpParser\NodeVisitor\NameResolver
*/
public function testResolveNames() {
$code = <<<'EOC'
@ -133,22 +133,26 @@ EOC;
$stmts = $parser->parse($code);
$stmts = $traverser->traverse($stmts);
$this->assertEquals($expectedCode, $prettyPrinter->prettyPrint($stmts));
$this->assertSame($expectedCode, $prettyPrinter->prettyPrint($stmts));
}
/**
* @covers NameResolver
* @covers PhpParser\NodeVisitor\NameResolver
*/
public function testResolveLocations() {
$code = <<<'EOC'
<?php
namespace NS;
class A extends B implements C {
use A;
class A extends B implements C, D {
use E, F, G {
f as private g;
E::h as i;
E::j insteadof F, G;
}
}
interface A extends C {
interface A extends C, D {
public function a(A $a);
}
@ -170,11 +174,15 @@ EOC;
$expectedCode = <<<'EOC'
namespace NS;
class A extends \NS\B implements \NS\C
class A extends \NS\B implements \NS\C, \NS\D
{
use \NS\A;
use \NS\E, \NS\F, \NS\G {
f as private g;
\NS\E::h as i;
\NS\E::j insteadof \NS\F, \NS\G;
}
}
interface A extends \NS\C
interface A extends \NS\C, \NS\D
{
public function a(\NS\A $a);
}
@ -200,7 +208,7 @@ EOC;
$stmts = $parser->parse($code);
$stmts = $traverser->traverse($stmts);
$this->assertEquals($expectedCode, $prettyPrinter->prettyPrint($stmts));
$this->assertSame($expectedCode, $prettyPrinter->prettyPrint($stmts));
}
public function testNoResolveSpecialName() {
@ -234,14 +242,14 @@ EOC;
$stmts = $traverser->traverse($stmts);
$this->assertEquals('NS\\A', (string) $stmts[0]->stmts[0]->namespacedName);
$this->assertEquals('NS\\B', (string) $stmts[0]->stmts[1]->namespacedName);
$this->assertEquals('NS\\C', (string) $stmts[0]->stmts[2]->namespacedName);
$this->assertEquals('NS\\D', (string) $stmts[0]->stmts[3]->consts[0]->namespacedName);
$this->assertEquals('A', (string) $stmts[1]->stmts[0]->namespacedName);
$this->assertEquals('B', (string) $stmts[1]->stmts[1]->namespacedName);
$this->assertEquals('C', (string) $stmts[1]->stmts[2]->namespacedName);
$this->assertEquals('D', (string) $stmts[1]->stmts[3]->consts[0]->namespacedName);
$this->assertSame('NS\\A', (string) $stmts[0]->stmts[0]->namespacedName);
$this->assertSame('NS\\B', (string) $stmts[0]->stmts[1]->namespacedName);
$this->assertSame('NS\\C', (string) $stmts[0]->stmts[2]->namespacedName);
$this->assertSame('NS\\D', (string) $stmts[0]->stmts[3]->consts[0]->namespacedName);
$this->assertSame('A', (string) $stmts[1]->stmts[0]->namespacedName);
$this->assertSame('B', (string) $stmts[1]->stmts[1]->namespacedName);
$this->assertSame('C', (string) $stmts[1]->stmts[2]->namespacedName);
$this->assertSame('D', (string) $stmts[1]->stmts[3]->consts[0]->namespacedName);
}
public function testAddTraitNamespacedName() {
@ -254,8 +262,8 @@ EOC;
$stmts = $traverser->traverse($stmts);
$this->assertEquals('NS\\A', (string) $stmts[0]->stmts[0]->namespacedName);
$this->assertEquals('A', (string) $stmts[1]->stmts[0]->namespacedName);
$this->assertSame('NS\\A', (string) $stmts[0]->stmts[0]->namespacedName);
$this->assertSame('A', (string) $stmts[1]->stmts[0]->namespacedName);
}
/**
@ -329,7 +337,7 @@ EOC;
$stmts = $traverser->traverse($stmts);
$stmt = $stmts[0];
$this->assertEquals(array('Bar', 'Baz'), $stmt->stmts[1]->expr->class->parts);
$this->assertSame(array('Bar', 'Baz'), $stmt->stmts[1]->expr->class->parts);
}
public function testSpecialClassNamesAreCaseInsensitive() {
@ -358,8 +366,8 @@ EOC;
$classStmt = $stmts[0];
$methodStmt = $classStmt->stmts[0]->stmts[0];
$this->assertEquals('SELF', (string)$methodStmt->stmts[0]->class);
$this->assertEquals('PARENT', (string)$methodStmt->stmts[1]->class);
$this->assertEquals('STATIC', (string)$methodStmt->stmts[2]->class);
$this->assertSame('SELF', (string)$methodStmt->stmts[0]->class);
$this->assertSame('PARENT', (string)$methodStmt->stmts[1]->class);
$this->assertSame('STATIC', (string)$methodStmt->stmts[2]->class);
}
}

View File

@ -14,7 +14,7 @@ class ParserTest extends CodeTestAbstract
$dumper = new NodeDumper;
$stmts = $parser->parse($code);
$this->assertEquals(
$this->assertSame(
$this->canonicalize($dump),
$this->canonicalize($dumper->dump($stmts)),
$name
@ -36,7 +36,7 @@ class ParserTest extends CodeTestAbstract
$this->fail(sprintf('"%s": Expected Error', $name));
} catch (Error $e) {
$this->assertEquals($msg, $e->getMessage(), $name);
$this->assertSame($msg, $e->getMessage(), $name);
}
}

View File

@ -11,7 +11,7 @@ class PrettyPrinterTest extends CodeTestAbstract
$prettyPrinter = new PrettyPrinter\Standard;
$stmts = $parser->parse($code);
$this->assertEquals(
$this->assertSame(
$this->canonicalize($dump),
$this->canonicalize($prettyPrinter->$method($stmts)),
$name
@ -20,7 +20,7 @@ class PrettyPrinterTest extends CodeTestAbstract
/**
* @dataProvider provideTestPrettyPrint
* @covers PrettyPrinter\Standard<extended>
* @covers PhpParser\PrettyPrinter\Standard<extended>
*/
public function testPrettyPrint($name, $code, $dump) {
$this->doTestPrettyPrintMethod('prettyPrint', $name, $code, $dump);
@ -28,7 +28,7 @@ class PrettyPrinterTest extends CodeTestAbstract
/**
* @dataProvider provideTestPrettyPrintFile
* @covers PrettyPrinter\Standard<extended>
* @covers PhpParser\PrettyPrinter\Standard<extended>
*/
public function testPrettyPrintFile($name, $code, $dump) {
$this->doTestPrettyPrintMethod('prettyPrintFile', $name, $code, $dump);

View File

@ -7,7 +7,7 @@ use PhpParser;
class XMLTest extends \PHPUnit_Framework_TestCase
{
/**
* @covers XML<extended>
* @covers PhpParser\Serializer\XML<extended>
*/
public function testSerialize() {
$code = <<<CODE

View File

@ -32,6 +32,13 @@ const T_25 = 1 + 2 * 3;
const T_26 = "1" + 2 + "3";
const T_27 = 2 ** 3;
const T_28 = [1, 2, 3][1];
const T_29 = 12 - 13;
const T_30 = 12 ^ 13;
const T_31 = 12 & 13;
const T_32 = 12 | 13;
const T_33 = 12 % 3;
const T_34 = 100 >> 4;
const T_35 = !false;
-----
array(
0: Stmt_Const(
@ -505,4 +512,110 @@ array(
)
)
)
28: Stmt_Const(
consts: array(
0: Const(
name: T_29
value: Expr_BinaryOp_Minus(
left: Scalar_LNumber(
value: 12
)
right: Scalar_LNumber(
value: 13
)
)
)
)
)
29: Stmt_Const(
consts: array(
0: Const(
name: T_30
value: Expr_BinaryOp_BitwiseXor(
left: Scalar_LNumber(
value: 12
)
right: Scalar_LNumber(
value: 13
)
)
)
)
)
30: Stmt_Const(
consts: array(
0: Const(
name: T_31
value: Expr_BinaryOp_BitwiseAnd(
left: Scalar_LNumber(
value: 12
)
right: Scalar_LNumber(
value: 13
)
)
)
)
)
31: Stmt_Const(
consts: array(
0: Const(
name: T_32
value: Expr_BinaryOp_BitwiseOr(
left: Scalar_LNumber(
value: 12
)
right: Scalar_LNumber(
value: 13
)
)
)
)
)
32: Stmt_Const(
consts: array(
0: Const(
name: T_33
value: Expr_BinaryOp_Mod(
left: Scalar_LNumber(
value: 12
)
right: Scalar_LNumber(
value: 3
)
)
)
)
)
33: Stmt_Const(
consts: array(
0: Const(
name: T_34
value: Expr_BinaryOp_ShiftRight(
left: Scalar_LNumber(
value: 100
)
right: Scalar_LNumber(
value: 4
)
)
)
)
)
34: Stmt_Const(
consts: array(
0: Const(
name: T_35
value: Expr_BooleanNot(
expr: Expr_ConstFetch(
name: Name(
parts: array(
0: false
)
)
)
)
)
)
)
)

View File

@ -0,0 +1,6 @@
New without a class
-----
<?php
new;
-----
Syntax error, unexpected ';' on line 2

View File

@ -0,0 +1,25 @@
Trait uses and adaptations
-----
<?php
class A
{
use B, C, D {
f as g;
f as private;
f as private g;
B::f as g;
B::f insteadof C, D;
}
}
-----
class A
{
use B, C, D {
f as g;
f as private;
f as private g;
B::f as g;
B::f insteadof C, D;
}
}