Skip to content

Commit 574f3c8

Browse files
committed
Converting To Use Local Variable Instead of Static Variable
1 parent ab31770 commit 574f3c8

File tree

4 files changed

+163
-30
lines changed

4 files changed

+163
-30
lines changed

src/Backend/Backend.php

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace Zephir\Backend;
1515

16+
use Zephir\Class\Definition\Definition;
1617
use Zephir\Class\Method\Method;
1718
use Zephir\Code\Printer;
1819
use Zephir\CompilationContext;
@@ -24,6 +25,7 @@
2425
use Zephir\FunctionDefinition;
2526
use Zephir\GlobalConstant;
2627
use Zephir\Name;
28+
use Zephir\StatementsBlock;
2729
use Zephir\Variable\Globals;
2830
use Zephir\Variable\Variable;
2931

@@ -866,13 +868,42 @@ public function copyOnWrite(Variable $target, $var, CompilationContext $context)
866868
}
867869
}
868870

869-
public function createClosure(Variable $variable, $classDefinition, CompilationContext $context): void
871+
public function createClosure(Variable $variable, Definition $classDefinition, CompilationContext $context, array $conArgs): void
870872
{
871-
$symbol = $this->getVariableCode($variable);
872-
$context->codePrinter->output(
873-
'zephir_create_closure_ex(' . $symbol . ', NULL, ' . $classDefinition->getClassEntry(
874-
) . ', SL("__invoke"));'
875-
);
873+
$parameters = [];
874+
foreach ($conArgs as $arg) {
875+
$parameters[] = [
876+
"parameter" => [
877+
'type' => $arg['data-type'],
878+
'value' => $arg['name'],
879+
]
880+
];
881+
}
882+
883+
$statementBlocks = [
884+
[
885+
'type' => 'let',
886+
'assignments' => [
887+
[
888+
'assign-type' => 'variable',
889+
'operator' => 'assign',
890+
'variable' => $variable->getName(),
891+
'expr' => [
892+
"type" => "new",
893+
"class" => "\\" . $classDefinition->getCompleteName(),
894+
"dynamic" => 0,
895+
"parameters" => $parameters,
896+
'file' => '',
897+
'line' => 0,
898+
'char' => 0
899+
]
900+
]
901+
]
902+
]
903+
];
904+
905+
$block = new StatementsBlock($statementBlocks);
906+
$block->compile($context);
876907
}
877908

878909
public function declareConstant($type, $name, $value, CompilationContext $context): void
@@ -1871,29 +1902,34 @@ public function updateArray(
18711902

18721903
public function updateProperty(Variable $variable, $property, $value, CompilationContext $context): void
18731904
{
1874-
$value = $this->resolveValue($value, $context);
1875-
18761905
if ($property instanceof Variable) {
18771906
$context->codePrinter->output(
18781907
sprintf(
18791908
'zephir_update_property_zval_zval(%s, %s, %s);',
18801909
$this->getVariableCode($variable),
18811910
$this->getVariableCode($property),
1882-
$value
1911+
$this->resolveValue($value, $context)
18831912
)
18841913
);
18851914

18861915
return;
18871916
}
18881917

1918+
$this->updateRawProperty($this->getVariableCode($variable), $property, $value, $context);
1919+
}
1920+
1921+
public function updateRawProperty(string $variableName, $property, $value, CompilationContext $context): void
1922+
{
18891923
$template = 'zephir_update_property_zval(%s, ZEND_STRL("%s"), %s);';
18901924
/* Are we going to init default object property value? */
18911925
if ($context->currentMethod && $context->currentMethod->isInitializer()) {
18921926
$template = 'zephir_update_property_zval_ex(%s, ZEND_STRL("%s"), %s);';
18931927
}
18941928

1929+
$value = $this->resolveValue($value, $context);
1930+
18951931
$context->codePrinter->output(
1896-
sprintf($template, $this->getVariableCode($variable), $property, $value)
1932+
sprintf($template, $variableName, $property, $value)
18971933
);
18981934
}
18991935

src/Expression/Closure.php

Lines changed: 104 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -80,26 +80,61 @@ public function compile(array $expression, CompilationContext $compilationContex
8080

8181
$block = $expression['right'] ?? [];
8282

83-
$staticVariables = [];
83+
$useVariables = [];
84+
8485
if (isset($expression['use']) && is_array($expression['use'])) {
8586
foreach ($expression['use'] as $parameter) {
86-
$staticVariables[$parameter['name']] = $compilationContext->symbolTable->getVariable(
87+
$useVariables[$parameter['name']] = $compilationContext->symbolTable->getVariable(
8788
$parameter['name']
8889
);
8990
}
9091
}
9192

92-
foreach ($staticVariables as $var) {
93+
foreach ($useVariables as $var) {
9394
$classDefinition->addProperty(
9495
new Property(
9596
$classDefinition,
96-
['public', 'static'],
97+
['public'],
9798
$var->getName(),
9899
null,
99100
null,
100101
null
101102
)
102103
);
104+
105+
array_unshift(
106+
$block,
107+
[
108+
'type' => 'declare',
109+
'data-type' => 'variable',
110+
'variables' => [
111+
[
112+
'variable' => $var->getName()
113+
]
114+
]
115+
],
116+
[
117+
'type' => 'let',
118+
'assignments' => [
119+
[
120+
'assign-type' => 'variable',
121+
'operator' => 'assign',
122+
'variable' => $var->getName(),
123+
'expr' => [
124+
'type' => 'property-access',
125+
'left' => [
126+
'type' => 'variable',
127+
'value' => 'this',
128+
],
129+
'right' => [
130+
'type' => 'variable',
131+
'value' => $var->getName(),
132+
]
133+
]
134+
]
135+
]
136+
]
137+
);
103138
}
104139

105140
$classMethod = new Method(
@@ -111,7 +146,6 @@ public function compile(array $expression, CompilationContext $compilationContex
111146
null,
112147
null,
113148
$expression,
114-
$staticVariables
115149
);
116150

117151
$symbolVariable = $this->generateClosure(
@@ -123,14 +157,68 @@ public function compile(array $expression, CompilationContext $compilationContex
123157
);
124158
$compilationContext->headersManager->add('kernel/object');
125159

126-
foreach ($staticVariables as $var) {
160+
//Only Compile Them If They Exist
161+
if (count($useVariables)) {
162+
$classDefinition->addMethod($this->buildConstructor($classDefinition, $expression['use']));
163+
$this->compileVariables($compilationContext, $symbolVariable, $useVariables);
164+
}
165+
166+
++self::$id;
167+
168+
return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
169+
}
170+
171+
private function buildConstructor(Definition $classDefinition, array $useProperties): Method
172+
{
173+
$useStatements = [];
174+
175+
foreach ($useProperties as $property) {
176+
$useStatements[] = [
177+
'type' => 'let',
178+
'assignments' => [
179+
[
180+
'assign-type' => 'variable',
181+
'operator' => 'assign',
182+
'variable' => $property['name'],
183+
'expr' => [
184+
'type' => 'property-access',
185+
'left' => [
186+
'type' => 'variable',
187+
'value' => 'this',
188+
],
189+
'right' => [
190+
'type' => 'variable',
191+
'value' => $property['name'],
192+
]
193+
]
194+
]
195+
]
196+
];
197+
}
198+
199+
return new Method(
200+
$classDefinition,
201+
['public', 'final'],
202+
'__construct',
203+
new Parameters($useProperties),
204+
new StatementsBlock($useStatements),
205+
null,
206+
null,
207+
[],
208+
);
209+
}
210+
211+
private function compileVariables(CompilationContext $compilationContext, Variable $symbolVariable, array $useVariables): void
212+
{
213+
foreach ($useVariables as $var) {
127214
if (in_array($var->getType(), ['variable', 'array'])) {
128-
$compilationContext->backend->updateStaticProperty(
129-
$classDefinition->getClassEntry(),
215+
$compilationContext->backend->updateRawProperty(
216+
$symbolVariable->getName(),
130217
$var->getName(),
131218
$var,
132219
$compilationContext
133220
);
221+
134222
continue;
135223
}
136224

@@ -162,17 +250,13 @@ public function compile(array $expression, CompilationContext $compilationContex
162250
break;
163251
}
164252

165-
$compilationContext->backend->updateStaticProperty(
166-
$classDefinition->getClassEntry(),
253+
$compilationContext->backend->updateRawProperty(
254+
$symbolVariable->getName(),
167255
$var->getName(),
168256
$tempVariable,
169257
$compilationContext
170258
);
171259
}
172-
173-
++self::$id;
174-
175-
return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
176260
}
177261

178262
/**
@@ -213,8 +297,6 @@ protected function generateClosure(
213297
): ?Variable {
214298
$classDefinition->addMethod($classMethod, $block);
215299

216-
$compilationContext->headersManager->add('kernel/object');
217-
218300
if ($this->expecting) {
219301
if ($this->expectingVariable) {
220302
$symbolVariable = $this->expectingVariable;
@@ -234,7 +316,12 @@ protected function generateClosure(
234316
}
235317

236318
$symbolVariable->initVariant($compilationContext);
237-
$compilationContext->backend->createClosure($symbolVariable, $classDefinition, $compilationContext);
319+
$compilationContext->backend->createClosure(
320+
$symbolVariable,
321+
$classDefinition,
322+
$compilationContext,
323+
$expression['use'] ?? []
324+
);
238325

239326
return $symbolVariable;
240327
}

stub/closures.zep

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,8 @@ class Closures
5252
return x => (x + 100) + (x * 150);
5353
}
5454

55-
public function testUseCommand()
55+
public function testUseCommand(var abc = 1)
5656
{
57-
var abc = 1;
5857
return function() use (abc) {
5958
return abc + 1;
6059
};

tests/Extension/ClosureTest.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,21 @@ public function testUseCommand(): void
2222
{
2323
$test = new Closures();
2424

25-
$this->assertSame(2, $test->testUseCommand()());
25+
$this->assertSame(2, $test->testUseCommand(1)());
2626
$this->assertInstanceOf(\stdClass::class, $test->issue642());
2727
}
2828

29+
public function testUseCommandMultiple(): void
30+
{
31+
$test = new Closures();
32+
33+
$callbackA = $test->testUseCommand(1);
34+
$callbackB = $test->testUseCommand(2);
35+
36+
$this->assertSame(2, $callbackA());
37+
$this->assertSame(3, $callbackB());
38+
}
39+
2940
/**
3041
* @issue https://github.com/zephir-lang/zephir/issues/1036
3142
*/

0 commit comments

Comments
 (0)