Skip to content

Commit f0515a7

Browse files
committed
Exclude grammar directory from export
Also statically analyze and format the rebuild parser script, and report memory usage in the benchmark.
1 parent ad5cd89 commit f0515a7

7 files changed

Lines changed: 61 additions & 41 deletions

File tree

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/.github/ export-ignore
2+
/grammar/ export-ignore
23
/tests/ export-ignore
34
/.editorconfig export-ignore
45
/.gitattributes export-ignore

.php-cs-fixer.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
$finder = PhpCsFixer\Finder::create()
44
->path([
5+
'grammar/',
56
'src/',
67
'tests/',
78
])

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"friendsofphp/php-cs-fixer": "^3.95",
2424
"ircmaxell/php-yacc": "^0.0.8",
2525
"jbboehr/handlebars-spec": "dev-master",
26-
"phpstan/phpstan": "^2.1.51",
26+
"phpstan/phpstan": "^2.1.54",
2727
"phpunit/phpunit": "^11.5"
2828
},
2929
"autoload": {

composer.lock

Lines changed: 23 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

grammar/rebuildParser.php

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
* Code based on https://github.com/nikic/PHP-Parser/blob/master/grammar/rebuildParsers.php
55
* by Nikita Popov.
66
*/
7+
if (!isset($argv)) {
8+
exit("This script must be run from the command line");
9+
}
710

811
const LIB = '(?(DEFINE)
912
(?<singleQuotedString>\'[^\\\\\']*+(?:\\\\.[^\\\\\']*+)*+\')
@@ -14,10 +17,10 @@
1417
)';
1518

1619
const PARAMS = '\[(?<params>[^[\]]*+(?:\[(?&params)\][^[\]]*+)*+)\]';
17-
const ARGS = '\((?<args>[^()]*+(?:\((?&args)\)[^()]*+)*+)\)';
20+
const ARGS = '\((?<args>[^()]*+(?:\((?&args)\)[^()]*+)*+)\)';
1821

19-
$grammarFile = __DIR__ . '/handlebars.y';
20-
$skeletonFile = __DIR__ . '/parser.template';
22+
$grammarFile = __DIR__ . '/handlebars.y';
23+
$skeletonFile = __DIR__ . '/parser.template';
2124
$tmpGrammarFile = __DIR__ . '/tmp_parser.phpy';
2225
$resultDir = __DIR__ . '/../src';
2326
$kmyacc = __DIR__ . '/../vendor/bin/phpyacc';
@@ -29,6 +32,10 @@
2932
echo "Building Handlebars parser.\n";
3033

3134
$grammarCode = file_get_contents($grammarFile);
35+
if ($grammarCode === false) {
36+
exit("Failed to load $grammarFile");
37+
}
38+
3239
$grammarCode = preprocessGrammar($grammarCode);
3340
file_put_contents($tmpGrammarFile, $grammarCode);
3441

@@ -39,7 +46,7 @@
3946

4047
function execCmd(string $cmd): string
4148
{
42-
$output = trim(shell_exec("$cmd 2>&1") ?? '');
49+
$output = trim(shell_exec("$cmd 2>&1") ?: '');
4350
if ($output !== "") {
4451
echo "> " . $cmd . "\n";
4552
echo $output;
@@ -51,14 +58,15 @@ function preprocessGrammar(string $code): string
5158
{
5259
$code = resolveMacros($code);
5360
$code = resolveStackAccess($code);
54-
$code = str_replace('$this', '$self', $code);
55-
return $code;
61+
return str_replace('$this', '$self', $code);
5662
}
5763

5864
function resolveStackAccess(string $code): string
5965
{
60-
$code = preg_replace('/\$\d+/', '$this->semStack[$0]', $code);
61-
return preg_replace('/#(\d+)/', '$$1', $code);
66+
$code = preg_replace('/\$\d+/', '$this->semStack[$0]', $code)
67+
?? throw new Exception('Failed to replace pattern with $this->semStack[$0]');
68+
return preg_replace('/#(\d+)/', '$$1', $code)
69+
?? throw new Exception('Failed to replace pattern with $$1');
6270
}
6371

6472
function resolveMacros(string $code): string
@@ -72,7 +80,7 @@ function ($matches) {
7280
$name = $matches['name'];
7381
$args = magicSplit(
7482
'(?:' . PARAMS . '|' . ARGS . ')(*SKIP)(*FAIL)|,',
75-
$matches['args']
83+
$matches['args'],
7684
);
7785

7886
if ('locInfo' === $name) {
@@ -98,10 +106,14 @@ function ($matches) {
98106

99107
return $matches[0];
100108
},
101-
$code
102-
);
109+
$code,
110+
)
111+
?? throw new Exception('Failed to replace pattern with callback');
103112
}
104113

114+
/**
115+
* @param list<string> $args
116+
*/
105117
function assertArgs(int $num, array $args, string $name): void
106118
{
107119
if ($num !== count($args)) {
@@ -114,10 +126,17 @@ function regex(string $regex): string
114126
return '~' . LIB . '(?:' . str_replace('~', '\~', $regex) . ')~';
115127
}
116128

129+
/**
130+
* @return list<string>
131+
*/
117132
function magicSplit(string $regex, string $string): array
118133
{
119134
$pieces = preg_split(regex('(?:(?&string)|(?&comment)|(?&code))(*SKIP)(*FAIL)|' . $regex), $string);
120135

136+
if ($pieces === false) {
137+
throw new Exception("Failed to split string $string");
138+
}
139+
121140
foreach ($pieces as &$piece) {
122141
$piece = trim($piece);
123142
}

phpstan.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
parameters:
22
level: 9
33
paths:
4+
- grammar
45
- src
56
- tests

tests/benchmark.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,11 @@
3333
}
3434

3535
$elapsed = (hrtime(true) - $start) / 1e9;
36-
$perParse = $elapsed / $iterations * 1000;
37-
$templateBytes = strlen($template);
36+
$peakMemory = memory_get_peak_usage();
3837

3938
printf(
40-
"Parsed %d times in %.3f s | %.3f ms/parse | %.1f KB template\n",
39+
"Parsed %d times | %.2f ms/parse | %.1f MB peak memory\n",
4140
$iterations,
42-
$elapsed,
43-
$perParse,
44-
$templateBytes / 1024,
41+
$elapsed / $iterations * 1000,
42+
$peakMemory / 1024 / 1024,
4543
);

0 commit comments

Comments
 (0)