Skip to content

Commit 1176ddd

Browse files
committed
Handle let keyword
1 parent 8bd3a87 commit 1176ddd

File tree

4 files changed

+70
-4
lines changed

4 files changed

+70
-4
lines changed

phpunit.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<testsuites>
1010
<testsuite name="render">
1111
<file>tests/render.php</file>
12+
<file>tests/handleLet.php</file>
1213
</testsuite>
1314
<testsuite name="compile">
1415
<file>tests/compile.php</file>
@@ -28,7 +29,7 @@
2829
<testsuite name="array">
2930
<file>tests/array.php</file>
3031
</testsuite>
31-
<testsuite name="badSyntaxes">
32+
<testsuite name="errors">
3233
<file>tests/badSyntaxes.php</file>
3334
<file>tests/badSwitchSyntaxes.php</file>
3435
<file>tests/badKeywordSyntaxes.php</file>

src/JsPhpize/Nodes/Block.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ public function let($variable)
5656
$this->letVariables[] = $variable;
5757
}
5858

59+
public function letAfter()
60+
{
61+
62+
}
63+
5964
public function getLetVariables()
6065
{
6166
$scope = $this;
@@ -107,6 +112,7 @@ public function addInstructions($instructions)
107112
$this->inInstruction = true;
108113
$this->instructions[] = new Instruction();
109114
}
115+
110116
foreach ($instructions as $instruction) {
111117
$this->instructions[count($this->instructions) - 1]->add($instruction);
112118
}
@@ -140,16 +146,21 @@ public function enableMultipleInstructions()
140146
public function getReadVariables()
141147
{
142148
$variables = $this->value->getReadVariables();
149+
143150
foreach ($this->instructions as $instruction) {
144151
$variables = array_merge($variables, $instruction->getReadVariables());
145152
}
153+
146154
$variables = array_unique($variables);
155+
147156
if ($this->type === 'function') {
148157
$nodes = isset($this->value, $this->value->nodes) ? $this->value->nodes : [];
158+
149159
if (count($nodes)) {
150160
$nodes = array_map(function ($node) {
151161
return $node instanceof Variable ? $node->name : null;
152162
}, $nodes);
163+
153164
$variables = array_filter($variables, function ($variable) use ($nodes) {
154165
return !in_array($variable, $nodes);
155166
});

src/JsPhpize/Parser/Parser.php

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use JsPhpize\Nodes\FunctionCall;
1212
use JsPhpize\Nodes\HooksArray;
1313
use JsPhpize\Nodes\Main;
14+
use JsPhpize\Nodes\Node;
1415
use JsPhpize\Nodes\Parenthesis;
1516
use JsPhpize\Nodes\Ternary;
1617
use JsPhpize\Nodes\Value;
@@ -33,6 +34,11 @@ class Parser extends TokenExtractor
3334
*/
3435
protected $stack;
3536

37+
/**
38+
* @var Node|null
39+
*/
40+
protected $letForNextBlock;
41+
3642
public function __construct(JsPhpize $engine, $input, $filename)
3743
{
3844
$input = str_replace(["\r\n", "\r"], ["\n", ''], $input);
@@ -71,6 +77,7 @@ protected function parseParentheses($allowedSeparators = [',', ';'])
7177
while ($token = $this->next()) {
7278
if ($token->is(')')) {
7379
$next = $this->get(0);
80+
7481
if ($next && $next->type === 'lambda') {
7582
$this->skip();
7683

@@ -106,9 +113,9 @@ protected function parseParentheses($allowedSeparators = [',', ';'])
106113

107114
if ($token->type === 'keyword' && $token->valueIn(['var', 'const', 'let'])) {
108115
// @TODO handle let scope here
109-
// if ($token->value === 'let') {
110-
// $this->letForNextBlock = $this->parseLet();
111-
// }
116+
if ($token->value === 'let') {
117+
$this->letForNextBlock = $this->parseLet();
118+
}
112119

113120
continue;
114121
}
@@ -204,6 +211,7 @@ protected function parseFunctionCallChildren($function, $applicant = null)
204211
$children[] = $value;
205212

206213
$next = $this->get(0);
214+
207215
if ($next && $next->is('(')) {
208216
$this->skip();
209217

@@ -238,6 +246,7 @@ protected function parseVariable($name)
238246
$children[] = $value;
239247

240248
$next = $this->get(0);
249+
241250
if ($next && $next->is('(')) {
242251
$this->skip();
243252

@@ -257,6 +266,7 @@ protected function parseVariable($name)
257266

258267
for ($i = count($this->stack) - 1; $i >= 0; $i--) {
259268
$block = $this->stack[$i];
269+
260270
if ($block->isLet($name)) {
261271
$variable->setScope($block);
262272

@@ -272,6 +282,7 @@ protected function parseTernary(Value $condition)
272282
{
273283
$trueValue = $this->expectValue($this->next());
274284
$next = $this->next();
285+
275286
if (!$next) {
276287
throw new Exception("Ternary expression not properly closed after '?' " . $this->exceptionInfos(), 14);
277288
}
@@ -281,6 +292,7 @@ protected function parseTernary(Value $condition)
281292
}
282293

283294
$next = $this->next();
295+
284296
if (!$next) {
285297
throw new Exception("Ternary expression not properly closed after ':' " . $this->exceptionInfos(), 16);
286298
}
@@ -294,6 +306,7 @@ protected function parseTernary(Value $condition)
294306
protected function jsonMethodToPhpFunction($method)
295307
{
296308
$function = null;
309+
297310
switch ($method) {
298311
case 'stringify':
299312
$function = 'json_encode';
@@ -310,6 +323,7 @@ protected function parseJsonMethod($method)
310323
{
311324
if ($method->type === 'variable' && ($function = $this->jsonMethodToPhpFunction($method->value))) {
312325
$this->skip(2);
326+
313327
if (($next = $this->get(0)) && $next->is('(')) {
314328
$this->skip();
315329

@@ -344,6 +358,7 @@ protected function parseFunction()
344358
$function = new Block('function');
345359
$function->enableMultipleInstructions();
346360
$token = $this->get(0);
361+
347362
if ($token && $token->type === 'variable') {
348363
$this->skip();
349364
$token = $this->get(0);
@@ -356,6 +371,7 @@ protected function parseFunction()
356371
$this->skip();
357372
$function->setValue($this->parseParentheses());
358373
$token = $this->get(0);
374+
359375
if ($token && !$token->is('{')) {
360376
throw $this->unexpected($token);
361377
}
@@ -370,6 +386,7 @@ protected function parseKeywordStatement($token)
370386
{
371387
$name = $token->value;
372388
$keyword = new Block($name);
389+
373390
switch ($name) {
374391
case 'typeof':
375392
throw new Exception('typeof keyword not supported', 26);
@@ -384,9 +401,11 @@ protected function parseKeywordStatement($token)
384401
'clone' => 'Object',
385402
];
386403
$value = $this->get(0);
404+
387405
if (isset($expects[$name]) && !$value) {
388406
throw new Exception($expects[$name] . " expected after '" . $name . "'", 25);
389407
}
408+
390409
$this->handleOptionalValue($keyword, $value, $name);
391410
break;
392411
case 'case':
@@ -407,6 +426,7 @@ protected function parseKeywordStatement($token)
407426
protected function parseKeyword($token)
408427
{
409428
$keyword = $this->parseKeywordStatement($token);
429+
410430
if ($keyword->handleInstructions()) {
411431
$this->parseBlock($keyword);
412432
}
@@ -417,6 +437,7 @@ protected function parseKeyword($token)
417437
protected function parseLet()
418438
{
419439
$letVariable = $this->get(0);
440+
420441
if ($letVariable->type !== 'variable') {
421442
throw $this->unexpected($letVariable);
422443
}
@@ -445,6 +466,7 @@ protected function parseInstruction($block, $token, &$initNext)
445466
if ($initNext && $instruction instanceof Variable) {
446467
$instruction = new Assignation('=', $instruction, new Constant('constant', 'null'));
447468
}
469+
448470
$initNext = false;
449471
$block->addInstruction($instruction);
450472

@@ -486,15 +508,24 @@ protected function parseInstructions($block)
486508
public function parseBlock($block)
487509
{
488510
$this->stack[] = $block;
511+
489512
if (!$block->multipleInstructions) {
490513
$next = $this->get(0);
514+
491515
if ($next && $next->is('{')) {
492516
$block->enableMultipleInstructions();
493517
}
518+
494519
if ($block->multipleInstructions) {
495520
$this->skip();
496521
}
497522
}
523+
524+
if ($this->letForNextBlock) {
525+
$block->letAfter($this->letForNextBlock);
526+
$this->letForNextBlock = null;
527+
}
528+
498529
$this->parseInstructions($block);
499530
array_pop($this->stack);
500531
}

tests/handleLet.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
use JsPhpize\JsPhpize;
4+
use PHPUnit\Framework\TestCase;
5+
6+
class RuntimeErrorsTest extends TestCase
7+
{
8+
/**
9+
* @group i
10+
*/
11+
public function testNoParenthesesClose()
12+
{
13+
$jsPhpize = new JsPhpize();
14+
$this->assertSame('8 // 22', $jsPhpize->renderCode('let n = 1;
15+
let i = 22;
16+
17+
for (let i = 0; i < 3; i++) {
18+
n *= 2;
19+
}
20+
21+
return n + \' // \' + i;'));
22+
}
23+
}

0 commit comments

Comments
 (0)