Skip to content

Commit dff2547

Browse files
author
Manuel Pichler
committed
Refs #202: Support for variable arg list implemented
Still missing support for epsillon token as part of the callee arguments.
1 parent 41d75da commit dff2547

13 files changed

+306
-114
lines changed

composer.lock

Lines changed: 129 additions & 110 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/php/PDepend/Source/AST/ASTFormalParameter.php

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,29 @@
5858
*/
5959
class ASTFormalParameter extends ASTNode
6060
{
61+
/**
62+
* This method will return <b>true</b> when the parameter is declared as a
63+
* variable argument list <b>...</b>.
64+
*
65+
* @return boolean
66+
* @since 2.0.7
67+
*/
68+
public function isVariableArgList()
69+
{
70+
return $this->getMetadataBoolean(6);
71+
}
72+
73+
/**
74+
* This method can be used to mark this parameter as passed by reference.
75+
*
76+
* @return void
77+
@since 2.0.7
78+
*/
79+
public function setVariableArgList()
80+
{
81+
return $this->setMetadataBoolean(6, true);
82+
}
83+
6184
/**
6285
* This method will return <b>true</b> when the parameter is passed by
6386
* reference.
@@ -102,6 +125,6 @@ public function accept(ASTVisitor $visitor, $data = null)
102125
*/
103126
protected function getMetadataSize()
104127
{
105-
return 6;
128+
return 7;
106129
}
107130
}

src/main/php/PDepend/Source/Language/PHP/AbstractPHPParser.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5418,7 +5418,7 @@ private function parseFormalParameterAndByReference()
54185418
* @return \PDepend\Source\AST\ASTFormalParameter
54195419
* @since 0.9.6
54205420
*/
5421-
private function parseFormalParameter()
5421+
protected function parseFormalParameter()
54225422
{
54235423
$parameter = $this->builder->buildAstFormalParameter();
54245424
$parameter->addChild($this->parseVariableDeclarator());
@@ -6204,7 +6204,7 @@ private function parseStaticVariableDeclaration(Token $token)
62046204
* @return \PDepend\Source\AST\ASTVariableDeclarator
62056205
* @since 0.9.6
62066206
*/
6207-
private function parseVariableDeclarator()
6207+
protected function parseVariableDeclarator()
62086208
{
62096209
$this->tokenStack->push();
62106210

src/main/php/PDepend/Source/Language/PHP/PHPParserGeneric.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,4 +376,33 @@ protected function parseStaticValueVersionSpecific(ASTValue $value)
376376

377377
return $value;
378378
}
379+
380+
/**
381+
* This method will parse a formal parameter. A formal parameter is at least
382+
* a variable name, but can also contain a default parameter value.
383+
*
384+
* <code>
385+
* // -- -------
386+
* function foo(Bar $x, $y = 42) {}
387+
* // -- -------
388+
* </code>
389+
*
390+
* @return \PDepend\Source\AST\ASTFormalParameter
391+
* @since 2.0.7
392+
*/
393+
protected function parseFormalParameter()
394+
{
395+
$parameter = $this->builder->buildAstFormalParameter();
396+
397+
if (Tokens::T_ELLIPSIS === $this->tokenizer->peek()) {
398+
$this->consumeToken(Tokens::T_ELLIPSIS);
399+
$this->consumeComments();
400+
401+
$parameter->setVariableArgList();
402+
}
403+
404+
$parameter->addChild($this->parseVariableDeclarator());
405+
406+
return $parameter;
407+
}
379408
}

src/main/php/PDepend/Source/Language/PHP/PHPTokenizerInternal.php

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@
5656
*/
5757
class PHPTokenizerInternal implements Tokenizer
5858
{
59+
/**
60+
* Internally used transition token.
61+
*/
62+
const T_ELLIPSIS = 23006;
63+
5964
/**
6065
* Mapping between php internal tokens and php depend tokens.
6166
*
@@ -129,6 +134,7 @@ class PHPTokenizerInternal implements Tokenizer
129134
T_OR_EQUAL => Tokens::T_OR_EQUAL,
130135
T_CONTINUE => Tokens::T_CONTINUE,
131136
T_METHOD_C => Tokens::T_METHOD_C,
137+
T_ELLIPSIS => Tokens::T_ELLIPSIS,
132138
T_OPEN_TAG => Tokens::T_OPEN_TAG,
133139
T_SL_EQUAL => Tokens::T_SL_EQUAL,
134140
T_SR_EQUAL => Tokens::T_SR_EQUAL,
@@ -358,6 +364,19 @@ class PHPTokenizerInternal implements Tokenizer
358364
),
359365
);
360366

367+
protected static $reductionMap = array(
368+
Tokens::T_CONCAT => array(
369+
Tokens::T_CONCAT => array(
370+
'type' => self::T_ELLIPSIS,
371+
'image' => '..'
372+
),
373+
self::T_ELLIPSIS => array(
374+
'type' => Tokens::T_ELLIPSIS,
375+
'image' => '...'
376+
)
377+
),
378+
);
379+
361380
/**
362381
* The source file instance.
363382
*
@@ -592,12 +611,20 @@ private function tokenize()
592611
if (isset($literalMap[$value])) {
593612
// Fetch literal type
594613
$type = $literalMap[$value];
614+
$image = $token[1];
595615

596616
// Check for a context sensitive alternative
597617
if (isset(self::$alternativeMap[$type][$previousType])) {
598618
$type = self::$alternativeMap[$type][$previousType];
599619
}
600-
$image = $token[1];
620+
621+
if (isset(self::$reductionMap[$type][$previousType])) {
622+
$image = self::$reductionMap[$type][$previousType]['image'];
623+
$type = self::$reductionMap[$type][$previousType]['type'];
624+
625+
array_pop($this->tokens);
626+
}
627+
601628
} elseif (isset($tokenMap[$token[0]])) {
602629
$type = $tokenMap[$token[0]];
603630
// Check for a context sensitive alternative

src/main/php/PDepend/Source/Tokenizer/Tokenizer.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@
8484
define('T_NAMESPACE', 42005);
8585
}
8686

87+
/**
88+
* Define PHP 5.6 '...' token constant
89+
*/
90+
if (!defined('T_ELLIPSIS')) {
91+
define('T_ELLIPSIS', 42006);
92+
}
93+
8794
/**
8895
* Define PHP 5.3's '__DIR__' token constant.
8996
*/

src/main/php/PDepend/Source/Tokenizer/Tokens.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,13 @@ interface Tokens
850850
*/
851851
const T_FINALLY = 160;
852852

853+
/**
854+
* TOken that represents the '...' token
855+
*
856+
* @since 2.0.7
857+
*/
858+
const T_ELLIPSIS = 161;
859+
853860
/**
854861
* Marks any content not between php tags.
855862
*/

src/test/php/PDepend/Source/AST/ASTFormalParameterTest.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,61 @@
5555
*/
5656
class ASTFormalParameterTest extends \PDepend\Source\AST\ASTNodeTest
5757
{
58+
/**
59+
* testIsVariableArgListReturnsFalseByDefault
60+
*
61+
* @return void
62+
*/
63+
public function testIsVariableArgListReturnsFalseByDefault()
64+
{
65+
$parameter = $this->_getFirstFormalParameterInFunction();
66+
$this->assertFalse($parameter->isVariableArgList());
67+
}
68+
69+
/**
70+
* testIsVariableArgListReturnsTrue
71+
*
72+
* @return void
73+
*/
74+
public function testIsVariableArgListReturnsTrue()
75+
{
76+
$parameter = $this->_getFirstFormalParameterInFunction();
77+
$this->assertTrue($parameter->isVariableArgList());
78+
}
79+
80+
/**
81+
* testIsVariableArgListWithArrayTypeHint
82+
*
83+
* @return void
84+
*/
85+
public function testIsVariableArgListWithArrayTypeHint()
86+
{
87+
$parameter = $this->_getFirstFormalParameterInFunction();
88+
$this->assertTrue($parameter->isVariableArgList());
89+
}
90+
91+
/**
92+
* testIsVariableArgListWithClassTypeHint
93+
*
94+
* @return void
95+
*/
96+
public function testIsVariableArgListWithClassTypeHint()
97+
{
98+
$parameter = $this->_getFirstFormalParameterInFunction();
99+
$this->assertTrue($parameter->isVariableArgList());
100+
}
101+
102+
/**
103+
* testIsVariableArgListPassedByReference
104+
*
105+
* @return void
106+
*/
107+
public function testIsVariableArgListPassedByReference()
108+
{
109+
$parameter = $this->_getFirstFormalParameterInFunction();
110+
$this->assertTrue($parameter->isVariableArgList());
111+
}
112+
58113
/**
59114
* testIsPassedByReferenceReturnsFalseByDefault
60115
*
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
function testIsVariableArgListPassedByReference(&...$argList)
3+
{
4+
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
function testIsVariableArgListReturnsFalseByDefault($pdepend)
3+
{
4+
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
function testIsVariableArgListReturnsTrue(...$argList)
3+
{
4+
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
function testIsVariableArgListWithArrayTypeHint(array ...$argList)
3+
{
4+
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
function testIsVariableArgListWithClassTypeHint(Iterator ...$iterator)
3+
{
4+
5+
}

0 commit comments

Comments
 (0)