1<?php
2
3
4
5
6/* File-scope initializer */
7namespace Wikimedia\Parsoid\ParserTests;
8
9use Wikimedia\Parsoid\Utils\PHPUtils;
10
11
12class Grammar extends \WikiPEG\PEGParserBase {
13  // initializer
14
15  	/** @var string */
16  	private $filename = '';
17  	/** @var int */
18  	private $lineNum = 1;
19
20  	/**
21  	 * @param string $filename
22  	 * @return array
23  	 */
24  	public static function load( string $filename ) {
25  		$g = new Grammar();
26  		$g->filename = $filename;
27  		$contents = file_get_contents( $filename ) ?: '';
28  		if ( substr( $contents, -1 ) !== "\n" ) {
29  			# ensure that the file is terminated with a newline
30  			# to match `end_section` rule (and other uses of `eol`)
31  			$contents .= "\n";
32  		}
33  		return $g->parse( $contents );
34  	}
35
36
37  // cache init
38
39
40  // expectations
41  protected $expectations = [
42    0 => ["type" => "end", "description" => "end of input"],
43    1 => ["type" => "literal", "value" => "!!", "description" => "\"!!\""],
44    2 => ["type" => "class", "value" => "[0-9]", "description" => "[0-9]"],
45    3 => ["type" => "class", "value" => "[ \\t]", "description" => "[ \\t]"],
46    4 => ["type" => "class", "value" => "[vV]", "description" => "[vV]"],
47    5 => ["type" => "class", "value" => "[eE]", "description" => "[eE]"],
48    6 => ["type" => "class", "value" => "[rR]", "description" => "[rR]"],
49    7 => ["type" => "class", "value" => "[sS]", "description" => "[sS]"],
50    8 => ["type" => "class", "value" => "[iI]", "description" => "[iI]"],
51    9 => ["type" => "class", "value" => "[oO]", "description" => "[oO]"],
52    10 => ["type" => "class", "value" => "[nN]", "description" => "[nN]"],
53    11 => ["type" => "class", "value" => "[^\\n]", "description" => "[^\\n]"],
54    12 => ["type" => "literal", "value" => "options", "description" => "\"options\""],
55    13 => ["type" => "literal", "value" => "end", "description" => "\"end\""],
56    14 => ["type" => "literal", "value" => "\x0a", "description" => "\"\\n\""],
57    15 => ["type" => "literal", "value" => "#", "description" => "\"#\""],
58    16 => ["type" => "literal", "value" => "article", "description" => "\"article\""],
59    17 => ["type" => "literal", "value" => "text", "description" => "\"text\""],
60    18 => ["type" => "literal", "value" => "endarticle", "description" => "\"endarticle\""],
61    19 => ["type" => "literal", "value" => "test", "description" => "\"test\""],
62    20 => ["type" => "class", "value" => "[^ \\t\\r\\n]", "description" => "[^ \\t\\r\\n]"],
63    21 => ["type" => "literal", "value" => "hooks", "description" => "\"hooks\""],
64    22 => ["type" => "literal", "value" => ":", "description" => "\":\""],
65    23 => ["type" => "literal", "value" => "endhooks", "description" => "\"endhooks\""],
66    24 => ["type" => "literal", "value" => "functionhooks", "description" => "\"functionhooks\""],
67    25 => ["type" => "literal", "value" => "endfunctionhooks", "description" => "\"endfunctionhooks\""],
68    26 => ["type" => "class", "value" => "[^ \\t\\n=!]", "description" => "[^ \\t\\n=!]"],
69    27 => ["type" => "literal", "value" => "=", "description" => "\"=\""],
70    28 => ["type" => "literal", "value" => ",", "description" => "\",\""],
71    29 => ["type" => "literal", "value" => "[[", "description" => "\"[[\""],
72    30 => ["type" => "class", "value" => "[^\\]\\n]", "description" => "[^\\]\\n]"],
73    31 => ["type" => "literal", "value" => "]]", "description" => "\"]]\""],
74    32 => ["type" => "class", "value" => "[\\\"]", "description" => "[\\\"]"],
75    33 => ["type" => "class", "value" => "[^\\\\\\\"\\n]", "description" => "[^\\\\\\\"\\n]"],
76    34 => ["type" => "literal", "value" => "\\", "description" => "\"\\\\\""],
77    35 => ["type" => "class", "value" => "[^ \\t\\n\\\"\\'\\[\\]=,!\\{]", "description" => "[^ \\t\\n\\\"\\'\\[\\]=,!\\{]"],
78    36 => ["type" => "literal", "value" => "{", "description" => "\"{\""],
79    37 => ["type" => "class", "value" => "[^\\\"\\{\\}\\n]", "description" => "[^\\\"\\{\\}\\n]"],
80    38 => ["type" => "literal", "value" => "}", "description" => "\"}\""],
81  ];
82
83  // actions
84  private function a0($v) {
85
86  		return [ 'type' => 'version', 'text' => $v ];
87
88  }
89  private function a1($sec) {
90
91  	return $sec['text'];
92
93  }
94  private function a2() {
95   return $this->lineNum;
96  }
97  private function a3($l, $c) {
98
99  	$c['filename'] = $this->filename;
100  	$c['lineNumStart'] = $l;
101  	$c['lineNumEnd'] = $this->lineNum;
102  	return $c;
103
104  }
105  private function a4($c) {
106
107  	return implode($c);
108
109  }
110  private function a5($opts) {
111
112  	$o = [];
113  	if ( $opts && count($opts) > 0 ) {
114  		foreach ( $opts as $opt ) {
115  			$o[$opt['k']] = $opt['v'];
116  		}
117  	}
118
119  	return [ 'name' => 'options', 'text' => $o ];
120
121  }
122  private function a6($l) {
123   return [ 'type' => 'line', 'text' => $l ];
124  }
125  private function a7($nl) {
126   $this->lineNum++; return $nl;
127  }
128  private function a8($o, $rest) {
129
130  	$result = [ $o ];
131  	if ( $rest && count( $rest ) > 0 ) {
132  		$result = array_merge( $result, $rest );
133  	}
134  	return $result;
135
136  }
137  private function a9($text) {
138   return [ 'type' => 'comment', 'text' => $text ];
139  }
140  private function a10($title, $text) {
141
142  	return [
143  		'type' => 'article',
144  		'title' => $title,
145  		'text' => $text
146  	];
147
148  }
149  private function a11($testName, $sections) {
150
151  	$test = [
152  		'type' => 'test',
153  		'testName' => $testName
154  	];
155
156  	foreach ( $sections as $section ) {
157  		$test[$section['name']] = $section['text'];
158  	}
159  	// pegjs parser handles item options as follows:
160  	//   item option             value of item.options.parsoid
161  	//    <none>                          undefined
162  	//    parsoid                             ""
163  	//    parsoid=wt2html                  "wt2html"
164  	//    parsoid=wt2html,wt2wt        ["wt2html","wt2wt"]
165  	//    parsoid={"modes":["wt2wt"]}    {modes:['wt2wt']}
166
167  	// treat 'parsoid=xxx,yyy' in options section as shorthand for
168  	// 'parsoid={modes:["xxx","yyy"]}'
169  	if ( isset($test['options']['parsoid'] ) ) {
170  		if ($test['options']['parsoid'] === '') {
171  			$test['options']['parsoid'] = [];
172  		}
173  		if ( is_string( $test['options']['parsoid'] ) ) {
174  			$test['options']['parsoid'] = [ $test['options']['parsoid'] ];
175  		}
176  		if ( is_array( $test['options']['parsoid'] ) &&
177  			isset( $test['options']['parsoid'][0] ) &&
178  			!isset( $test['options']['parsoid']['modes'] )
179  		) {
180  			$test['options']['parsoid'] = [ 'modes' => $test['options']['parsoid'] ];
181  		}
182  	}
183  	return $test;
184
185  }
186  private function a12($line) {
187
188  	return $line;
189
190  }
191  private function a13($text) {
192
193  	return [ 'type' => 'hooks', 'text' => $text ];
194
195  }
196  private function a14($text) {
197
198  	return [ 'type' => 'functionhooks', 'text' => $text ];
199
200  }
201  private function a15($k, $v) {
202
203  	return [ 'k' => strtolower( $k ), 'v' => $v ?? '' ];
204
205  }
206  private function a16($lines) {
207
208  	return implode("\n", $lines);
209
210  }
211  private function a17($c) {
212   return implode( $c );
213  }
214  private function a18($name, $text) {
215
216  	return [ 'name' => $name, 'text' => $text ];
217
218  }
219  private function a19($ovl) {
220
221  	return count( $ovl ) === 1 ? $ovl[0] : $ovl;
222
223  }
224  private function a20($v, $ovl) {
225   return $ovl;
226  }
227  private function a21($v, $rest) {
228
229  	$result = [ $v ];
230  	if ( $rest && count( $rest ) > 0 ) {
231  		$result = array_merge( $result, $rest );
232  	}
233  	return $result;
234
235  }
236  private function a22($v) {
237
238  	if ( $v[0] === '"' || $v[0] === '{' ) { // } is needed to make pegjs happy
239  		return PHPUtils::jsonDecode( $v );
240  	}
241  	return $v;
242
243  }
244  private function a23($v) {
245
246  	// Perhaps we should canonicalize the title?
247  	// Protect with JSON.stringify just in case the link target starts with
248  	// double-quote or open-brace.
249  	return PHPUtils::jsonEncode( implode( $v ) );
250
251  }
252  private function a24($c) {
253   return "\\" . $c;
254  }
255  private function a25($v) {
256
257  	return '"' . implode( $v ) . '"';
258
259  }
260  private function a26($v) {
261
262  	return implode( $v );
263
264  }
265  private function a27($v) {
266
267  	return "{" . implode( $v ) . "}";
268
269  }
270
271  // generated
272  private function parsetestfile($silence) {
273    // start seq_1
274    $p1 = $this->currPos;
275    $r3 = $this->parseformat($silence);
276    if ($r3===self::$FAILED) {
277      $r3 = null;
278    }
279    $r4 = $this->parsetestfile_options($silence);
280    if ($r4===self::$FAILED) {
281      $r4 = null;
282    }
283    $r5 = [];
284    for (;;) {
285      $r6 = $this->parselined_chunk($silence);
286      if ($r6!==self::$FAILED) {
287        $r5[] = $r6;
288      } else {
289        break;
290      }
291    }
292    if (count($r5) === 0) {
293      $r5 = self::$FAILED;
294    }
295    if ($r5===self::$FAILED) {
296      $this->currPos = $p1;
297      $r2 = self::$FAILED;
298      goto seq_1;
299    }
300    // free $r6
301    $r2 = [$r3,$r4,$r5];
302    seq_1:
303    // free $r2,$p1
304    return $r2;
305  }
306  private function parseformat($silence) {
307    $p2 = $this->currPos;
308    // start seq_1
309    $p3 = $this->currPos;
310    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "!!", $this->currPos, 2, false) === 0) {
311      $r4 = "!!";
312      $this->currPos += 2;
313    } else {
314      if (!$silence) {$this->fail(1);}
315      $r4 = self::$FAILED;
316      $r1 = self::$FAILED;
317      goto seq_1;
318    }
319    $r5 = $this->discardwhitespace($silence);
320    if ($r5===self::$FAILED) {
321      $r5 = null;
322    }
323    $r6 = $this->discardversion_keyword($silence);
324    if ($r6===self::$FAILED) {
325      $this->currPos = $p3;
326      $r1 = self::$FAILED;
327      goto seq_1;
328    }
329    $r7 = self::$FAILED;
330    for (;;) {
331      $r8 = $this->discardwhitespace($silence);
332      if ($r8!==self::$FAILED) {
333        $r7 = true;
334      } else {
335        break;
336      }
337    }
338    if ($r7===self::$FAILED) {
339      $this->currPos = $p3;
340      $r1 = self::$FAILED;
341      goto seq_1;
342    }
343    // free $r8
344    $p9 = $this->currPos;
345    $r8 = self::$FAILED;
346    for (;;) {
347      $r10 = $this->input[$this->currPos] ?? '';
348      if (preg_match("/^[0-9]/", $r10)) {
349        $this->currPos++;
350        $r8 = true;
351      } else {
352        $r10 = self::$FAILED;
353        if (!$silence) {$this->fail(2);}
354        break;
355      }
356    }
357    // v <- $r8
358    if ($r8!==self::$FAILED) {
359      $r8 = substr($this->input, $p9, $this->currPos - $p9);
360    } else {
361      $r8 = self::$FAILED;
362      $this->currPos = $p3;
363      $r1 = self::$FAILED;
364      goto seq_1;
365    }
366    // free $r10
367    // free $p9
368    $r10 = $this->discardrest_of_line($silence);
369    if ($r10===self::$FAILED) {
370      $this->currPos = $p3;
371      $r1 = self::$FAILED;
372      goto seq_1;
373    }
374    $r1 = true;
375    seq_1:
376    if ($r1!==self::$FAILED) {
377      $this->savedPos = $p2;
378      $r1 = $this->a0($r8);
379    }
380    // free $p3
381    return $r1;
382  }
383  private function parsetestfile_options($silence) {
384    $p2 = $this->currPos;
385    // start seq_1
386    $p3 = $this->currPos;
387    $r4 = $this->parseoption_section($silence);
388    // sec <- $r4
389    if ($r4===self::$FAILED) {
390      $r1 = self::$FAILED;
391      goto seq_1;
392    }
393    $r5 = $this->discardend_section($silence);
394    if ($r5===self::$FAILED) {
395      $this->currPos = $p3;
396      $r1 = self::$FAILED;
397      goto seq_1;
398    }
399    $r1 = true;
400    seq_1:
401    if ($r1!==self::$FAILED) {
402      $this->savedPos = $p2;
403      $r1 = $this->a1($r4);
404    }
405    // free $p3
406    return $r1;
407  }
408  private function parselined_chunk($silence) {
409    $p2 = $this->currPos;
410    // start seq_1
411    $p3 = $this->currPos;
412    $p5 = $this->currPos;
413    $r4 = '';
414    // l <- $r4
415    if ($r4!==self::$FAILED) {
416      $this->savedPos = $p5;
417      $r4 = $this->a2();
418    } else {
419      $r1 = self::$FAILED;
420      goto seq_1;
421    }
422    $r6 = $this->parsechunk($silence);
423    // c <- $r6
424    if ($r6===self::$FAILED) {
425      $this->currPos = $p3;
426      $r1 = self::$FAILED;
427      goto seq_1;
428    }
429    $r1 = true;
430    seq_1:
431    if ($r1!==self::$FAILED) {
432      $this->savedPos = $p2;
433      $r1 = $this->a3($r4, $r6);
434    }
435    // free $p3
436    return $r1;
437  }
438  private function discardwhitespace($silence) {
439    $r1 = self::$FAILED;
440    for (;;) {
441      $r2 = $this->input[$this->currPos] ?? '';
442      if ($r2 === " " || $r2 === "\x09") {
443        $this->currPos++;
444        $r1 = true;
445      } else {
446        $r2 = self::$FAILED;
447        if (!$silence) {$this->fail(3);}
448        break;
449      }
450    }
451    // free $r2
452    return $r1;
453  }
454  private function discardversion_keyword($silence) {
455    // start seq_1
456    $p1 = $this->currPos;
457    $r3 = $this->input[$this->currPos] ?? '';
458    if ($r3 === "v" || $r3 === "V") {
459      $this->currPos++;
460    } else {
461      $r3 = self::$FAILED;
462      if (!$silence) {$this->fail(4);}
463      $r2 = self::$FAILED;
464      goto seq_1;
465    }
466    $r4 = $this->input[$this->currPos] ?? '';
467    if ($r4 === "e" || $r4 === "E") {
468      $this->currPos++;
469    } else {
470      $r4 = self::$FAILED;
471      if (!$silence) {$this->fail(5);}
472      $this->currPos = $p1;
473      $r2 = self::$FAILED;
474      goto seq_1;
475    }
476    $r5 = $this->input[$this->currPos] ?? '';
477    if ($r5 === "r" || $r5 === "R") {
478      $this->currPos++;
479    } else {
480      $r5 = self::$FAILED;
481      if (!$silence) {$this->fail(6);}
482      $this->currPos = $p1;
483      $r2 = self::$FAILED;
484      goto seq_1;
485    }
486    $r6 = $this->input[$this->currPos] ?? '';
487    if ($r6 === "s" || $r6 === "S") {
488      $this->currPos++;
489    } else {
490      $r6 = self::$FAILED;
491      if (!$silence) {$this->fail(7);}
492      $this->currPos = $p1;
493      $r2 = self::$FAILED;
494      goto seq_1;
495    }
496    $r7 = $this->input[$this->currPos] ?? '';
497    if ($r7 === "i" || $r7 === "I") {
498      $this->currPos++;
499    } else {
500      $r7 = self::$FAILED;
501      if (!$silence) {$this->fail(8);}
502      $this->currPos = $p1;
503      $r2 = self::$FAILED;
504      goto seq_1;
505    }
506    $r8 = $this->input[$this->currPos] ?? '';
507    if ($r8 === "o" || $r8 === "O") {
508      $this->currPos++;
509    } else {
510      $r8 = self::$FAILED;
511      if (!$silence) {$this->fail(9);}
512      $this->currPos = $p1;
513      $r2 = self::$FAILED;
514      goto seq_1;
515    }
516    $r9 = $this->input[$this->currPos] ?? '';
517    if ($r9 === "n" || $r9 === "N") {
518      $this->currPos++;
519    } else {
520      $r9 = self::$FAILED;
521      if (!$silence) {$this->fail(10);}
522      $this->currPos = $p1;
523      $r2 = self::$FAILED;
524      goto seq_1;
525    }
526    $r2 = true;
527    seq_1:
528    // free $r2,$p1
529    return $r2;
530  }
531  private function discardrest_of_line($silence) {
532    $p2 = $this->currPos;
533    // start seq_1
534    $p3 = $this->currPos;
535    $r4 = [];
536    for (;;) {
537      $r5 = self::charAt($this->input, $this->currPos);
538      if ($r5 !== '' && !($r5 === "\x0a")) {
539        $this->currPos += strlen($r5);
540        $r4[] = $r5;
541      } else {
542        $r5 = self::$FAILED;
543        if (!$silence) {$this->fail(11);}
544        break;
545      }
546    }
547    // c <- $r4
548    // free $r5
549    $r5 = $this->discardeol($silence);
550    if ($r5===self::$FAILED) {
551      $this->currPos = $p3;
552      $r1 = self::$FAILED;
553      goto seq_1;
554    }
555    $r1 = true;
556    seq_1:
557    if ($r1!==self::$FAILED) {
558      $this->savedPos = $p2;
559      $r1 = $this->a4($r4);
560    }
561    // free $p3
562    return $r1;
563  }
564  private function parseoption_section($silence) {
565    $p2 = $this->currPos;
566    // start seq_1
567    $p3 = $this->currPos;
568    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "!!", $this->currPos, 2, false) === 0) {
569      $r4 = "!!";
570      $this->currPos += 2;
571    } else {
572      if (!$silence) {$this->fail(1);}
573      $r4 = self::$FAILED;
574      $r1 = self::$FAILED;
575      goto seq_1;
576    }
577    $r5 = $this->discardwhitespace($silence);
578    if ($r5===self::$FAILED) {
579      $r5 = null;
580    }
581    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "options", $this->currPos, 7, false) === 0) {
582      $r6 = "options";
583      $this->currPos += 7;
584    } else {
585      if (!$silence) {$this->fail(12);}
586      $r6 = self::$FAILED;
587      $this->currPos = $p3;
588      $r1 = self::$FAILED;
589      goto seq_1;
590    }
591    $r7 = $this->discardwhitespace($silence);
592    if ($r7===self::$FAILED) {
593      $r7 = null;
594    }
595    $r8 = $this->discardeol($silence);
596    if ($r8===self::$FAILED) {
597      $this->currPos = $p3;
598      $r1 = self::$FAILED;
599      goto seq_1;
600    }
601    $r9 = $this->parseoption_list($silence);
602    if ($r9===self::$FAILED) {
603      $r9 = null;
604    }
605    // opts <- $r9
606    $r1 = true;
607    seq_1:
608    if ($r1!==self::$FAILED) {
609      $this->savedPos = $p2;
610      $r1 = $this->a5($r9);
611    }
612    // free $p3
613    return $r1;
614  }
615  private function discardend_section($silence) {
616    // start seq_1
617    $p1 = $this->currPos;
618    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "!!", $this->currPos, 2, false) === 0) {
619      $r3 = "!!";
620      $this->currPos += 2;
621    } else {
622      if (!$silence) {$this->fail(1);}
623      $r3 = self::$FAILED;
624      $r2 = self::$FAILED;
625      goto seq_1;
626    }
627    $r4 = $this->discardwhitespace($silence);
628    if ($r4===self::$FAILED) {
629      $r4 = null;
630    }
631    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "end", $this->currPos, 3, false) === 0) {
632      $r5 = "end";
633      $this->currPos += 3;
634    } else {
635      if (!$silence) {$this->fail(13);}
636      $r5 = self::$FAILED;
637      $this->currPos = $p1;
638      $r2 = self::$FAILED;
639      goto seq_1;
640    }
641    $r6 = $this->discardwhitespace($silence);
642    if ($r6===self::$FAILED) {
643      $r6 = null;
644    }
645    $r7 = $this->discardeol($silence);
646    if ($r7===self::$FAILED) {
647      $this->currPos = $p1;
648      $r2 = self::$FAILED;
649      goto seq_1;
650    }
651    $r2 = true;
652    seq_1:
653    // free $r2,$p1
654    return $r2;
655  }
656  private function parsechunk($silence) {
657    // start choice_1
658    $r1 = $this->parsecomment($silence);
659    if ($r1!==self::$FAILED) {
660      goto choice_1;
661    }
662    $r1 = $this->parsearticle($silence);
663    if ($r1!==self::$FAILED) {
664      goto choice_1;
665    }
666    $r1 = $this->parsetest($silence);
667    if ($r1!==self::$FAILED) {
668      goto choice_1;
669    }
670    $p2 = $this->currPos;
671    $r3 = $this->parseline($silence);
672    // l <- $r3
673    $r1 = $r3;
674    if ($r1!==self::$FAILED) {
675      $this->savedPos = $p2;
676      $r1 = $this->a6($r3);
677      goto choice_1;
678    }
679    $r1 = $this->parsehooks($silence);
680    if ($r1!==self::$FAILED) {
681      goto choice_1;
682    }
683    $r1 = $this->parsefunctionhooks($silence);
684    choice_1:
685    return $r1;
686  }
687  private function discardeol($silence) {
688    $p2 = $this->currPos;
689    // nl <- $r3
690    if (($this->input[$this->currPos] ?? null) === "\x0a") {
691      $this->currPos++;
692      $r3 = "\x0a";
693    } else {
694      if (!$silence) {$this->fail(14);}
695      $r3 = self::$FAILED;
696    }
697    $r1 = $r3;
698    if ($r1!==self::$FAILED) {
699      $this->savedPos = $p2;
700      $r1 = $this->a7($r3);
701    }
702    return $r1;
703  }
704  private function parseoption_list($silence) {
705    $p2 = $this->currPos;
706    // start seq_1
707    $p3 = $this->currPos;
708    $r4 = $this->parsean_option($silence);
709    // o <- $r4
710    if ($r4===self::$FAILED) {
711      $r1 = self::$FAILED;
712      goto seq_1;
713    }
714    $r5 = self::$FAILED;
715    for (;;) {
716      // start choice_1
717      $r6 = $this->input[$this->currPos] ?? '';
718      if ($r6 === " " || $r6 === "\x09") {
719        $this->currPos++;
720        goto choice_1;
721      } else {
722        $r6 = self::$FAILED;
723        if (!$silence) {$this->fail(3);}
724      }
725      $r6 = $this->discardeol($silence);
726      choice_1:
727      if ($r6!==self::$FAILED) {
728        $r5 = true;
729      } else {
730        break;
731      }
732    }
733    if ($r5===self::$FAILED) {
734      $this->currPos = $p3;
735      $r1 = self::$FAILED;
736      goto seq_1;
737    }
738    // free $r6
739    $r6 = $this->parseoption_list($silence);
740    if ($r6===self::$FAILED) {
741      $r6 = null;
742    }
743    // rest <- $r6
744    $r1 = true;
745    seq_1:
746    if ($r1!==self::$FAILED) {
747      $this->savedPos = $p2;
748      $r1 = $this->a8($r4, $r6);
749    }
750    // free $p3
751    return $r1;
752  }
753  private function parsecomment($silence) {
754    $p2 = $this->currPos;
755    // start seq_1
756    $p3 = $this->currPos;
757    if (($this->input[$this->currPos] ?? null) === "#") {
758      $this->currPos++;
759      $r4 = "#";
760    } else {
761      if (!$silence) {$this->fail(15);}
762      $r4 = self::$FAILED;
763      $r1 = self::$FAILED;
764      goto seq_1;
765    }
766    $r5 = $this->parserest_of_line($silence);
767    // text <- $r5
768    if ($r5===self::$FAILED) {
769      $this->currPos = $p3;
770      $r1 = self::$FAILED;
771      goto seq_1;
772    }
773    $r1 = true;
774    seq_1:
775    if ($r1!==self::$FAILED) {
776      $this->savedPos = $p2;
777      $r1 = $this->a9($r5);
778    }
779    // free $p3
780    return $r1;
781  }
782  private function parsearticle($silence) {
783    $p2 = $this->currPos;
784    // start seq_1
785    $p3 = $this->currPos;
786    $r4 = $this->discardstart_article($silence);
787    if ($r4===self::$FAILED) {
788      $r1 = self::$FAILED;
789      goto seq_1;
790    }
791    $r5 = $this->parseline($silence);
792    // title <- $r5
793    if ($r5===self::$FAILED) {
794      $this->currPos = $p3;
795      $r1 = self::$FAILED;
796      goto seq_1;
797    }
798    $r6 = $this->discardstart_text($silence);
799    if ($r6===self::$FAILED) {
800      $this->currPos = $p3;
801      $r1 = self::$FAILED;
802      goto seq_1;
803    }
804    $r7 = $this->parsetext($silence);
805    // text <- $r7
806    if ($r7===self::$FAILED) {
807      $this->currPos = $p3;
808      $r1 = self::$FAILED;
809      goto seq_1;
810    }
811    // start choice_1
812    $r8 = $this->discardend_article($silence);
813    if ($r8!==self::$FAILED) {
814      goto choice_1;
815    }
816    $r8 = $this->discardend_section($silence);
817    choice_1:
818    if ($r8===self::$FAILED) {
819      $this->currPos = $p3;
820      $r1 = self::$FAILED;
821      goto seq_1;
822    }
823    $r1 = true;
824    seq_1:
825    if ($r1!==self::$FAILED) {
826      $this->savedPos = $p2;
827      $r1 = $this->a10($r5, $r7);
828    }
829    // free $p3
830    return $r1;
831  }
832  private function parsetest($silence) {
833    $p2 = $this->currPos;
834    // start seq_1
835    $p3 = $this->currPos;
836    $r4 = $this->discardstart_test($silence);
837    if ($r4===self::$FAILED) {
838      $r1 = self::$FAILED;
839      goto seq_1;
840    }
841    $r5 = $this->parsetext($silence);
842    // testName <- $r5
843    if ($r5===self::$FAILED) {
844      $this->currPos = $p3;
845      $r1 = self::$FAILED;
846      goto seq_1;
847    }
848    $r6 = [];
849    for (;;) {
850      // start choice_1
851      $r7 = $this->parsesection($silence);
852      if ($r7!==self::$FAILED) {
853        goto choice_1;
854      }
855      $r7 = $this->parseoption_section($silence);
856      choice_1:
857      if ($r7!==self::$FAILED) {
858        $r6[] = $r7;
859      } else {
860        break;
861      }
862    }
863    // sections <- $r6
864    // free $r7
865    $r7 = $this->discardend_section($silence);
866    if ($r7===self::$FAILED) {
867      $this->currPos = $p3;
868      $r1 = self::$FAILED;
869      goto seq_1;
870    }
871    $r1 = true;
872    seq_1:
873    if ($r1!==self::$FAILED) {
874      $this->savedPos = $p2;
875      $r1 = $this->a11($r5, $r6);
876    }
877    // free $p3
878    return $r1;
879  }
880  private function parseline($silence) {
881    $p2 = $this->currPos;
882    // start seq_1
883    $p3 = $this->currPos;
884    $p4 = $this->currPos;
885    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "!!", $this->currPos, 2, false) === 0) {
886      $r5 = "!!";
887      $this->currPos += 2;
888    } else {
889      $r5 = self::$FAILED;
890    }
891    if ($r5 === self::$FAILED) {
892      $r5 = false;
893    } else {
894      $r5 = self::$FAILED;
895      $this->currPos = $p4;
896      $r1 = self::$FAILED;
897      goto seq_1;
898    }
899    // free $p4
900    $r6 = $this->parserest_of_line($silence);
901    // line <- $r6
902    if ($r6===self::$FAILED) {
903      $this->currPos = $p3;
904      $r1 = self::$FAILED;
905      goto seq_1;
906    }
907    $r1 = true;
908    seq_1:
909    if ($r1!==self::$FAILED) {
910      $this->savedPos = $p2;
911      $r1 = $this->a12($r6);
912    }
913    // free $p3
914    return $r1;
915  }
916  private function parsehooks($silence) {
917    $p2 = $this->currPos;
918    // start seq_1
919    $p3 = $this->currPos;
920    $r4 = $this->discardstart_hooks($silence);
921    if ($r4===self::$FAILED) {
922      $r1 = self::$FAILED;
923      goto seq_1;
924    }
925    $r5 = $this->parsetext($silence);
926    // text <- $r5
927    if ($r5===self::$FAILED) {
928      $this->currPos = $p3;
929      $r1 = self::$FAILED;
930      goto seq_1;
931    }
932    // start choice_1
933    $r6 = $this->discardend_hooks($silence);
934    if ($r6!==self::$FAILED) {
935      goto choice_1;
936    }
937    $r6 = $this->discardend_section($silence);
938    choice_1:
939    if ($r6===self::$FAILED) {
940      $this->currPos = $p3;
941      $r1 = self::$FAILED;
942      goto seq_1;
943    }
944    $r1 = true;
945    seq_1:
946    if ($r1!==self::$FAILED) {
947      $this->savedPos = $p2;
948      $r1 = $this->a13($r5);
949    }
950    // free $p3
951    return $r1;
952  }
953  private function parsefunctionhooks($silence) {
954    $p2 = $this->currPos;
955    // start seq_1
956    $p3 = $this->currPos;
957    $r4 = $this->discardstart_functionhooks($silence);
958    if ($r4===self::$FAILED) {
959      $r1 = self::$FAILED;
960      goto seq_1;
961    }
962    $r5 = $this->parsetext($silence);
963    // text <- $r5
964    if ($r5===self::$FAILED) {
965      $this->currPos = $p3;
966      $r1 = self::$FAILED;
967      goto seq_1;
968    }
969    // start choice_1
970    $r6 = $this->discardend_functionhooks($silence);
971    if ($r6!==self::$FAILED) {
972      goto choice_1;
973    }
974    $r6 = $this->discardend_section($silence);
975    choice_1:
976    if ($r6===self::$FAILED) {
977      $this->currPos = $p3;
978      $r1 = self::$FAILED;
979      goto seq_1;
980    }
981    $r1 = true;
982    seq_1:
983    if ($r1!==self::$FAILED) {
984      $this->savedPos = $p2;
985      $r1 = $this->a14($r5);
986    }
987    // free $p3
988    return $r1;
989  }
990  private function parsean_option($silence) {
991    $p2 = $this->currPos;
992    // start seq_1
993    $p3 = $this->currPos;
994    $r4 = $this->parseoption_name($silence);
995    // k <- $r4
996    if ($r4===self::$FAILED) {
997      $r1 = self::$FAILED;
998      goto seq_1;
999    }
1000    $r5 = $this->parseoption_value($silence);
1001    if ($r5===self::$FAILED) {
1002      $r5 = null;
1003    }
1004    // v <- $r5
1005    $r1 = true;
1006    seq_1:
1007    if ($r1!==self::$FAILED) {
1008      $this->savedPos = $p2;
1009      $r1 = $this->a15($r4, $r5);
1010    }
1011    // free $p3
1012    return $r1;
1013  }
1014  private function parserest_of_line($silence) {
1015    $p2 = $this->currPos;
1016    // start seq_1
1017    $p3 = $this->currPos;
1018    $r4 = [];
1019    for (;;) {
1020      $r5 = self::charAt($this->input, $this->currPos);
1021      if ($r5 !== '' && !($r5 === "\x0a")) {
1022        $this->currPos += strlen($r5);
1023        $r4[] = $r5;
1024      } else {
1025        $r5 = self::$FAILED;
1026        if (!$silence) {$this->fail(11);}
1027        break;
1028      }
1029    }
1030    // c <- $r4
1031    // free $r5
1032    $r5 = $this->discardeol($silence);
1033    if ($r5===self::$FAILED) {
1034      $this->currPos = $p3;
1035      $r1 = self::$FAILED;
1036      goto seq_1;
1037    }
1038    $r1 = true;
1039    seq_1:
1040    if ($r1!==self::$FAILED) {
1041      $this->savedPos = $p2;
1042      $r1 = $this->a4($r4);
1043    }
1044    // free $p3
1045    return $r1;
1046  }
1047  private function discardstart_article($silence) {
1048    // start seq_1
1049    $p1 = $this->currPos;
1050    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "!!", $this->currPos, 2, false) === 0) {
1051      $r3 = "!!";
1052      $this->currPos += 2;
1053    } else {
1054      if (!$silence) {$this->fail(1);}
1055      $r3 = self::$FAILED;
1056      $r2 = self::$FAILED;
1057      goto seq_1;
1058    }
1059    $r4 = $this->discardwhitespace($silence);
1060    if ($r4===self::$FAILED) {
1061      $r4 = null;
1062    }
1063    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "article", $this->currPos, 7, false) === 0) {
1064      $r5 = "article";
1065      $this->currPos += 7;
1066    } else {
1067      if (!$silence) {$this->fail(16);}
1068      $r5 = self::$FAILED;
1069      $this->currPos = $p1;
1070      $r2 = self::$FAILED;
1071      goto seq_1;
1072    }
1073    $r6 = $this->discardwhitespace($silence);
1074    if ($r6===self::$FAILED) {
1075      $r6 = null;
1076    }
1077    $r7 = $this->discardeol($silence);
1078    if ($r7===self::$FAILED) {
1079      $this->currPos = $p1;
1080      $r2 = self::$FAILED;
1081      goto seq_1;
1082    }
1083    $r2 = true;
1084    seq_1:
1085    // free $r2,$p1
1086    return $r2;
1087  }
1088  private function discardstart_text($silence) {
1089    // start seq_1
1090    $p1 = $this->currPos;
1091    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "!!", $this->currPos, 2, false) === 0) {
1092      $r3 = "!!";
1093      $this->currPos += 2;
1094    } else {
1095      if (!$silence) {$this->fail(1);}
1096      $r3 = self::$FAILED;
1097      $r2 = self::$FAILED;
1098      goto seq_1;
1099    }
1100    $r4 = $this->discardwhitespace($silence);
1101    if ($r4===self::$FAILED) {
1102      $r4 = null;
1103    }
1104    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "text", $this->currPos, 4, false) === 0) {
1105      $r5 = "text";
1106      $this->currPos += 4;
1107    } else {
1108      if (!$silence) {$this->fail(17);}
1109      $r5 = self::$FAILED;
1110      $this->currPos = $p1;
1111      $r2 = self::$FAILED;
1112      goto seq_1;
1113    }
1114    $r6 = $this->discardwhitespace($silence);
1115    if ($r6===self::$FAILED) {
1116      $r6 = null;
1117    }
1118    $r7 = $this->discardeol($silence);
1119    if ($r7===self::$FAILED) {
1120      $this->currPos = $p1;
1121      $r2 = self::$FAILED;
1122      goto seq_1;
1123    }
1124    $r2 = true;
1125    seq_1:
1126    // free $r2,$p1
1127    return $r2;
1128  }
1129  private function parsetext($silence) {
1130    $p2 = $this->currPos;
1131    $r3 = [];
1132    for (;;) {
1133      $r4 = $this->parseline($silence);
1134      if ($r4!==self::$FAILED) {
1135        $r3[] = $r4;
1136      } else {
1137        break;
1138      }
1139    }
1140    // lines <- $r3
1141    // free $r4
1142    $r1 = $r3;
1143    if ($r1!==self::$FAILED) {
1144      $this->savedPos = $p2;
1145      $r1 = $this->a16($r3);
1146    }
1147    return $r1;
1148  }
1149  private function discardend_article($silence) {
1150    // start seq_1
1151    $p1 = $this->currPos;
1152    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "!!", $this->currPos, 2, false) === 0) {
1153      $r3 = "!!";
1154      $this->currPos += 2;
1155    } else {
1156      if (!$silence) {$this->fail(1);}
1157      $r3 = self::$FAILED;
1158      $r2 = self::$FAILED;
1159      goto seq_1;
1160    }
1161    $r4 = $this->discardwhitespace($silence);
1162    if ($r4===self::$FAILED) {
1163      $r4 = null;
1164    }
1165    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "endarticle", $this->currPos, 10, false) === 0) {
1166      $r5 = "endarticle";
1167      $this->currPos += 10;
1168    } else {
1169      if (!$silence) {$this->fail(18);}
1170      $r5 = self::$FAILED;
1171      $this->currPos = $p1;
1172      $r2 = self::$FAILED;
1173      goto seq_1;
1174    }
1175    $r6 = $this->discardwhitespace($silence);
1176    if ($r6===self::$FAILED) {
1177      $r6 = null;
1178    }
1179    $r7 = $this->discardeol($silence);
1180    if ($r7===self::$FAILED) {
1181      $this->currPos = $p1;
1182      $r2 = self::$FAILED;
1183      goto seq_1;
1184    }
1185    $r2 = true;
1186    seq_1:
1187    // free $r2,$p1
1188    return $r2;
1189  }
1190  private function discardstart_test($silence) {
1191    // start seq_1
1192    $p1 = $this->currPos;
1193    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "!!", $this->currPos, 2, false) === 0) {
1194      $r3 = "!!";
1195      $this->currPos += 2;
1196    } else {
1197      if (!$silence) {$this->fail(1);}
1198      $r3 = self::$FAILED;
1199      $r2 = self::$FAILED;
1200      goto seq_1;
1201    }
1202    $r4 = $this->discardwhitespace($silence);
1203    if ($r4===self::$FAILED) {
1204      $r4 = null;
1205    }
1206    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "test", $this->currPos, 4, false) === 0) {
1207      $r5 = "test";
1208      $this->currPos += 4;
1209    } else {
1210      if (!$silence) {$this->fail(19);}
1211      $r5 = self::$FAILED;
1212      $this->currPos = $p1;
1213      $r2 = self::$FAILED;
1214      goto seq_1;
1215    }
1216    $r6 = $this->discardwhitespace($silence);
1217    if ($r6===self::$FAILED) {
1218      $r6 = null;
1219    }
1220    $r7 = $this->discardeol($silence);
1221    if ($r7===self::$FAILED) {
1222      $this->currPos = $p1;
1223      $r2 = self::$FAILED;
1224      goto seq_1;
1225    }
1226    $r2 = true;
1227    seq_1:
1228    // free $r2,$p1
1229    return $r2;
1230  }
1231  private function parsesection($silence) {
1232    $p2 = $this->currPos;
1233    // start seq_1
1234    $p3 = $this->currPos;
1235    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "!!", $this->currPos, 2, false) === 0) {
1236      $r4 = "!!";
1237      $this->currPos += 2;
1238    } else {
1239      if (!$silence) {$this->fail(1);}
1240      $r4 = self::$FAILED;
1241      $r1 = self::$FAILED;
1242      goto seq_1;
1243    }
1244    $r5 = $this->discardwhitespace($silence);
1245    if ($r5===self::$FAILED) {
1246      $r5 = null;
1247    }
1248    $p6 = $this->currPos;
1249    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "end", $this->currPos, 3, false) === 0) {
1250      $r7 = "end";
1251      $this->currPos += 3;
1252    } else {
1253      $r7 = self::$FAILED;
1254    }
1255    if ($r7 === self::$FAILED) {
1256      $r7 = false;
1257    } else {
1258      $r7 = self::$FAILED;
1259      $this->currPos = $p6;
1260      $this->currPos = $p3;
1261      $r1 = self::$FAILED;
1262      goto seq_1;
1263    }
1264    // free $p6
1265    $p6 = $this->currPos;
1266    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "options", $this->currPos, 7, false) === 0) {
1267      $r8 = "options";
1268      $this->currPos += 7;
1269    } else {
1270      $r8 = self::$FAILED;
1271    }
1272    if ($r8 === self::$FAILED) {
1273      $r8 = false;
1274    } else {
1275      $r8 = self::$FAILED;
1276      $this->currPos = $p6;
1277      $this->currPos = $p3;
1278      $r1 = self::$FAILED;
1279      goto seq_1;
1280    }
1281    // free $p6
1282    $p6 = $this->currPos;
1283    $r10 = [];
1284    for (;;) {
1285      if (strcspn($this->input, " \x09\x0d\x0a", $this->currPos, 1) !== 0) {
1286        $r11 = self::consumeChar($this->input, $this->currPos);
1287        $r10[] = $r11;
1288      } else {
1289        $r11 = self::$FAILED;
1290        if (!$silence) {$this->fail(20);}
1291        break;
1292      }
1293    }
1294    if (count($r10) === 0) {
1295      $r10 = self::$FAILED;
1296    }
1297    // c <- $r10
1298    // free $r11
1299    $r9 = $r10;
1300    // name <- $r9
1301    if ($r9!==self::$FAILED) {
1302      $this->savedPos = $p6;
1303      $r9 = $this->a17($r10);
1304    } else {
1305      $this->currPos = $p3;
1306      $r1 = self::$FAILED;
1307      goto seq_1;
1308    }
1309    $r11 = $this->discardrest_of_line($silence);
1310    if ($r11===self::$FAILED) {
1311      $this->currPos = $p3;
1312      $r1 = self::$FAILED;
1313      goto seq_1;
1314    }
1315    $r12 = $this->parsetext($silence);
1316    // text <- $r12
1317    if ($r12===self::$FAILED) {
1318      $this->currPos = $p3;
1319      $r1 = self::$FAILED;
1320      goto seq_1;
1321    }
1322    $r1 = true;
1323    seq_1:
1324    if ($r1!==self::$FAILED) {
1325      $this->savedPos = $p2;
1326      $r1 = $this->a18($r9, $r12);
1327    }
1328    // free $p3
1329    return $r1;
1330  }
1331  private function discardstart_hooks($silence) {
1332    // start seq_1
1333    $p1 = $this->currPos;
1334    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "!!", $this->currPos, 2, false) === 0) {
1335      $r3 = "!!";
1336      $this->currPos += 2;
1337    } else {
1338      if (!$silence) {$this->fail(1);}
1339      $r3 = self::$FAILED;
1340      $r2 = self::$FAILED;
1341      goto seq_1;
1342    }
1343    $r4 = $this->discardwhitespace($silence);
1344    if ($r4===self::$FAILED) {
1345      $r4 = null;
1346    }
1347    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "hooks", $this->currPos, 5, false) === 0) {
1348      $r5 = "hooks";
1349      $this->currPos += 5;
1350    } else {
1351      if (!$silence) {$this->fail(21);}
1352      $r5 = self::$FAILED;
1353      $this->currPos = $p1;
1354      $r2 = self::$FAILED;
1355      goto seq_1;
1356    }
1357    if (($this->input[$this->currPos] ?? null) === ":") {
1358      $this->currPos++;
1359      $r6 = ":";
1360    } else {
1361      if (!$silence) {$this->fail(22);}
1362      $r6 = self::$FAILED;
1363      $r6 = null;
1364    }
1365    $r7 = $this->discardwhitespace($silence);
1366    if ($r7===self::$FAILED) {
1367      $r7 = null;
1368    }
1369    $r8 = $this->discardeol($silence);
1370    if ($r8===self::$FAILED) {
1371      $this->currPos = $p1;
1372      $r2 = self::$FAILED;
1373      goto seq_1;
1374    }
1375    $r2 = true;
1376    seq_1:
1377    // free $r2,$p1
1378    return $r2;
1379  }
1380  private function discardend_hooks($silence) {
1381    // start seq_1
1382    $p1 = $this->currPos;
1383    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "!!", $this->currPos, 2, false) === 0) {
1384      $r3 = "!!";
1385      $this->currPos += 2;
1386    } else {
1387      if (!$silence) {$this->fail(1);}
1388      $r3 = self::$FAILED;
1389      $r2 = self::$FAILED;
1390      goto seq_1;
1391    }
1392    $r4 = $this->discardwhitespace($silence);
1393    if ($r4===self::$FAILED) {
1394      $r4 = null;
1395    }
1396    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "endhooks", $this->currPos, 8, false) === 0) {
1397      $r5 = "endhooks";
1398      $this->currPos += 8;
1399    } else {
1400      if (!$silence) {$this->fail(23);}
1401      $r5 = self::$FAILED;
1402      $this->currPos = $p1;
1403      $r2 = self::$FAILED;
1404      goto seq_1;
1405    }
1406    $r6 = $this->discardwhitespace($silence);
1407    if ($r6===self::$FAILED) {
1408      $r6 = null;
1409    }
1410    $r7 = $this->discardeol($silence);
1411    if ($r7===self::$FAILED) {
1412      $this->currPos = $p1;
1413      $r2 = self::$FAILED;
1414      goto seq_1;
1415    }
1416    $r2 = true;
1417    seq_1:
1418    // free $r2,$p1
1419    return $r2;
1420  }
1421  private function discardstart_functionhooks($silence) {
1422    // start seq_1
1423    $p1 = $this->currPos;
1424    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "!!", $this->currPos, 2, false) === 0) {
1425      $r3 = "!!";
1426      $this->currPos += 2;
1427    } else {
1428      if (!$silence) {$this->fail(1);}
1429      $r3 = self::$FAILED;
1430      $r2 = self::$FAILED;
1431      goto seq_1;
1432    }
1433    $r4 = $this->discardwhitespace($silence);
1434    if ($r4===self::$FAILED) {
1435      $r4 = null;
1436    }
1437    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "functionhooks", $this->currPos, 13, false) === 0) {
1438      $r5 = "functionhooks";
1439      $this->currPos += 13;
1440    } else {
1441      if (!$silence) {$this->fail(24);}
1442      $r5 = self::$FAILED;
1443      $this->currPos = $p1;
1444      $r2 = self::$FAILED;
1445      goto seq_1;
1446    }
1447    if (($this->input[$this->currPos] ?? null) === ":") {
1448      $this->currPos++;
1449      $r6 = ":";
1450    } else {
1451      if (!$silence) {$this->fail(22);}
1452      $r6 = self::$FAILED;
1453      $r6 = null;
1454    }
1455    $r7 = $this->discardwhitespace($silence);
1456    if ($r7===self::$FAILED) {
1457      $r7 = null;
1458    }
1459    $r8 = $this->discardeol($silence);
1460    if ($r8===self::$FAILED) {
1461      $this->currPos = $p1;
1462      $r2 = self::$FAILED;
1463      goto seq_1;
1464    }
1465    $r2 = true;
1466    seq_1:
1467    // free $r2,$p1
1468    return $r2;
1469  }
1470  private function discardend_functionhooks($silence) {
1471    // start seq_1
1472    $p1 = $this->currPos;
1473    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "!!", $this->currPos, 2, false) === 0) {
1474      $r3 = "!!";
1475      $this->currPos += 2;
1476    } else {
1477      if (!$silence) {$this->fail(1);}
1478      $r3 = self::$FAILED;
1479      $r2 = self::$FAILED;
1480      goto seq_1;
1481    }
1482    $r4 = $this->discardwhitespace($silence);
1483    if ($r4===self::$FAILED) {
1484      $r4 = null;
1485    }
1486    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "endfunctionhooks", $this->currPos, 16, false) === 0) {
1487      $r5 = "endfunctionhooks";
1488      $this->currPos += 16;
1489    } else {
1490      if (!$silence) {$this->fail(25);}
1491      $r5 = self::$FAILED;
1492      $this->currPos = $p1;
1493      $r2 = self::$FAILED;
1494      goto seq_1;
1495    }
1496    if (($this->input[$this->currPos] ?? null) === ":") {
1497      $this->currPos++;
1498      $r6 = ":";
1499    } else {
1500      if (!$silence) {$this->fail(22);}
1501      $r6 = self::$FAILED;
1502      $r6 = null;
1503    }
1504    $r7 = $this->discardwhitespace($silence);
1505    if ($r7===self::$FAILED) {
1506      $r7 = null;
1507    }
1508    $r8 = $this->discardeol($silence);
1509    if ($r8===self::$FAILED) {
1510      $this->currPos = $p1;
1511      $r2 = self::$FAILED;
1512      goto seq_1;
1513    }
1514    $r2 = true;
1515    seq_1:
1516    // free $r2,$p1
1517    return $r2;
1518  }
1519  private function parseoption_name($silence) {
1520    $p2 = $this->currPos;
1521    $r3 = [];
1522    for (;;) {
1523      if (strcspn($this->input, " \x09\x0a=!", $this->currPos, 1) !== 0) {
1524        $r4 = self::consumeChar($this->input, $this->currPos);
1525        $r3[] = $r4;
1526      } else {
1527        $r4 = self::$FAILED;
1528        if (!$silence) {$this->fail(26);}
1529        break;
1530      }
1531    }
1532    if (count($r3) === 0) {
1533      $r3 = self::$FAILED;
1534    }
1535    // c <- $r3
1536    // free $r4
1537    $r1 = $r3;
1538    if ($r1!==self::$FAILED) {
1539      $this->savedPos = $p2;
1540      $r1 = $this->a4($r3);
1541    }
1542    return $r1;
1543  }
1544  private function parseoption_value($silence) {
1545    $p2 = $this->currPos;
1546    // start seq_1
1547    $p3 = $this->currPos;
1548    $r4 = $this->discardwhitespace($silence);
1549    if ($r4===self::$FAILED) {
1550      $r4 = null;
1551    }
1552    if (($this->input[$this->currPos] ?? null) === "=") {
1553      $this->currPos++;
1554      $r5 = "=";
1555    } else {
1556      if (!$silence) {$this->fail(27);}
1557      $r5 = self::$FAILED;
1558      $this->currPos = $p3;
1559      $r1 = self::$FAILED;
1560      goto seq_1;
1561    }
1562    $r6 = $this->discardwhitespace($silence);
1563    if ($r6===self::$FAILED) {
1564      $r6 = null;
1565    }
1566    $r7 = $this->parseoption_value_list($silence);
1567    // ovl <- $r7
1568    if ($r7===self::$FAILED) {
1569      $this->currPos = $p3;
1570      $r1 = self::$FAILED;
1571      goto seq_1;
1572    }
1573    $r1 = true;
1574    seq_1:
1575    if ($r1!==self::$FAILED) {
1576      $this->savedPos = $p2;
1577      $r1 = $this->a19($r7);
1578    }
1579    // free $p3
1580    return $r1;
1581  }
1582  private function parseoption_value_list($silence) {
1583    $p2 = $this->currPos;
1584    // start seq_1
1585    $p3 = $this->currPos;
1586    $r4 = $this->parsean_option_value($silence);
1587    // v <- $r4
1588    if ($r4===self::$FAILED) {
1589      $r1 = self::$FAILED;
1590      goto seq_1;
1591    }
1592    $p6 = $this->currPos;
1593    // start seq_2
1594    $p7 = $this->currPos;
1595    $r8 = $this->discardwhitespace($silence);
1596    if ($r8===self::$FAILED) {
1597      $r8 = null;
1598    }
1599    if (($this->input[$this->currPos] ?? null) === ",") {
1600      $this->currPos++;
1601      $r9 = ",";
1602    } else {
1603      if (!$silence) {$this->fail(28);}
1604      $r9 = self::$FAILED;
1605      $this->currPos = $p7;
1606      $r5 = self::$FAILED;
1607      goto seq_2;
1608    }
1609    $r10 = $this->discardwhitespace($silence);
1610    if ($r10===self::$FAILED) {
1611      $r10 = null;
1612    }
1613    $r11 = $this->parseoption_value_list($silence);
1614    // ovl <- $r11
1615    if ($r11===self::$FAILED) {
1616      $this->currPos = $p7;
1617      $r5 = self::$FAILED;
1618      goto seq_2;
1619    }
1620    $r5 = true;
1621    seq_2:
1622    if ($r5!==self::$FAILED) {
1623      $this->savedPos = $p6;
1624      $r5 = $this->a20($r4, $r11);
1625    } else {
1626      $r5 = null;
1627    }
1628    // free $p7
1629    // rest <- $r5
1630    $r1 = true;
1631    seq_1:
1632    if ($r1!==self::$FAILED) {
1633      $this->savedPos = $p2;
1634      $r1 = $this->a21($r4, $r5);
1635    }
1636    // free $p3
1637    return $r1;
1638  }
1639  private function parsean_option_value($silence) {
1640    $p2 = $this->currPos;
1641    // start choice_1
1642    $r3 = $this->parselink_target_value($silence);
1643    if ($r3!==self::$FAILED) {
1644      goto choice_1;
1645    }
1646    $r3 = $this->parsequoted_value($silence);
1647    if ($r3!==self::$FAILED) {
1648      goto choice_1;
1649    }
1650    $r3 = $this->parseplain_value($silence);
1651    if ($r3!==self::$FAILED) {
1652      goto choice_1;
1653    }
1654    $r3 = $this->parsejson_value($silence);
1655    choice_1:
1656    // v <- $r3
1657    $r1 = $r3;
1658    if ($r1!==self::$FAILED) {
1659      $this->savedPos = $p2;
1660      $r1 = $this->a22($r3);
1661    }
1662    return $r1;
1663  }
1664  private function parselink_target_value($silence) {
1665    $p2 = $this->currPos;
1666    // start seq_1
1667    $p3 = $this->currPos;
1668    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "[[", $this->currPos, 2, false) === 0) {
1669      $r4 = "[[";
1670      $this->currPos += 2;
1671    } else {
1672      if (!$silence) {$this->fail(29);}
1673      $r4 = self::$FAILED;
1674      $r1 = self::$FAILED;
1675      goto seq_1;
1676    }
1677    $r5 = [];
1678    for (;;) {
1679      $r6 = self::charAt($this->input, $this->currPos);
1680      if ($r6 !== '' && !($r6 === "]" || $r6 === "\x0a")) {
1681        $this->currPos += strlen($r6);
1682        $r5[] = $r6;
1683      } else {
1684        $r6 = self::$FAILED;
1685        if (!$silence) {$this->fail(30);}
1686        break;
1687      }
1688    }
1689    // v <- $r5
1690    // free $r6
1691    if ($this->currPos >= $this->inputLength ? false : substr_compare($this->input, "]]", $this->currPos, 2, false) === 0) {
1692      $r6 = "]]";
1693      $this->currPos += 2;
1694    } else {
1695      if (!$silence) {$this->fail(31);}
1696      $r6 = self::$FAILED;
1697      $this->currPos = $p3;
1698      $r1 = self::$FAILED;
1699      goto seq_1;
1700    }
1701    $r1 = true;
1702    seq_1:
1703    if ($r1!==self::$FAILED) {
1704      $this->savedPos = $p2;
1705      $r1 = $this->a23($r5);
1706    }
1707    // free $p3
1708    return $r1;
1709  }
1710  private function parsequoted_value($silence) {
1711    $p2 = $this->currPos;
1712    // start seq_1
1713    $p3 = $this->currPos;
1714    $r4 = $this->input[$this->currPos] ?? '';
1715    if ($r4 === "\"") {
1716      $this->currPos++;
1717    } else {
1718      $r4 = self::$FAILED;
1719      if (!$silence) {$this->fail(32);}
1720      $r1 = self::$FAILED;
1721      goto seq_1;
1722    }
1723    $r5 = [];
1724    for (;;) {
1725      // start choice_1
1726      if (strcspn($this->input, "\\\"\x0a", $this->currPos, 1) !== 0) {
1727        $r6 = self::consumeChar($this->input, $this->currPos);
1728        goto choice_1;
1729      } else {
1730        $r6 = self::$FAILED;
1731        if (!$silence) {$this->fail(33);}
1732      }
1733      $p7 = $this->currPos;
1734      // start seq_2
1735      $p8 = $this->currPos;
1736      if (($this->input[$this->currPos] ?? null) === "\\") {
1737        $this->currPos++;
1738        $r9 = "\\";
1739      } else {
1740        if (!$silence) {$this->fail(34);}
1741        $r9 = self::$FAILED;
1742        $r6 = self::$FAILED;
1743        goto seq_2;
1744      }
1745      $r10 = self::charAt($this->input, $this->currPos);
1746      // c <- $r10
1747      if ($r10 !== '' && !($r10 === "\x0a")) {
1748        $this->currPos += strlen($r10);
1749      } else {
1750        $r10 = self::$FAILED;
1751        if (!$silence) {$this->fail(11);}
1752        $this->currPos = $p8;
1753        $r6 = self::$FAILED;
1754        goto seq_2;
1755      }
1756      $r6 = true;
1757      seq_2:
1758      if ($r6!==self::$FAILED) {
1759        $this->savedPos = $p7;
1760        $r6 = $this->a24($r10);
1761      }
1762      // free $p8
1763      choice_1:
1764      if ($r6!==self::$FAILED) {
1765        $r5[] = $r6;
1766      } else {
1767        break;
1768      }
1769    }
1770    // v <- $r5
1771    // free $r6
1772    $r6 = $this->input[$this->currPos] ?? '';
1773    if ($r6 === "\"") {
1774      $this->currPos++;
1775    } else {
1776      $r6 = self::$FAILED;
1777      if (!$silence) {$this->fail(32);}
1778      $this->currPos = $p3;
1779      $r1 = self::$FAILED;
1780      goto seq_1;
1781    }
1782    $r1 = true;
1783    seq_1:
1784    if ($r1!==self::$FAILED) {
1785      $this->savedPos = $p2;
1786      $r1 = $this->a25($r5);
1787    }
1788    // free $p3
1789    return $r1;
1790  }
1791  private function parseplain_value($silence) {
1792    $p2 = $this->currPos;
1793    $r3 = [];
1794    for (;;) {
1795      if (strcspn($this->input, " \x09\x0a\"'[]=,!{", $this->currPos, 1) !== 0) {
1796        $r4 = self::consumeChar($this->input, $this->currPos);
1797        $r3[] = $r4;
1798      } else {
1799        $r4 = self::$FAILED;
1800        if (!$silence) {$this->fail(35);}
1801        break;
1802      }
1803    }
1804    if (count($r3) === 0) {
1805      $r3 = self::$FAILED;
1806    }
1807    // v <- $r3
1808    // free $r4
1809    $r1 = $r3;
1810    if ($r1!==self::$FAILED) {
1811      $this->savedPos = $p2;
1812      $r1 = $this->a26($r3);
1813    }
1814    return $r1;
1815  }
1816  private function parsejson_value($silence) {
1817    $p2 = $this->currPos;
1818    // start seq_1
1819    $p3 = $this->currPos;
1820    if (($this->input[$this->currPos] ?? null) === "{") {
1821      $this->currPos++;
1822      $r4 = "{";
1823    } else {
1824      if (!$silence) {$this->fail(36);}
1825      $r4 = self::$FAILED;
1826      $r1 = self::$FAILED;
1827      goto seq_1;
1828    }
1829    $r5 = [];
1830    for (;;) {
1831      // start choice_1
1832      if (strcspn($this->input, "\"{}\x0a", $this->currPos, 1) !== 0) {
1833        $r6 = self::consumeChar($this->input, $this->currPos);
1834        goto choice_1;
1835      } else {
1836        $r6 = self::$FAILED;
1837        if (!$silence) {$this->fail(37);}
1838      }
1839      $r6 = $this->parsequoted_value($silence);
1840      if ($r6!==self::$FAILED) {
1841        goto choice_1;
1842      }
1843      $r6 = $this->parsejson_value($silence);
1844      if ($r6!==self::$FAILED) {
1845        goto choice_1;
1846      }
1847      $r6 = $this->parseeol($silence);
1848      choice_1:
1849      if ($r6!==self::$FAILED) {
1850        $r5[] = $r6;
1851      } else {
1852        break;
1853      }
1854    }
1855    // v <- $r5
1856    // free $r6
1857    if (($this->input[$this->currPos] ?? null) === "}") {
1858      $this->currPos++;
1859      $r6 = "}";
1860    } else {
1861      if (!$silence) {$this->fail(38);}
1862      $r6 = self::$FAILED;
1863      $this->currPos = $p3;
1864      $r1 = self::$FAILED;
1865      goto seq_1;
1866    }
1867    $r1 = true;
1868    seq_1:
1869    if ($r1!==self::$FAILED) {
1870      $this->savedPos = $p2;
1871      $r1 = $this->a27($r5);
1872    }
1873    // free $p3
1874    return $r1;
1875  }
1876  private function parseeol($silence) {
1877    $p2 = $this->currPos;
1878    // nl <- $r3
1879    if (($this->input[$this->currPos] ?? null) === "\x0a") {
1880      $this->currPos++;
1881      $r3 = "\x0a";
1882    } else {
1883      if (!$silence) {$this->fail(14);}
1884      $r3 = self::$FAILED;
1885    }
1886    $r1 = $r3;
1887    if ($r1!==self::$FAILED) {
1888      $this->savedPos = $p2;
1889      $r1 = $this->a7($r3);
1890    }
1891    return $r1;
1892  }
1893
1894  public function parse($input, $options = []) {
1895    $this->initInternal($input, $options);
1896    $startRule = $options['startRule'] ?? '(DEFAULT)';
1897    $result = null;
1898
1899    if (!empty($options['stream'])) {
1900      switch ($startRule) {
1901
1902        default:
1903          throw new \WikiPEG\InternalError("Can't stream rule $startRule.");
1904      }
1905    } else {
1906      switch ($startRule) {
1907        case '(DEFAULT)':
1908        case "testfile":
1909          $result = $this->parsetestfile(false);
1910          break;
1911        default:
1912          throw new \WikiPEG\InternalError("Can't start parsing from rule $startRule.");
1913      }
1914    }
1915
1916    if ($result !== self::$FAILED && $this->currPos === $this->inputLength) {
1917      return $result;
1918    } else {
1919      if ($result !== self::$FAILED && $this->currPos < $this->inputLength) {
1920        $this->fail(0);
1921      }
1922      throw $this->buildParseException();
1923    }
1924  }
1925}
1926
1927