Skip to content

Commit 3870cd6

Browse files
committed
WIP: Parsica parse TemplateLiteralNode
All ExpressionParser tests are green
1 parent fc5fbf7 commit 3870cd6

File tree

5 files changed

+101
-30
lines changed

5 files changed

+101
-30
lines changed

src/Parser/Ast/TemplateLiteralNode.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ final class TemplateLiteralNode implements \JsonSerializable
3535
*/
3636
public readonly array $segments;
3737

38-
private function __construct(
38+
public function __construct(
3939
StringLiteralNode|ExpressionNode ...$segments
4040
) {
4141
$this->segments = $segments;

src/Parser/Parser/Expression/ExpressionParser.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
use PackageFactory\ComponentEngine\Parser\Parser\PrecedenceParser;
3535
use PackageFactory\ComponentEngine\Parser\Parser\StringLiteral\StringLiteralParser;
3636
use PackageFactory\ComponentEngine\Parser\Parser\Tag\TagParser;
37+
use PackageFactory\ComponentEngine\Parser\Parser\TemplateLiteral\TemplateLiteralParser;
3738
use PackageFactory\ComponentEngine\Parser\Parser\TernaryOperation\TernaryOperationParser;
3839
use PackageFactory\ComponentEngine\Parser\Parser\UnaryOperation\UnaryOperationParser;
3940
use Parsica\Parsica\Parser;
@@ -53,6 +54,7 @@ public static function get(Precedence $precedence = Precedence::SEQUENCE): Parse
5354
TagParser::get(),
5455
StringLiteralParser::get(),
5556
IdentifierParser::get(),
57+
TemplateLiteralParser::get(),
5658
UnaryOperationParser::get()
5759
));
5860

src/Parser/Parser/StringLiteral/StringLiteralParser.php

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,9 @@
2323
namespace PackageFactory\ComponentEngine\Parser\Parser\StringLiteral;
2424

2525
use PackageFactory\ComponentEngine\Parser\Ast\StringLiteralNode;
26+
use PackageFactory\ComponentEngine\Parser\Parser\UtilityParser;
2627
use Parsica\Parsica\Parser;
2728

28-
use function Parsica\Parsica\{anySingle, append, between, char, assemble, either, takeWhile, zeroOrMore};
29-
3029
final class StringLiteralParser
3130
{
3231
private static ?Parser $instance = null;
@@ -38,32 +37,6 @@ public static function get(): Parser
3837

3938
private static function build(): Parser
4039
{
41-
// labels, and escaping handling
42-
// also maybe use bind with the start character instead of two parsers
43-
return either(
44-
self::forQuotedStringType('\''),
45-
self::forQuotedStringType('"')
46-
)->map(fn (string $contents) => new StringLiteralNode($contents));
47-
}
48-
49-
private static function forQuotedStringType(string $qouteType): Parser
50-
{
51-
assert($qouteType === '"' || $qouteType === '\'');
52-
$takeAllNonBackslashesAndQuoteChars = takeWhile(
53-
fn (string $char): bool => $char !== $qouteType && $char !== '\\'
54-
);
55-
return between(
56-
char($qouteType),
57-
char($qouteType),
58-
append(
59-
$takeAllNonBackslashesAndQuoteChars,
60-
zeroOrMore(
61-
append(
62-
char("\\")->followedBy(anySingle()),
63-
$takeAllNonBackslashesAndQuoteChars,
64-
)
65-
)
66-
)
67-
);
40+
return UtilityParser::quotedStringContents()->map(fn (string $contents) => new StringLiteralNode($contents));
6841
}
6942
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
/**
4+
* PackageFactory.ComponentEngine - Universal View Components for PHP
5+
* Copyright (C) 2022 Contributors of PackageFactory.ComponentEngine
6+
*
7+
* This program is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
*/
20+
21+
declare(strict_types=1);
22+
23+
namespace PackageFactory\ComponentEngine\Parser\Parser\TemplateLiteral;
24+
25+
use PackageFactory\ComponentEngine\Parser\Ast\StringLiteralNode;
26+
use PackageFactory\ComponentEngine\Parser\Ast\TemplateLiteralNode;
27+
use PackageFactory\ComponentEngine\Parser\Parser\Expression\ExpressionParser;
28+
use Parsica\Parsica\Parser;
29+
30+
use function Parsica\Parsica\any;
31+
use function Parsica\Parsica\char;
32+
use function Parsica\Parsica\string;
33+
use function Parsica\Parsica\takeWhile1;
34+
use function Parsica\Parsica\zeroOrMore;
35+
36+
final class TemplateLiteralParser
37+
{
38+
private static ?Parser $instance = null;
39+
40+
public static function get(): Parser
41+
{
42+
return self::$instance ??= self::build();
43+
}
44+
45+
private static function build(): Parser
46+
{
47+
return char('`')->bind(
48+
fn () => zeroOrMore(
49+
any(
50+
self::stringLiteral(),
51+
self::expression(),
52+
)->map(fn ($item) => [$item])
53+
)->map(fn ($collected) => new TemplateLiteralNode(...$collected ? $collected : []))
54+
->thenIgnore(char('`'))
55+
);
56+
}
57+
58+
private static function expression(): Parser
59+
{
60+
return string('${')->followedBy(ExpressionParser::get())->thenIgnore(char('}'));
61+
}
62+
63+
private static function stringLiteral(): Parser
64+
{
65+
// @todo escapes? or allow `single unescaped $ dollar?`
66+
return takeWhile1(fn ($char) => $char !== '$' && $char !== '`')->map(fn ($text) => new StringLiteralNode($text));
67+
}
68+
}

src/Parser/Parser/UtilityParser.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,36 @@
2828
use Parsica\Parsica\ParseResult;
2929
use Parsica\Parsica\Stream;
3030

31+
use function Parsica\Parsica\anySingle;
32+
use function Parsica\Parsica\append;
33+
use function Parsica\Parsica\char;
34+
use function Parsica\Parsica\oneOfS;
35+
use function Parsica\Parsica\takeWhile;
36+
use function Parsica\Parsica\zeroOrMore;
37+
3138
final class UtilityParser
3239
{
40+
/**
41+
* @return Parser<string>
42+
*/
43+
public static function quotedStringContents(): Parser
44+
{
45+
// labels, and escaping handling
46+
return oneOfS('"\'')->bind(
47+
fn (string $startingQuoteChar) => append(
48+
$simpleCase = takeWhile(
49+
fn (string $char): bool => $char !== $startingQuoteChar && $char !== '\\'
50+
),
51+
zeroOrMore(
52+
append(
53+
char('\\')->followedBy(anySingle()),
54+
$simpleCase,
55+
)
56+
)
57+
)->thenIgnore(char($startingQuoteChar))
58+
);
59+
}
60+
3361
/**
3462
* A multi character compatible version (eg. for strings) of {@see oneOf()}
3563
*

0 commit comments

Comments
 (0)