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
811const LIB = '(?(DEFINE)
912 (?<singleQuotedString> \'[^ \\\\\']*+(?: \\\\.[^ \\\\\']*+)*+ \')
1417) ' ;
1518
1619const PARAMS = '\[(?<params>[^[\]]*+(?:\[(?¶ms)\][^[\]]*+)*+)\] ' ;
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 ' ;
2932echo "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 );
3340file_put_contents ($ tmpGrammarFile , $ grammarCode );
3441
3946
4047function 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
5864function 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
6472function 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+ */
105117function 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+ */
117132function 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 }
0 commit comments