Skip to content
This repository was archived by the owner on Sep 9, 2019. It is now read-only.

Commit 9380233

Browse files
committed
Merge pull request #45 from xp-lang/fix/lambda-uses-explicit
Make capturing explicit when using the PHP lambda form
2 parents e0f63f3 + ec8cf7a commit 9380233

File tree

5 files changed

+1169
-1148
lines changed

5 files changed

+1169
-1148
lines changed

src/main/jay/grammars/php.jay

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -662,8 +662,8 @@ expression:
662662
| '@' expression {
663663
$$= $yyLex->create(new SilenceOperatorNode($2));
664664
}
665-
| T_FUNCTION '(' lambda_input ')' '{' statements_opt '}' {
666-
$$= $yyLex->create(new LambdaNode($3, (array)$6));
665+
| T_FUNCTION '(' lambda_input ')' lambda_uses_opt '{' statements_opt '}' {
666+
$$= $yyLex->create(new LambdaNode($3, (array)$7, $5));
667667
}
668668
| '(' expression ')' chain_opt {
669669
if ($4) {
@@ -689,6 +689,11 @@ lambda_input_parameter:
689689
T_VARIABLE initialization_opt { $$= array('name' => $1); $2 && $$['default']= $2; }
690690
;
691691

692+
lambda_uses_opt:
693+
/* empty */ { $$= array(); }
694+
| T_USE '(' lambda_input_parameters ')' { $$= $3; }
695+
;
696+
692697
literal:
693698
scalar
694699
| T_ARRAY '(' { $p= $yyLex->position; } map_or_list ')' { $4->position= $p; $4->type= NULL; $$= $4; }

src/main/php/xp/compiler/ast/LambdaNode.class.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@
66
class LambdaNode extends Node {
77
public $parameters;
88
public $statements;
9+
public $uses;
910

1011
/**
1112
* Constructor
1213
*
1314
* @param xp.compiler.ast.Node[] parameters
1415
* @param xp.compiler.ast.Node[] statements
16+
* @param xp.compiler.ast.Node[] uses
1517
*/
16-
public function __construct(array $parameters, array $statements) {
18+
public function __construct(array $parameters, array $statements, $uses= null) {
1719
$this->parameters= $parameters;
1820
$this->statements= $statements;
21+
$this->uses= $uses;
1922
}
2023
}

src/main/php/xp/compiler/emit/php/V54Emitter.class.php

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -212,17 +212,6 @@ protected function emitArm($b, $arm) {
212212
*/
213213
protected function emitLambda($b, $lambda) {
214214

215-
// Capture all local variables and parameters of containing scope which
216-
// are also used inside the lambda by value.
217-
$finder= new \xp\compiler\ast\LocalVariableFinder();
218-
foreach ($finder->variablesIn((array)$this->scope[0]->routine->body) as $variable) {
219-
$finder->including($variable);
220-
}
221-
foreach ($this->scope[0]->routine->parameters as $param) {
222-
$finder->including($param['name']);
223-
}
224-
$finder->excluding('*');
225-
226215
// Parameters
227216
$b->append('function(');
228217
$s= sizeof($lambda->parameters)- 1;
@@ -236,8 +225,24 @@ protected function emitLambda($b, $lambda) {
236225
}
237226
$b->append(')');
238227

239-
// Use variables
240-
if ($capture= $finder->variablesIn($lambda->statements)) {
228+
// If not explicitely stated: Capture all local variables and parameters of
229+
// containing scope which are also used inside the lambda by value.
230+
if (null === $lambda->uses) {
231+
$finder= new \xp\compiler\ast\LocalVariableFinder();
232+
foreach ($finder->variablesIn((array)$this->scope[0]->routine->body) as $variable) {
233+
$finder->including($variable);
234+
}
235+
foreach ($this->scope[0]->routine->parameters as $param) {
236+
$finder->including($param['name']);
237+
}
238+
$finder->excluding('*');
239+
240+
// Use variables
241+
if ($capture= $finder->variablesIn($lambda->statements)) {
242+
$b->append(' use($')->append(implode(', $', $capture))->append(')');
243+
}
244+
} else if ($lambda->uses) {
245+
$capture= array_map(function($var) { return $var->name; }, $lambda->uses);
241246
$b->append(' use($')->append(implode(', $', $capture))->append(')');
242247
}
243248

0 commit comments

Comments
 (0)