Skip to content

Commit 52ef73a

Browse files
committed
Fix single-quoted string parsing and compiling
1 parent 1d07213 commit 52ef73a

File tree

9 files changed

+37
-28
lines changed

9 files changed

+37
-28
lines changed

src/Compiler.php

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ public static function compileTemplate(Context $context, string $template): stri
2323
return '';
2424
}
2525

26-
Token::setDelimiter($context);
27-
2826
$context->compile = true;
2927

3028
// Handle dynamic partials
@@ -36,7 +34,7 @@ public static function compileTemplate(Context $context, string $template): stri
3634
if (is_array($info)) {
3735
$code .= "'" . static::compileToken($context, $info) . "'";
3836
} else {
39-
$code .= $info;
37+
$code .= addcslashes($info, "'");
4038
}
4139
}
4240

@@ -120,7 +118,7 @@ protected static function getVariableNames(Context $context, array $vn, array $b
120118
}
121119
$exps[] = $V[1];
122120
}
123-
$bp = $blockParams ? (',[' . Expression::listString($blockParams) . ']') : '';
121+
$bp = $blockParams ? ',' . Expression::listString($blockParams) : '';
124122
return ['[[' . implode(',', $vars[0]) . '],[' . implode(',', $vars[1]) . "]$bp]", $exps];
125123
}
126124

@@ -253,7 +251,7 @@ protected static function compileToken(Context $context, array $info): string
253251
*
254252
* @param array<mixed> $vars parsed arguments list
255253
*/
256-
public static function partial(Context $context, array $vars): string
254+
public static function partial(Context $context, array &$vars): string
257255
{
258256
Parser::getBlockParams($vars);
259257
$pid = Parser::getPartialBlock($vars);
@@ -266,7 +264,7 @@ public static function partial(Context $context, array $vars): string
266264
if (Parser::isSubExp($p)) {
267265
[$p] = static::compileSubExpression($context, $p[1]);
268266
} else {
269-
$p = "'$p[0]'";
267+
$p = Expression::quoteString($p[0]);
270268
}
271269
$sp = "(\$sp ?? '') . '{$context->partialIndent}'";
272270
return $context->separator .
@@ -400,7 +398,7 @@ protected static function section(Context $context, array $vars, bool $isEach =
400398
$be = '';
401399
if ($isEach) {
402400
$bp = Parser::getBlockParams($vars);
403-
$bs = $bp ? ('array(' . Expression::listString($bp) . ')') : 'null';
401+
$bs = $bp ? Expression::listString($bp) : 'null';
404402
$be = $bp ? (' as |' . implode(' ', $bp) . '|') : '';
405403
array_shift($vars);
406404
}
@@ -421,7 +419,7 @@ protected static function with(Context $context, array $vars)
421419
{
422420
$v = isset($vars[1]) ? static::getVariableNameOrSubExpression($context, $vars[1]) : [null, []];
423421
$bp = Parser::getBlockParams($vars);
424-
$bs = $bp ? ('[' . Expression::listString($bp) . ']') : 'null';
422+
$bs = $bp ? Expression::listString($bp) : 'null';
425423
$be = $bp ? " as |$bp[0]|" : '';
426424
return $context->separator . static::getFuncName($context, 'wi', 'with ' . $v[1] . $be)
427425
. "\$cx, {$v[0]}, $bs, \$in, function(\$cx, \$in) {{$context->fStart}";

src/Expression.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ final class Expression
1414
*/
1515
public static function listString(array $list): string
1616
{
17-
return implode(',', array_map(static fn($v) => "'$v'", $list));
17+
return '[' . implode(',', array_map(static fn($v) => "'$v'", $list)) . ']';
1818
}
1919

2020
/**
@@ -24,7 +24,12 @@ public static function listString(array $list): string
2424
*/
2525
public static function arrayString(array $list): string
2626
{
27-
return implode('', array_map(static fn($v) => "['$v']", $list));
27+
return implode('', array_map(static fn($v) => "[" . self::quoteString($v) . "]", $list));
28+
}
29+
30+
public static function quoteString(string $string): string
31+
{
32+
return "'" . addcslashes($string, "'") . "'";
2833
}
2934

3035
/**

src/Parser.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public static function getBlockParams(array &$vars): array
5555
*/
5656
protected static function getLiteral(string $name, bool $asis, bool $quote = false): array
5757
{
58-
return $asis ? [$name] : [static::LITERAL, $quote ? "'$name'" : $name];
58+
return $asis ? [$name] : [static::LITERAL, $quote ? Expression::quoteString($name) : $name];
5959
}
6060

6161
/**
@@ -81,8 +81,9 @@ protected static function getExpression(string $v, Context $context, int|string
8181
}
8282

8383
// handle single quoted string
84-
if (preg_match('/^\\\\\'(.*)\\\\\'$/', $v, $matched)) {
85-
return static::getLiteral($matched[1], $asis, true);
84+
if (preg_match("/^'(.*)'$/", $v, $matched)) {
85+
$literal = str_replace("\\\\'", "'", $matched[1]);
86+
return static::getLiteral($literal, $asis, true);
8687
}
8788

8889
// handle bool, null and undefined
@@ -250,7 +251,7 @@ protected static function advancedVariable(array $vars, Context $context, string
250251
}
251252
}
252253

253-
if (!preg_match("/^(\"|\\\\')(.*)(\"|\\\\')$/", $var)) {
254+
if (!preg_match("/^([\"'])(.*)([\"'])$/", $var)) {
254255
// foo] Rule 1: no starting [ or [ not start from head
255256
if (preg_match('/^[^\\[.]+[\\[\\]]/', $var)
256257
// [bar Rule 2: no ending ] or ] not in the end

src/Partial.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public static function compileDynamic(Context $context, string $name): ?string
7171
$func = static::compile($context, $context->usedPartial[$name], $name);
7272

7373
if (!isset($context->partialCode[$name]) && $func) {
74-
$context->partialCode[$name] = "'$name' => $func";
74+
$context->partialCode[$name] = Expression::quoteString($name) . " => $func";
7575
}
7676

7777
return $func;

src/SafeString.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,6 @@ public static function stripExtendedComments(string $template): string
3939
*/
4040
public static function escapeTemplate(string $template): string
4141
{
42-
return addcslashes(addcslashes($template, '\\'), "'");
42+
return addcslashes($template, '\\');
4343
}
4444
}

src/Validator.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -713,16 +713,17 @@ protected static function inline(Context $context, array $vars)
713713
/**
714714
* validate partial
715715
*
716-
* @param array<bool|int|string|array<mixed>> $vars parsed arguments list
716+
* @param array<array<mixed>> $vars parsed arguments list
717717
*
718718
* @return int|bool Return 1 or larger number for runtime partial, return true for other case
719719
*/
720-
protected static function partial(Context $context, array $vars)
720+
protected static function partial(Context $context, array &$vars)
721721
{
722722
if (Parser::isSubExp($vars[0])) {
723723
return $context->usedDynPartial++;
724724
} else {
725725
if ($context->currentToken[Token::POS_OP] !== '#>') {
726+
$vars[0][0] = preg_replace("/^'(.*)'$/", '$1', $vars[0][0]);
726727
Partial::read($context, $vars[0][0]);
727728
}
728729
}

tests/ExpressionTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ class ExpressionTest extends TestCase
99
{
1010
public function testListString(): void
1111
{
12-
$this->assertSame('', Expression::listString([]));
13-
$this->assertSame("'a'", Expression::listString(['a']));
14-
$this->assertSame("'a','b','c'", Expression::listString(['a', 'b', 'c']));
12+
$this->assertSame('[]', Expression::listString([]));
13+
$this->assertSame("['a']", Expression::listString(['a']));
14+
$this->assertSame("['a','b','c']", Expression::listString(['a', 'b', 'c']));
1515
}
1616

1717
public function testArrayString(): void

tests/RegressionTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,6 +1345,17 @@ public static function issueProvider(): array
13451345
),
13461346
'expected' => '&quot;&quot;&quot; &quot;&quot;&quot;',
13471347
],
1348+
[
1349+
'template' => "{{test '\'\'\'' prop='\'\'\''}}",
1350+
'options' => new Options(
1351+
helpers: [
1352+
'test' => function ($arg1, HelperOptions $options) {
1353+
return "{$arg1} {$options->hash['prop']}";
1354+
},
1355+
],
1356+
),
1357+
'expected' => '&#x27;&#x27;&#x27; &#x27;&#x27;&#x27;',
1358+
],
13481359

13491360
[
13501361
'id' => 302,

tests/SafeStringTest.php

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,4 @@ public function testStripExtendedComments(): void
1313
$this->assertSame('abc{{!}}cde', SafeString::stripExtendedComments('abc{{!}}cde'));
1414
$this->assertSame('abc{{! }}cde', SafeString::stripExtendedComments('abc{{!----}}cde'));
1515
}
16-
17-
public function testEscapeTemplate(): void
18-
{
19-
$this->assertSame('abc', SafeString::escapeTemplate('abc'));
20-
$this->assertSame('a\\\\bc', SafeString::escapeTemplate('a\bc'));
21-
$this->assertSame('a\\\'bc', SafeString::escapeTemplate('a\'bc'));
22-
}
2316
}

0 commit comments

Comments
 (0)