mirror of
https://github.com/phabelio/PHP-Parser.git
synced 2025-01-21 21:01:15 +01:00
Add support for "yield from"
This commit is contained in:
parent
a6d2cd69f8
commit
ab80054e97
@ -8,6 +8,7 @@
|
||||
%left T_LOGICAL_AND
|
||||
%right T_PRINT
|
||||
%right T_YIELD
|
||||
%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 '?' ':'
|
||||
%right T_COALESCE
|
||||
@ -616,6 +617,7 @@ expr:
|
||||
| '`' backticks_expr '`' { $$ = Expr\ShellExec[$2]; }
|
||||
| T_PRINT expr { $$ = Expr\Print_[$2]; }
|
||||
| T_YIELD { $$ = Expr\Yield_[null, null]; }
|
||||
| T_YIELD_FROM expr { $$ = Expr\YieldFrom[$2]; }
|
||||
| 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]]; }
|
||||
|
@ -12,11 +12,12 @@ class Emulative extends \PhpParser\Lexer
|
||||
protected $newKeywords;
|
||||
protected $inObjectAccess;
|
||||
|
||||
const T_ELLIPSIS = 1001;
|
||||
const T_POW = 1002;
|
||||
const T_POW_EQUAL = 1003;
|
||||
const T_COALESCE = 1004;
|
||||
const T_SPACESHIP = 1005;
|
||||
const T_ELLIPSIS = 1001;
|
||||
const T_POW = 1002;
|
||||
const T_POW_EQUAL = 1003;
|
||||
const T_COALESCE = 1004;
|
||||
const T_SPACESHIP = 1005;
|
||||
const T_YIELD_FROM = 1006;
|
||||
|
||||
const PHP_7_0 = '7.0.0dev';
|
||||
const PHP_5_6 = '5.6.0rc1';
|
||||
@ -53,6 +54,7 @@ class Emulative extends \PhpParser\Lexer
|
||||
}
|
||||
$this->tokenMap[self::T_COALESCE] = Parser::T_COALESCE;
|
||||
$this->tokenMap[self::T_SPACESHIP] = Parser::T_SPACESHIP;
|
||||
$this->tokenMap[self::T_YIELD_FROM] = Parser::T_YIELD_FROM;
|
||||
|
||||
if (version_compare(PHP_VERSION, self::PHP_5_6, '>=')) {
|
||||
return;
|
||||
@ -91,6 +93,10 @@ class Emulative extends \PhpParser\Lexer
|
||||
|
||||
$code = str_replace('??', '~__EMU__COALESCE__~', $code);
|
||||
$code = str_replace('<=>', '~__EMU__SPACESHIP__~', $code);
|
||||
$code = preg_replace_callback('(yield[ \n\r\t]+from)', function($matches) {
|
||||
// Encoding $0 in order to preserve exact whitespace
|
||||
return '~__EMU__YIELDFROM__' . bin2hex($matches[0]) . '__~';
|
||||
}, $code);
|
||||
|
||||
if (version_compare(PHP_VERSION, self::PHP_5_6, '>=')) {
|
||||
return $code;
|
||||
@ -127,8 +133,9 @@ class Emulative extends \PhpParser\Lexer
|
||||
if ('BINARY' === $matches[1]) {
|
||||
// the binary number can either be an integer or a double, so return a LNUMBER
|
||||
// or DNUMBER respectively
|
||||
$isInt = is_int(bindec($matches[2]));
|
||||
$replace = array(
|
||||
array(is_int(bindec($matches[2])) ? T_LNUMBER : T_DNUMBER, $matches[2], $this->tokens[$i + 1][2])
|
||||
array($isInt ? T_LNUMBER : T_DNUMBER, $matches[2], $this->tokens[$i + 1][2])
|
||||
);
|
||||
} else if ('ELLIPSIS' === $matches[1]) {
|
||||
$replace = array(
|
||||
@ -150,9 +157,13 @@ class Emulative extends \PhpParser\Lexer
|
||||
$replace = array(
|
||||
array(self::T_SPACESHIP, '<=>', $this->tokens[$i + 1][2]),
|
||||
);
|
||||
} else if ('YIELDFROM' === $matches[1]) {
|
||||
$content = $this->hex2bin($matches[2]);
|
||||
$replace = array(
|
||||
array(self::T_YIELD_FROM, $content, $this->tokens[$i + 1][2] - substr_count($content, "\n"))
|
||||
);
|
||||
} else {
|
||||
// just ignore all other __EMU__ sequences
|
||||
continue;
|
||||
throw new \RuntimeException('Invalid __EMU__ sequence');
|
||||
}
|
||||
|
||||
array_splice($this->tokens, $i, 3, $replace);
|
||||
@ -188,11 +199,18 @@ class Emulative extends \PhpParser\Lexer
|
||||
return '??';
|
||||
} else if ('SPACESHIP' === $matches[1]) {
|
||||
return '<=>';
|
||||
} else if ('YIELDFROM' === $matches[1]) {
|
||||
return $this->hex2bin($matches[2]);
|
||||
} else {
|
||||
return $matches[0];
|
||||
}
|
||||
}
|
||||
|
||||
private function hex2bin($str) {
|
||||
// TODO Drop when removing support for PHP 5.3
|
||||
return pack('H*', $str);
|
||||
}
|
||||
|
||||
public function getNextToken(&$value = null, &$startAttributes = null, &$endAttributes = null) {
|
||||
$token = parent::getNextToken($value, $startAttributes, $endAttributes);
|
||||
|
||||
@ -203,11 +221,9 @@ class Emulative extends \PhpParser\Lexer
|
||||
if (isset($this->newKeywords[strtolower($value)])) {
|
||||
return $this->newKeywords[strtolower($value)];
|
||||
}
|
||||
// keep track of whether we currently are in an object access (after ->)
|
||||
} elseif (Parser::T_OBJECT_OPERATOR === $token) {
|
||||
$this->inObjectAccess = true;
|
||||
} else {
|
||||
$this->inObjectAccess = false;
|
||||
// keep track of whether we currently are in an object access (after ->)
|
||||
$this->inObjectAccess = Parser::T_OBJECT_OPERATOR === $token;
|
||||
}
|
||||
|
||||
return $token;
|
||||
|
26
lib/PhpParser/Node/Expr/YieldFrom.php
Normal file
26
lib/PhpParser/Node/Expr/YieldFrom.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
class YieldFrom extends Expr
|
||||
{
|
||||
/** @var Expr Expression to yield from */
|
||||
public $expr;
|
||||
|
||||
/**
|
||||
* Constructs an "yield from" node.
|
||||
*
|
||||
* @param Expr $expr Expression
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $expr, array $attributes = array()) {
|
||||
parent::__construct(null, $attributes);
|
||||
$this->expr = $expr;
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('expr');
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -312,6 +312,10 @@ class Standard extends PrettyPrinterAbstract
|
||||
return $this->pPrefixOp('Expr_ErrorSuppress', '@', $node->expr);
|
||||
}
|
||||
|
||||
public function pExpr_YieldFrom(Expr\YieldFrom $node) {
|
||||
return $this->pPrefixOp('Expr_YieldFrom', 'yield from ', $node->expr);
|
||||
}
|
||||
|
||||
// Casts
|
||||
|
||||
public function pExpr_Cast_Int(Cast\Int_ $node) {
|
||||
|
@ -66,6 +66,7 @@ abstract class PrettyPrinterAbstract
|
||||
'Expr_AssignOp_ShiftLeft' => array(160, 1),
|
||||
'Expr_AssignOp_ShiftRight' => array(160, 1),
|
||||
'Expr_AssignOp_Pow' => array(160, 1),
|
||||
'Expr_YieldFrom' => array(165, 1),
|
||||
'Expr_BinaryOp_LogicalAnd' => array(170, -1),
|
||||
'Expr_BinaryOp_LogicalXor' => array(180, -1),
|
||||
'Expr_BinaryOp_LogicalOr' => array(190, -1),
|
||||
|
@ -87,6 +87,12 @@ class EmulativeTest extends LexerTest
|
||||
|
||||
public function provideTestLexNewFeatures() {
|
||||
return array(
|
||||
array('yield from', array(
|
||||
array(Parser::T_YIELD_FROM, 'yield from'),
|
||||
)),
|
||||
array("yield\r\nfrom", array(
|
||||
array(Parser::T_YIELD_FROM, "yield\r\nfrom"),
|
||||
)),
|
||||
array('...', array(
|
||||
array(Parser::T_ELLIPSIS, '...'),
|
||||
)),
|
||||
|
@ -1,4 +1,4 @@
|
||||
Generators (yield expression
|
||||
Generators (yield expression)
|
||||
-----
|
||||
<?php
|
||||
|
||||
@ -25,6 +25,10 @@ function gen() {
|
||||
func(yield $foo);
|
||||
$foo->func(yield $foo);
|
||||
new Foo(yield $foo);
|
||||
|
||||
yield from $foo;
|
||||
yield from $foo and yield from $bar;
|
||||
yield from $foo + $bar;
|
||||
}
|
||||
-----
|
||||
array(
|
||||
@ -226,6 +230,33 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
15: Expr_YieldFrom(
|
||||
expr: Expr_Variable(
|
||||
name: foo
|
||||
)
|
||||
)
|
||||
16: Expr_BinaryOp_LogicalAnd(
|
||||
left: Expr_YieldFrom(
|
||||
expr: Expr_Variable(
|
||||
name: foo
|
||||
)
|
||||
)
|
||||
right: Expr_YieldFrom(
|
||||
expr: Expr_Variable(
|
||||
name: bar
|
||||
)
|
||||
)
|
||||
)
|
||||
17: Expr_YieldFrom(
|
||||
expr: Expr_BinaryOp_Plus(
|
||||
left: Expr_Variable(
|
||||
name: foo
|
||||
)
|
||||
right: Expr_Variable(
|
||||
name: bar
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -33,6 +33,9 @@ $a ** $b ** $c;
|
||||
($a ** $b) ** $c;
|
||||
-1 ** 2;
|
||||
|
||||
yield from $a and yield from $b;
|
||||
yield from ($a and yield from $b);
|
||||
|
||||
// The following will currently add unnecessary parentheses, because the pretty printer is not aware that assignment
|
||||
// and incdec only work on variables.
|
||||
!$a = $b;
|
||||
@ -62,6 +65,8 @@ $a + $b++;
|
||||
$a ** $b ** $c;
|
||||
($a ** $b) ** $c;
|
||||
-1 ** 2;
|
||||
yield from $a and yield from $b;
|
||||
yield from ($a and yield from $b);
|
||||
// The following will currently add unnecessary parentheses, because the pretty printer is not aware that assignment
|
||||
// and incdec only work on variables.
|
||||
!($a = $b);
|
||||
|
Loading…
x
Reference in New Issue
Block a user