mirror of
https://github.com/nikic/PHP-Parser.git
synced 2025-01-17 07:08:14 +01:00
Add support for variadic parameters (PHP 5.6)
This commit is contained in:
parent
f5be0d30f7
commit
96f1151ab2
@ -106,6 +106,7 @@
|
||||
%token T_NS_C
|
||||
%token T_DIR
|
||||
%token T_NS_SEPARATOR
|
||||
%token T_ELLIPSIS
|
||||
|
||||
%%
|
||||
|
||||
@ -235,6 +236,11 @@ optional_ref:
|
||||
| '&' { $$ = true; }
|
||||
;
|
||||
|
||||
optional_ellipsis:
|
||||
/* empty */ { $$ = false; }
|
||||
| T_ELLIPSIS { $$ = true; }
|
||||
;
|
||||
|
||||
function_declaration_statement:
|
||||
T_FUNCTION optional_ref T_STRING '(' parameter_list ')' '{' inner_statement_list '}'
|
||||
{ $$ = Stmt\Function_[$3, [byRef: $2, params: $5, stmts: $8]]; }
|
||||
@ -371,10 +377,10 @@ non_empty_parameter_list:
|
||||
;
|
||||
|
||||
parameter:
|
||||
optional_class_type optional_ref T_VARIABLE
|
||||
{ $$ = Param[parseVar($3), null, $1, $2]; }
|
||||
| optional_class_type optional_ref T_VARIABLE '=' static_scalar
|
||||
{ $$ = Param[parseVar($3), $5, $1, $2]; }
|
||||
optional_class_type optional_ref optional_ellipsis T_VARIABLE
|
||||
{ $$ = Param[parseVar($4), null, $1, $2, $3]; }
|
||||
| optional_class_type optional_ref optional_ellipsis T_VARIABLE '=' static_scalar
|
||||
{ $$ = Param[parseVar($4), $6, $1, $2, $3]; }
|
||||
;
|
||||
|
||||
optional_class_type:
|
||||
|
@ -12,6 +12,8 @@ class Emulative extends \PhpParser\Lexer
|
||||
protected $newKeywords;
|
||||
protected $inObjectAccess;
|
||||
|
||||
const T_ELLIPSIS = 1001;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
@ -36,13 +38,17 @@ class Emulative extends \PhpParser\Lexer
|
||||
|
||||
$this->newKeywords += $newKeywords;
|
||||
}
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.6.0beta1', '<')) {
|
||||
$this->tokenMap[self::T_ELLIPSIS] = Parser::T_ELLIPSIS;
|
||||
}
|
||||
}
|
||||
|
||||
public function startLexing($code) {
|
||||
$this->inObjectAccess = false;
|
||||
|
||||
// on PHP 5.4 don't do anything
|
||||
if (version_compare(PHP_VERSION, '5.4.0RC1', '>=')) {
|
||||
// on PHP 5.6 don't do anything
|
||||
if (version_compare(PHP_VERSION, '5.6.0beta1', '>=')) {
|
||||
parent::startLexing($code);
|
||||
} else {
|
||||
$code = $this->preprocessCode($code);
|
||||
@ -60,8 +66,14 @@ class Emulative extends \PhpParser\Lexer
|
||||
* inside a string, i.e. a place where they don't have a special meaning).
|
||||
*/
|
||||
protected function preprocessCode($code) {
|
||||
// binary notation (0b010101101001...)
|
||||
return preg_replace('(\b0b[01]+\b)', '~__EMU__BINARY__$0__~', $code);
|
||||
$code = str_replace('...', '~__EMU__ELLIPSIS__~', $code);
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.4.0beta1', '<')) {
|
||||
// binary notation (0b010101101001...)
|
||||
$code = preg_replace('(\b0b[01]+\b)', '~__EMU__BINARY__$0__~', $code);
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -86,6 +98,10 @@ class Emulative extends \PhpParser\Lexer
|
||||
$replace = array(
|
||||
array(is_int(bindec($matches[2])) ? T_LNUMBER : T_DNUMBER, $matches[2], $this->tokens[$i + 1][2])
|
||||
);
|
||||
} else if ('ELLIPSIS' === $matches[1]) {
|
||||
$replace = array(
|
||||
array(self::T_ELLIPSIS, '...', $this->tokens[$i + 1][2])
|
||||
);
|
||||
} else {
|
||||
// just ignore all other __EMU__ sequences
|
||||
continue;
|
||||
@ -114,6 +130,8 @@ class Emulative extends \PhpParser\Lexer
|
||||
public function restoreContentCallback(array $matches) {
|
||||
if ('BINARY' === $matches[1]) {
|
||||
return $matches[2];
|
||||
} else if ('ELLIPSIS' === $matches[1]) {
|
||||
return '...';
|
||||
} else {
|
||||
return $matches[0];
|
||||
}
|
||||
|
@ -2,13 +2,15 @@
|
||||
|
||||
namespace PhpParser\Node;
|
||||
|
||||
use PhpParser\Error;
|
||||
use PhpParser\NodeAbstract;
|
||||
|
||||
/**
|
||||
* @property string $name Name
|
||||
* @property null|Expr $default Default value
|
||||
* @property null|string|Name $type Typehint
|
||||
* @property bool $byRef Whether is passed by reference
|
||||
* @property null|string|Name $type Typehint
|
||||
* @property bool $byRef Whether is passed by reference
|
||||
* @property bool $variadic Whether this is a variadic argument
|
||||
* @property string $name Name
|
||||
* @property null|Expr $default Default value
|
||||
*/
|
||||
class Param extends NodeAbstract
|
||||
{
|
||||
@ -19,17 +21,23 @@ class Param extends NodeAbstract
|
||||
* @param null|Expr $default Default value
|
||||
* @param null|string|Name $type Typehint
|
||||
* @param bool $byRef Whether is passed by reference
|
||||
* @param bool $variadic Whether this is a variadic argument
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($name, $default = null, $type = null, $byRef = false, array $attributes = array()) {
|
||||
public function __construct($name, $default = null, $type = null, $byRef = false, $variadic = false, array $attributes = array()) {
|
||||
parent::__construct(
|
||||
array(
|
||||
'name' => $name,
|
||||
'default' => $default,
|
||||
'type' => $type,
|
||||
'byRef' => $byRef
|
||||
'type' => $type,
|
||||
'byRef' => $byRef,
|
||||
'variadic' => $variadic,
|
||||
'name' => $name,
|
||||
'default' => $default,
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
|
||||
if ($variadic && null !== $default) {
|
||||
throw new Error('Variadic parameter cannot have a default value');
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,7 @@ class Standard extends PrettyPrinterAbstract
|
||||
public function pParam(Node\Param $node) {
|
||||
return ($node->type ? (is_string($node->type) ? $node->type : $this->p($node->type)) . ' ' : '')
|
||||
. ($node->byRef ? '&' : '')
|
||||
. ($node->variadic ? '... ' : '')
|
||||
. '$' . $node->name
|
||||
. ($node->default ? ' = ' . $this->p($node->default) : '');
|
||||
}
|
||||
|
@ -82,6 +82,9 @@ class EmulativeTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function provideTestLexNewFeatures() {
|
||||
return array(
|
||||
array('...', array(
|
||||
array(Parser::T_ELLIPSIS, '...'),
|
||||
)),
|
||||
array('0b1010110', array(
|
||||
array(Parser::T_LNUMBER, '0b1010110'),
|
||||
)),
|
||||
|
@ -51,6 +51,15 @@ CODE;
|
||||
<attribute:endLine>
|
||||
<scalar:int>4</scalar:int>
|
||||
</attribute:endLine>
|
||||
<subNode:type>
|
||||
<scalar:null/>
|
||||
</subNode:type>
|
||||
<subNode:byRef>
|
||||
<scalar:true/>
|
||||
</subNode:byRef>
|
||||
<subNode:variadic>
|
||||
<scalar:false/>
|
||||
</subNode:variadic>
|
||||
<subNode:name>
|
||||
<scalar:string>a</scalar:string>
|
||||
</subNode:name>
|
||||
@ -67,12 +76,6 @@ CODE;
|
||||
</subNode:value>
|
||||
</node:Scalar_LNumber>
|
||||
</subNode:default>
|
||||
<subNode:type>
|
||||
<scalar:null/>
|
||||
</subNode:type>
|
||||
<subNode:byRef>
|
||||
<scalar:true/>
|
||||
</subNode:byRef>
|
||||
</node:Param>
|
||||
<node:Param>
|
||||
<attribute:startLine>
|
||||
@ -81,6 +84,15 @@ CODE;
|
||||
<attribute:endLine>
|
||||
<scalar:int>4</scalar:int>
|
||||
</attribute:endLine>
|
||||
<subNode:type>
|
||||
<scalar:null/>
|
||||
</subNode:type>
|
||||
<subNode:byRef>
|
||||
<scalar:false/>
|
||||
</subNode:byRef>
|
||||
<subNode:variadic>
|
||||
<scalar:false/>
|
||||
</subNode:variadic>
|
||||
<subNode:name>
|
||||
<scalar:string>b</scalar:string>
|
||||
</subNode:name>
|
||||
@ -97,12 +109,6 @@ CODE;
|
||||
</subNode:value>
|
||||
</node:Scalar_DNumber>
|
||||
</subNode:default>
|
||||
<subNode:type>
|
||||
<scalar:null/>
|
||||
</subNode:type>
|
||||
<subNode:byRef>
|
||||
<scalar:false/>
|
||||
</subNode:byRef>
|
||||
</node:Param>
|
||||
</scalar:array>
|
||||
</subNode:params>
|
||||
|
@ -13,10 +13,11 @@ array(
|
||||
byRef: false
|
||||
params: array(
|
||||
0: Param(
|
||||
name: a
|
||||
default: null
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: a
|
||||
default: null
|
||||
)
|
||||
)
|
||||
uses: array(
|
||||
@ -32,10 +33,11 @@ array(
|
||||
byRef: false
|
||||
params: array(
|
||||
0: Param(
|
||||
name: a
|
||||
default: null
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: a
|
||||
default: null
|
||||
)
|
||||
)
|
||||
uses: array(
|
||||
@ -70,10 +72,11 @@ array(
|
||||
byRef: true
|
||||
params: array(
|
||||
0: Param(
|
||||
name: a
|
||||
default: null
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: a
|
||||
default: null
|
||||
)
|
||||
)
|
||||
uses: array(
|
||||
|
@ -11,10 +11,11 @@ array(
|
||||
name: a
|
||||
params: array(
|
||||
0: Param(
|
||||
name: b
|
||||
default: null
|
||||
type: null
|
||||
byRef: true
|
||||
variadic: false
|
||||
name: b
|
||||
default: null
|
||||
)
|
||||
)
|
||||
stmts: array(
|
||||
@ -25,10 +26,11 @@ array(
|
||||
name: a
|
||||
params: array(
|
||||
0: Param(
|
||||
name: b
|
||||
default: null
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: b
|
||||
default: null
|
||||
)
|
||||
)
|
||||
stmts: array(
|
||||
|
@ -20,6 +20,9 @@ array(
|
||||
name: a
|
||||
params: array(
|
||||
0: Param(
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: b
|
||||
default: Expr_ConstFetch(
|
||||
name: Name(
|
||||
@ -28,18 +31,20 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
type: null
|
||||
byRef: false
|
||||
)
|
||||
1: Param(
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: c
|
||||
default: Scalar_String(
|
||||
value: foo
|
||||
)
|
||||
type: null
|
||||
byRef: false
|
||||
)
|
||||
2: Param(
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: d
|
||||
default: Expr_ClassConstFetch(
|
||||
class: Name(
|
||||
@ -49,48 +54,53 @@ array(
|
||||
)
|
||||
name: B
|
||||
)
|
||||
type: null
|
||||
byRef: false
|
||||
)
|
||||
3: Param(
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: f
|
||||
default: Expr_UnaryPlus(
|
||||
expr: Scalar_LNumber(
|
||||
value: 1
|
||||
)
|
||||
)
|
||||
type: null
|
||||
byRef: false
|
||||
)
|
||||
4: Param(
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: g
|
||||
default: Expr_UnaryMinus(
|
||||
expr: Scalar_DNumber(
|
||||
value: 1
|
||||
)
|
||||
)
|
||||
type: null
|
||||
byRef: false
|
||||
)
|
||||
5: Param(
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: h
|
||||
default: Expr_Array(
|
||||
items: array(
|
||||
)
|
||||
)
|
||||
type: null
|
||||
byRef: false
|
||||
)
|
||||
6: Param(
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: i
|
||||
default: Expr_Array(
|
||||
items: array(
|
||||
)
|
||||
)
|
||||
type: null
|
||||
byRef: false
|
||||
)
|
||||
7: Param(
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: j
|
||||
default: Expr_Array(
|
||||
items: array(
|
||||
@ -103,10 +113,11 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
type: null
|
||||
byRef: false
|
||||
)
|
||||
8: Param(
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: k
|
||||
default: Expr_Array(
|
||||
items: array(
|
||||
@ -128,8 +139,6 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
type: null
|
||||
byRef: false
|
||||
)
|
||||
)
|
||||
stmts: array(
|
||||
|
@ -10,32 +10,36 @@ array(
|
||||
name: a
|
||||
params: array(
|
||||
0: Param(
|
||||
name: b
|
||||
default: null
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: b
|
||||
default: null
|
||||
)
|
||||
1: Param(
|
||||
name: c
|
||||
default: null
|
||||
type: array
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: c
|
||||
default: null
|
||||
)
|
||||
2: Param(
|
||||
name: d
|
||||
default: null
|
||||
type: callable
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: d
|
||||
default: null
|
||||
)
|
||||
3: Param(
|
||||
name: f
|
||||
default: null
|
||||
type: Name(
|
||||
parts: array(
|
||||
0: E
|
||||
)
|
||||
)
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: f
|
||||
default: null
|
||||
)
|
||||
)
|
||||
stmts: array(
|
||||
|
106
test/code/parser/stmt/function/variadic.test
Normal file
106
test/code/parser/stmt/function/variadic.test
Normal file
@ -0,0 +1,106 @@
|
||||
Variadic functions
|
||||
-----
|
||||
<?php
|
||||
function test($a, ... $b) {}
|
||||
function test($a, &... $b) {}
|
||||
function test($a, Type ... $b) {}
|
||||
function test($a, Type &... $b) {}
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
byRef: false
|
||||
name: test
|
||||
params: array(
|
||||
0: Param(
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: a
|
||||
default: null
|
||||
)
|
||||
1: Param(
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: true
|
||||
name: b
|
||||
default: null
|
||||
)
|
||||
)
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Function(
|
||||
byRef: false
|
||||
name: test
|
||||
params: array(
|
||||
0: Param(
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: a
|
||||
default: null
|
||||
)
|
||||
1: Param(
|
||||
type: null
|
||||
byRef: true
|
||||
variadic: true
|
||||
name: b
|
||||
default: null
|
||||
)
|
||||
)
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
2: Stmt_Function(
|
||||
byRef: false
|
||||
name: test
|
||||
params: array(
|
||||
0: Param(
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: a
|
||||
default: null
|
||||
)
|
||||
1: Param(
|
||||
type: Name(
|
||||
parts: array(
|
||||
0: Type
|
||||
)
|
||||
)
|
||||
byRef: false
|
||||
variadic: true
|
||||
name: b
|
||||
default: null
|
||||
)
|
||||
)
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
3: Stmt_Function(
|
||||
byRef: false
|
||||
name: test
|
||||
params: array(
|
||||
0: Param(
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
name: a
|
||||
default: null
|
||||
)
|
||||
1: Param(
|
||||
type: Name(
|
||||
parts: array(
|
||||
0: Type
|
||||
)
|
||||
)
|
||||
byRef: true
|
||||
variadic: true
|
||||
name: b
|
||||
default: null
|
||||
)
|
||||
)
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
)
|
6
test/code/parser/stmt/function/variadic.test-fail
Normal file
6
test/code/parser/stmt/function/variadic.test-fail
Normal file
@ -0,0 +1,6 @@
|
||||
Invalid variadic function
|
||||
-----
|
||||
<?php
|
||||
function foo(...$foo = []) {}
|
||||
-----
|
||||
Variadic parameter cannot have a default value on line 2
|
25
test/code/prettyPrinter/param.test
Normal file
25
test/code/prettyPrinter/param.test
Normal file
@ -0,0 +1,25 @@
|
||||
Function parameters
|
||||
-----
|
||||
<?php
|
||||
|
||||
function test($a, &$b, Type $c, Type &$c, Type &... $d) {}
|
||||
function test(... $foo) {}
|
||||
function test(Type ... $foo) {}
|
||||
function test(&... $foo) {}
|
||||
-----
|
||||
function test($a, &$b, Type $c, Type &$c, Type &... $d)
|
||||
{
|
||||
|
||||
}
|
||||
function test(... $foo)
|
||||
{
|
||||
|
||||
}
|
||||
function test(Type ... $foo)
|
||||
{
|
||||
|
||||
}
|
||||
function test(&... $foo)
|
||||
{
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user