‪TYPO3CMS  ‪main
LosslessTokenizer.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
43 
61 {
63 
67 
68  private array ‪$lines;
69  private int ‪$currentLineNumber;
70  private string ‪$currentLineString;
71  private \closure ‪$currentLinebreakCallback;
72  private int ‪$currentColumnInLine = 0;
73 
74  public function ‪tokenize(string $source): ‪LineStream
75  {
76  $this->lineStream = new ‪LineStream();
77  $this->currentLineNumber = -1;
78  $this->lines = [];
79  $this->‪splitLines($source);
80 
81  while (true) {
82  $this->tokenStream = new ‪TokenStream();
83  $this->currentLineNumber++;
84  if (!array_key_exists($this->currentLineNumber, $this->lines)) {
85  break;
86  }
87  $this->currentColumnInLine = 0;
88  $this->currentLineString = $this->lines[‪$this->currentLineNumber]['line'];
89  $this->currentLinebreakCallback = $this->lines[‪$this->currentLineNumber]['linebreakCallback'];
91  $nextChar = substr($this->currentLineString, 0, 1);
92  if ($nextChar === '') {
94  if (!$this->tokenStream->isEmpty()) {
95  $this->‪createEmptyLine();
96  }
97  continue;
98  }
99  $nextTwoChars = substr($this->currentLineString, 0, 2);
100  if ($nextChar === '#') {
101  $this->‪createHashCommentLine();
102  } elseif ($nextTwoChars === '//') {
104  } elseif ($nextTwoChars === '/*') {
106  } elseif ($nextChar === '[') {
107  $this->‪createConditionLine();
108  } elseif ($nextChar === '}') {
109  $this->‪createBlockStopLine();
110  } elseif (str_starts_with($this->currentLineString, '@import')) {
111  $this->‪parseImportLine();
112  } elseif (str_starts_with($this->currentLineString, '<INCLUDE_TYPOSCRIPT:')) {
113  $this->‪parseImportOld();
114  } else {
115  $this->‪parseIdentifier();
116  }
117  }
118 
119  return ‪$this->lineStream;
120  }
121 
122  private function ‪splitLines($source): void
123  {
124  $vanillaLines = explode(chr(10), $source);
125  $this->lines = array_map(
126  fn(int $lineNumber, string $vanillaLine): array => [
127  'line' => rtrim($vanillaLine, "\r"),
128  'linebreakCallback' => str_ends_with($vanillaLine, "\r")
129  ? fn() => $this->tokenStream->append(new ‪Token(TokenType::T_NEWLINE, "\r\n", $lineNumber, mb_strlen($vanillaLine) - 1))
130  : fn() => $this->tokenStream->append(new ‪Token(TokenType::T_NEWLINE, "\n", $lineNumber, mb_strlen($vanillaLine))),
131  ],
132  array_keys($vanillaLines),
133  $vanillaLines
134  );
135  // Set the linebreak callback of last line to empty to suppress dangling linebreak tokens
136  $this->lines[count($vanillaLines) - 1]['linebreakCallback'] = function () {};
137  }
138 
139  private function ‪createEmptyLine(): void
140  {
141  $this->lineStream->append((new ‪EmptyLine())->setTokenStream($this->tokenStream));
142  }
143 
147  private function ‪parseTabsAndWhitespaces(): void
148  {
149  $matches = [];
150  if (preg_match('#^(\s+)(.*)$#', $this->currentLineString, $matches)) {
151  $this->tokenStream->append(new ‪Token(TokenType::T_BLANK, $matches[1], $this->currentLineNumber, $this->currentColumnInLine));
152  $this->currentLineString = $matches[2];
153  $this->currentColumnInLine = $this->currentColumnInLine + strlen($matches[1]);
154  }
155  }
156 
157  private function ‪makeComment(): void
158  {
159  $nextChar = substr($this->currentLineString, 0, 1);
160  if ($nextChar === '') {
162  return;
163  }
164  $nextTwoChars = substr($this->currentLineString, 0, 2);
165  if ($nextChar === '#') {
166  $this->‪parseHashComment();
167  } elseif ($nextTwoChars === '//') {
169  } elseif ($nextTwoChars === '/*') {
170  $this->‪parseMultilineComment();
171  } else {
172  $this->‪parseHashComment();
173  }
174  }
175 
176  private function ‪createHashCommentLine(): void
177  {
178  $this->‪parseHashComment();
179  $this->lineStream->append((new ‪CommentLine())->setTokenStream($this->tokenStream));
180  }
181 
182  private function ‪parseHashComment(): void
183  {
184  $this->tokenStream->append(new ‪Token(TokenType::T_COMMENT_ONELINE_HASH, $this->currentLineString, $this->currentLineNumber, $this->currentColumnInLine));
186  }
187 
188  private function ‪createDoubleSlashCommentLine(): void
189  {
191  $this->lineStream->append((new ‪CommentLine())->setTokenStream($this->tokenStream));
192  }
193 
194  private function ‪parseDoubleSlashComment(): void
195  {
196  $this->tokenStream->append(new ‪Token(TokenType::T_COMMENT_ONELINE_DOUBLESLASH, $this->currentLineString, $this->currentLineNumber, $this->currentColumnInLine));
198  }
199 
200  private function ‪createMultilineCommentLine(): void
201  {
202  $this->‪parseMultilineComment();
203  $this->lineStream->append((new ‪CommentLine())->setTokenStream($this->tokenStream));
204  }
205 
206  private function ‪parseMultilineComment(): void
207  {
208  $this->tokenStream->append(new ‪Token(TokenType::T_COMMENT_MULTILINE_START, '/*', $this->currentLineNumber, $this->currentColumnInLine));
209  $this->currentColumnInLine += 2;
210  $this->currentLineString = substr($this->currentLineString, 2);
211  while (true) {
212  if (str_ends_with($this->currentLineString, '*/')) {
213  if (strlen($this->currentLineString) > 2) {
214  $this->tokenStream->append(new ‪Token(TokenType::T_VALUE, substr($this->currentLineString, 0, -2), $this->currentLineNumber, $this->currentColumnInLine));
215  }
216  $this->tokenStream->append(new ‪Token(TokenType::T_COMMENT_MULTILINE_STOP, '*/', $this->currentLineNumber, $this->currentColumnInLine + strlen($this->currentLineString) - 2));
218  return;
219  }
220  if (strlen($this->currentLineString)) {
221  $this->tokenStream->append(new ‪Token(TokenType::T_VALUE, $this->currentLineString, $this->currentLineNumber, $this->currentColumnInLine));
222  }
224  if (!array_key_exists($this->currentLineNumber + 1, $this->lines)) {
225  return;
226  }
227  $this->currentLineNumber++;
228  $this->currentColumnInLine = 0;
229  $this->currentLineString = $this->lines[‪$this->currentLineNumber]['line'];
230  $this->currentLinebreakCallback = $this->lines[‪$this->currentLineNumber]['linebreakCallback'];
231  }
232  }
233 
237  private function ‪createConditionLine(): void
238  {
239  $upperCaseLine = strtoupper($this->currentLineString);
240  $this->tokenStream->append(new ‪Token(TokenType::T_CONDITION_START, '[', $this->currentLineNumber, $this->currentColumnInLine));
241  if (str_starts_with($upperCaseLine, '[ELSE]')) {
242  $this->tokenStream->append(new ‪Token(TokenType::T_CONDITION_ELSE, substr($this->currentLineString, 1, 4), $this->currentLineNumber, $this->currentColumnInLine + 1));
243  $this->tokenStream->append(new ‪Token(TokenType::T_CONDITION_STOP, ']', $this->currentLineNumber, $this->currentColumnInLine + 5));
244  $this->currentLineString = substr($this->currentLineString, 6);
245  $this->currentColumnInLine += 6;
247  $this->‪makeComment();
248  $this->lineStream->append((new ‪ConditionElseLine())->setTokenStream($this->tokenStream));
249  return;
250  }
251  if (str_starts_with($upperCaseLine, '[END]')) {
252  $this->tokenStream->append(new ‪Token(TokenType::T_CONDITION_END, substr($this->currentLineString, 1, 3), $this->currentLineNumber, $this->currentColumnInLine + 1));
253  $this->tokenStream->append(new ‪Token(TokenType::T_CONDITION_STOP, ']', $this->currentLineNumber, $this->currentColumnInLine + 4));
254  $this->currentLineString = substr($this->currentLineString, 5);
255  $this->currentColumnInLine += 5;
257  $this->‪makeComment();
258  $this->lineStream->append((new ‪ConditionStopLine())->setTokenStream($this->tokenStream));
259  return;
260  }
261  if (str_starts_with($upperCaseLine, '[GLOBAL]')) {
262  $this->tokenStream->append(new ‪Token(TokenType::T_CONDITION_GLOBAL, substr($this->currentLineString, 1, 6), $this->currentLineNumber, $this->currentColumnInLine + 1));
263  $this->tokenStream->append(new ‪Token(TokenType::T_CONDITION_STOP, ']', $this->currentLineNumber, $this->currentColumnInLine + 7));
264  $this->currentLineString = substr($this->currentLineString, 8);
265  $this->currentColumnInLine += 8;
267  $this->‪makeComment();
268  $this->lineStream->append((new ‪ConditionStopLine())->setTokenStream($this->tokenStream));
269  return;
270  }
271  $conditionBody = '';
272  $conditionBodyStartPosition = $this->currentColumnInLine + 1;
273  $conditionBodyCharCount = 0;
274  $conditionBodyChars = mb_str_split(substr($this->currentLineString, 1), 1, 'UTF-8');
275  $bracketCount = 1;
276  while (true) {
277  $nextChar = $conditionBodyChars[$conditionBodyCharCount] ?? null;
278  if ($nextChar === null) {
279  // end of chars
280  if ($conditionBodyCharCount) {
281  $this->tokenStream->append(new ‪Token(TokenType::T_VALUE, $conditionBody, $this->currentLineNumber, $conditionBodyStartPosition));
282  }
284  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
285  return;
286  }
287  if ($nextChar === '[') {
288  $bracketCount++;
289  $conditionBody .= $nextChar;
290  $conditionBodyCharCount++;
291  continue;
292  }
293  if ($nextChar === ']') {
294  $bracketCount--;
295  if ($bracketCount === 0) {
296  if ($conditionBodyCharCount) {
297  $conditionBodyToken = new ‪Token(TokenType::T_VALUE, $conditionBody, $this->currentLineNumber, $conditionBodyStartPosition);
298  $this->tokenStream->append($conditionBodyToken);
299  $this->tokenStream->append(new ‪Token(TokenType::T_CONDITION_STOP, ']', $this->currentLineNumber, $this->currentColumnInLine + $conditionBodyCharCount + 1));
300  $this->currentLineString = mb_substr($this->currentLineString, $conditionBodyCharCount + 2);
301  $this->currentColumnInLine = $this->currentColumnInLine + $conditionBodyCharCount + 2;
303  $this->‪makeComment();
304  $this->lineStream->append((new ‪ConditionLine())->setTokenStream($this->tokenStream)->setValueToken($conditionBodyToken));
305  return;
306  }
307  $this->tokenStream->append(new ‪Token(TokenType::T_CONDITION_STOP, ']', $this->currentLineNumber, $this->currentColumnInLine + $conditionBodyCharCount + 1));
308  $this->currentLineString = mb_substr($this->currentLineString, $conditionBodyCharCount + 2);
309  $this->currentColumnInLine = $this->currentColumnInLine + $conditionBodyCharCount + 2;
311  $this->‪makeComment();
312  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
313  return;
314  }
315  $conditionBody .= $nextChar;
316  $conditionBodyCharCount++;
317  continue;
318  }
319  $conditionBody .= $nextChar;
320  $conditionBodyCharCount++;
321  }
322  }
323 
324  private function ‪createBlockStopLine(): void
325  {
326  $this->tokenStream->append(new ‪Token(TokenType::T_BLOCK_STOP, $this->currentLineString, $this->currentLineNumber, $this->currentColumnInLine));
327  $this->currentColumnInLine++;
328  $this->currentLineString = substr($this->currentLineString, 1);
329  $this->‪makeComment();
330  $this->lineStream->append((new ‪BlockCloseLine())->setTokenStream($this->tokenStream));
331  }
332 
333  private function ‪parseBlockStart(): void
334  {
335  $this->tokenStream->append(new ‪Token(TokenType::T_BLOCK_START, '{', $this->currentLineNumber, $this->currentColumnInLine));
336  $this->currentColumnInLine++;
337  $this->currentLineString = substr($this->currentLineString, 1);
339  if (str_starts_with($this->currentLineString, '}')) {
340  // Edge case: foo = { } in one line. Note content within {} is not parsed, everything behind { ends up as comment.
341  $this->lineStream->append((new ‪IdentifierBlockOpenLine())->setIdentifierTokenStream($this->identifierStream)->setTokenStream($this->tokenStream));
342  $this->tokenStream = new ‪TokenStream();
343  $this->tokenStream->append(new ‪Token(TokenType::T_BLOCK_STOP, '}', $this->currentLineNumber, $this->currentColumnInLine));
344  $this->currentLineString = substr($this->currentLineString, 1);
345  $this->currentColumnInLine++;
346  $this->‪makeComment();
347  $this->lineStream->append((new ‪BlockCloseLine())->setTokenStream($this->tokenStream));
348  return;
349  }
350  $this->‪makeComment();
351  $this->lineStream->append((new ‪IdentifierBlockOpenLine())->setIdentifierTokenStream($this->identifierStream)->setTokenStream($this->tokenStream));
352  }
353 
354  private function ‪parseImportLine(): void
355  {
356  $this->tokenStream->append(new ‪Token(TokenType::T_IMPORT_KEYWORD, '@import', $this->currentLineNumber, $this->currentColumnInLine));
357  $this->currentColumnInLine += 7;
358  $this->currentLineString = substr($this->currentLineString, 7);
360 
361  // Next char should be the opening tick or doubletick, otherwise we create a comment until end of line
362  $nextChar = substr($this->currentLineString, 0, 1);
363  if ($nextChar !== '\'' && $nextChar !== '"') {
364  $this->‪makeComment();
365  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
366  return;
367  }
368  $this->tokenStream->append(new ‪Token(TokenType::T_IMPORT_START, $nextChar, $this->currentLineNumber, $this->currentColumnInLine));
369 
370  $importBody = '';
371  $importBodyStartPosition = $this->currentColumnInLine + 1;
372  $importBodyCharCount = 0;
373  $importBodyChars = mb_str_split(substr($this->currentLineString, 1), 1, 'UTF-8');
374  while (true) {
375  $nextChar = $importBodyChars[$importBodyCharCount] ?? null;
376  if ($nextChar === null) {
377  // end of chars
378  if ($importBodyCharCount) {
379  $importBodyToken = (new ‪Token(TokenType::T_VALUE, $importBody, $this->currentLineNumber, $importBodyStartPosition));
380  $this->tokenStream->append($importBodyToken);
382  $this->lineStream->append((new ‪ImportLine())->setTokenStream($this->tokenStream)->setValueToken($importBodyToken));
383  return;
384  }
386  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
387  return;
388  }
389  if ($nextChar === '\'' || $nextChar === '"') {
390  if ($importBodyCharCount) {
391  $importBodyToken = new ‪Token(TokenType::T_VALUE, $importBody, $this->currentLineNumber, $importBodyStartPosition);
392  $this->tokenStream->append($importBodyToken);
393  $this->tokenStream->append(new ‪Token(TokenType::T_IMPORT_STOP, $nextChar, $this->currentLineNumber, $this->currentColumnInLine + $importBodyCharCount + 1));
394  $this->currentLineString = mb_substr($this->currentLineString, $importBodyCharCount + 2);
395  $this->currentColumnInLine = $this->currentColumnInLine + $importBodyCharCount + 2;
397  $this->‪makeComment();
398  $this->lineStream->append((new ‪ImportLine())->setTokenStream($this->tokenStream)->setValueToken($importBodyToken));
399  return;
400  }
401  $this->tokenStream->append(new ‪Token(TokenType::T_IMPORT_STOP, $nextChar, $this->currentLineNumber, $this->currentColumnInLine + $importBodyCharCount + 1));
402  $this->currentLineString = mb_substr($this->currentLineString, $importBodyCharCount + 2);
403  $this->currentColumnInLine = $this->currentColumnInLine + $importBodyCharCount + 2;
405  $this->‪makeComment();
406  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
407  return;
408  }
409  $importBody .= $nextChar;
410  $importBodyCharCount++;
411  }
412  }
413 
418  private function ‪parseImportOld(): void
419  {
420  $this->tokenStream->append(new ‪Token(TokenType::T_IMPORT_KEYWORD_OLD, '<INCLUDE_TYPOSCRIPT:', $this->currentLineNumber, $this->currentColumnInLine));
421  $this->currentColumnInLine += 20;
422  $this->currentLineString = substr($this->currentLineString, 20);
423  $importBody = '';
424  $importBodyStartPosition = ‪$this->currentColumnInLine;
425  $importBodyCharCount = 0;
426  $importBodyChars = mb_str_split($this->currentLineString, 1, 'UTF-8');
427  while (true) {
428  $nextChar = $importBodyChars[$importBodyCharCount] ?? null;
429  if ($nextChar === null) {
430  // end of chars
431  if ($importBodyCharCount) {
432  $importBodyToken = (new ‪Token(TokenType::T_VALUE, $importBody, $this->currentLineNumber, $importBodyStartPosition));
433  $this->tokenStream->append($importBodyToken);
435  $this->lineStream->append((new ‪ImportOldLine())->setTokenStream($this->tokenStream)->setValueToken($importBodyToken));
436  return;
437  }
439  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
440  return;
441  }
442  if ($nextChar === '>') {
443  if ($importBodyCharCount) {
444  $importBodyToken = new ‪Token(TokenType::T_VALUE, $importBody, $this->currentLineNumber, $importBodyStartPosition);
445  $this->tokenStream->append($importBodyToken);
446  $this->tokenStream->append(new ‪Token(‪TokenType::T_IMPORT_KEYWORD_OLD_STOP, '>', $this->currentLineNumber, $this->currentColumnInLine + $importBodyCharCount));
447  $this->currentLineString = mb_substr($this->currentLineString, $importBodyCharCount + 1);
448  $this->currentColumnInLine = $this->currentColumnInLine + $importBodyCharCount + 1;
450  $this->‪makeComment();
451  $this->lineStream->append((new ‪ImportOldLine())->setTokenStream($this->tokenStream)->setValueToken($importBodyToken));
452  return;
453  }
454  $this->tokenStream->append(new ‪Token(‪TokenType::T_IMPORT_KEYWORD_OLD_STOP, '>', $this->currentLineNumber, $this->currentColumnInLine + $importBodyCharCount));
455  $this->currentLineString = mb_substr($this->currentLineString, $importBodyCharCount + 1);
456  $this->currentColumnInLine = $this->currentColumnInLine + $importBodyCharCount + 1;
458  $this->‪makeComment();
459  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
460  return;
461  }
462  $importBody .= $nextChar;
463  $importBodyCharCount++;
464  }
465  }
466 
467  private function ‪parseIdentifier(): void
468  {
469  $splitLine = mb_str_split($this->currentLineString, 1, 'UTF-8');
470  $currentPosition = $this->‪parseIdentifierUntilStopChar($splitLine);
471  if (!$currentPosition) {
472  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
473  return;
474  }
475  $this->currentLineString = substr($this->currentLineString, $currentPosition);
476  $this->currentColumnInLine = $this->currentColumnInLine + $currentPosition;
477  $currentColumnInLineBefore = ‪$this->currentColumnInLine;
479  $currentPosition = $currentPosition + $this->currentColumnInLine - $currentColumnInLineBefore;
480  $nextChar = $splitLine[$currentPosition] ?? null;
481  $nextTwoChars = $nextChar . ($splitLine[$currentPosition + 1] ?? '');
482  if ($nextTwoChars === '=<') {
483  $this->‪parseOperatorReference();
484  return;
485  }
486  if ($nextChar === '=') {
488  return;
489  }
490  if ($nextChar === '{') {
491  $this->‪parseBlockStart();
492  return;
493  }
494  if ($nextChar === '>') {
495  $this->‪parseOperatorUnset();
496  return;
497  }
498  if ($nextChar === '<') {
499  $this->‪parseOperatorCopy();
500  return;
501  }
502  if ($nextChar === '(') {
504  return;
505  }
506  if ($nextTwoChars === ':=') {
507  $this->‪parseOperatorFunction();
508  return;
509  }
510  if ($nextChar === '#') {
511  $this->‪parseHashComment();
512  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
513  return;
514  }
515  if ($nextTwoChars === '//') {
517  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
518  return;
519  }
520  if ($nextTwoChars === '/*') {
521  $this->‪parseMultilineComment();
522  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
523  return;
524  }
525  if ($nextChar === null) {
527  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
528  }
529  }
530 
531  private function ‪parseOperatorAssignment(): void
532  {
533  $this->tokenStream->append(new ‪Token(TokenType::T_OPERATOR_ASSIGNMENT, '=', $this->currentLineNumber, $this->currentColumnInLine));
534  $this->currentColumnInLine++;
535  $this->currentLineString = substr($this->currentLineString, 1);
537  $this->valueStream = new ‪TokenStream();
538  $this->‪parseValueForConstants();
540  $this->lineStream->append((new ‪IdentifierAssignmentLine())->setTokenStream($this->tokenStream)->setIdentifierTokenStream($this->identifierStream)->setValueTokenStream($this->valueStream));
541  }
542 
543  private function ‪parseOperatorMultilineAssignment(): void
544  {
545  $this->valueStream = new ‪TokenStream();
546  $this->tokenStream->append(new ‪Token(TokenType::T_OPERATOR_ASSIGNMENT_MULTILINE_START, '(', $this->currentLineNumber, $this->currentColumnInLine));
547  $this->currentColumnInLine++;
548  $this->currentLineString = substr($this->currentLineString, 1);
549  // True if we're currently in the line with the opening '('
550  $isFirstLine = true;
551  // True if the first line has a first value token: "foo ( thisIsTheFirstValueToken"
552  $valueOnFirstLine = false;
553  // True if the line after '(' is parsed
554  $isSecondLine = false;
555  $previousLineCallback = function () {};
556  while (true) {
557  if (str_starts_with(ltrim($this->currentLineString), ')')) {
559  $this->tokenStream->append(new ‪Token(TokenType::T_OPERATOR_ASSIGNMENT_MULTILINE_STOP, ')', $this->currentLineNumber, $this->currentColumnInLine));
560  $this->currentLineString = substr($this->currentLineString, 1);
561  $this->currentColumnInLine++;
563  $this->‪makeComment();
564  if ($this->valueStream->isEmpty()) {
565  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
566  } else {
567  $this->lineStream->append((new ‪IdentifierAssignmentLine())->setIdentifierTokenStream($this->identifierStream)->setValueTokenStream($this->valueStream)->setTokenStream($this->tokenStream));
568  }
569  return;
570  }
571  if ($isFirstLine && str_ends_with($this->currentLineString, ')')) {
572  // Special case if the ')' is on same line as the opening '('
573  $this->currentLineString = substr($this->currentLineString, 0, -1);
574  if (strlen($this->currentLineString) > 1) {
575  $this->‪parseValueForConstants();
576  $this->tokenStream->append(new ‪Token(TokenType::T_OPERATOR_ASSIGNMENT_MULTILINE_STOP, ')', $this->currentLineNumber, $this->currentColumnInLine + strlen($this->currentLineString)));
577  // Tricky to swap the streams here, but that's the most effective solution I could come up with for the line endings here.
579  $tempStream = ‪$this->tokenStream;
580  $this->tokenStream = ‪$this->valueStream;
582  $this->tokenStream = $tempStream;
583  $this->lineStream->‪append((new ‪IdentifierAssignmentLine())->setIdentifierTokenStream($this->identifierStream)->setValueTokenStream($this->valueStream)->setTokenStream($this->tokenStream));
584  return;
585  }
586  $this->tokenStream->append(new ‪Token(TokenType::T_OPERATOR_ASSIGNMENT_MULTILINE_STOP, ')', $this->currentLineNumber, $this->currentColumnInLine + strlen($this->currentLineString)));
588  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
589  return;
590  }
591  if ($isFirstLine && strlen($this->currentLineString)) {
592  $this->‪parseValueForConstants();
593  $valueOnFirstLine = true;
594  $previousLineCallback = ‪$this->currentLinebreakCallback;
595  }
596  if (($isFirstLine && $valueOnFirstLine)
597  || (!$isFirstLine && !$isSecondLine)
598  ) {
599  $tempStream = ‪$this->tokenStream;
600  $this->tokenStream = ‪$this->valueStream;
601  $previousLineCallback();
602  $this->tokenStream = $tempStream;
603  }
604  if (!$isFirstLine && strlen($this->currentLineString)) {
605  $this->‪parseValueForConstants();
606  }
607  $previousLineCallback = ‪$this->currentLinebreakCallback;
609  if (!array_key_exists($this->currentLineNumber + 1, $this->lines)) {
610  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
611  return;
612  }
613  if ($isFirstLine) {
614  $isSecondLine = true;
615  } else {
616  $isSecondLine = false;
617  }
618  $isFirstLine = false;
619  $valueOnFirstLine = false;
620  $this->currentLineNumber++;
621  $this->currentColumnInLine = 0;
622  $this->currentLineString = $this->lines[‪$this->currentLineNumber]['line'];
623  $this->currentLinebreakCallback = $this->lines[‪$this->currentLineNumber]['linebreakCallback'];
624  }
625  }
626 
627  private function ‪parseOperatorUnset(): void
628  {
629  $this->tokenStream->append(new ‪Token(TokenType::T_OPERATOR_UNSET, '>', $this->currentLineNumber, $this->currentColumnInLine));
630  $this->currentColumnInLine++;
631  $this->currentLineString = substr($this->currentLineString, 1);
633  $this->‪makeComment();
634  $this->lineStream->append((new ‪IdentifierUnsetLine())->setTokenStream($this->tokenStream)->setIdentifierTokenStream($this->identifierStream));
635  }
636 
637  private function ‪parseOperatorCopy(): void
638  {
639  $this->tokenStream->append(new ‪Token(TokenType::T_OPERATOR_COPY, '<', $this->currentLineNumber, $this->currentColumnInLine));
640  $this->currentColumnInLine++;
641  $this->currentLineString = substr($this->currentLineString, 1);
643  $identifierStream = ‪$this->identifierStream;
645  $referenceStream = ‪$this->identifierStream;
646  if ($referenceStream->isEmpty()) {
647  $this->lineStream->‪append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
648  return;
649  }
650  $this->lineStream->append(
651  (new ‪IdentifierCopyLine())
652  ->setIdentifierTokenStream(‪$identifierStream)
653  ->setValueTokenStream($referenceStream)
654  ->setTokenStream($this->tokenStream)
655  );
656  }
657 
658  private function ‪parseOperatorReference(): void
659  {
660  $this->tokenStream->append(new ‪Token(TokenType::T_OPERATOR_REFERENCE, '=<', $this->currentLineNumber, $this->currentColumnInLine));
661  $this->currentColumnInLine += 2;
662  $this->currentLineString = substr($this->currentLineString, 2);
664  $identifierStream = ‪$this->identifierStream;
666  $referenceStream = ‪$this->identifierStream;
667  if ($referenceStream->isEmpty()) {
668  $this->lineStream->‪append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
669  return;
670  }
671  $this->lineStream->append(
673  ->setIdentifierTokenStream(‪$identifierStream)
674  ->setValueTokenStream($referenceStream)
675  ->setTokenStream($this->tokenStream)
676  );
677  }
678 
679  private function ‪parseIdentifierAtEndOfLine(): void
680  {
681  $this->identifierStream = new ‪IdentifierTokenStream();
682  $isRelative = false;
683  $splitLine = mb_str_split($this->currentLineString, 1, 'UTF-8');
684  $char = $splitLine[0] ?? null;
685  if ($char === null) {
686  return;
687  }
688  $nextTwoChars = $char . ($splitLine[1] ?? '');
689  if ($char === '.') {
690  // A relative right side: foo.bar < .foo (note the dot!). we identifierStream->setRelative() and
691  // get rid of the dot for the rest of the processing.
692  $isRelative = true;
693  $this->tokenStream->append((new ‪Token(TokenType::T_DOT, '.', 0, $this->currentColumnInLine)));
694  array_shift($splitLine);
695  $this->currentColumnInLine++;
696  $this->currentLineString = substr($this->currentLineString, 1);
697  }
698  if ($char === '#') {
699  $this->‪parseHashComment();
700  return;
701  }
702  if ($nextTwoChars === '//') {
704  return;
705  }
706  if ($nextTwoChars === '/*') {
707  $this->‪parseMultilineComment();
708  return;
709  }
710  $currentPosition = $this->‪parseIdentifierUntilStopChar($splitLine, $isRelative);
711  if (!$currentPosition) {
712  return;
713  }
714  $this->currentLineString = substr($this->currentLineString, $currentPosition);
715  $this->currentColumnInLine = $this->currentColumnInLine + $currentPosition;
717  $this->‪makeComment();
718  }
719 
720  private function ‪parseIdentifierUntilStopChar(array $splitLine, bool $isRelative = false): ?int
721  {
722  $this->identifierStream = new ‪IdentifierTokenStream();
723  if ($isRelative) {
724  $this->identifierStream->setRelative();
725  }
726  $currentPosition = 0;
727  $currentIdentifierStartPosition = ‪$this->currentColumnInLine;
728  $currentIdentifierBody = '';
729  $currentIdentifierCharCount = 0;
730  while (true) {
731  $nextChar = $splitLine[$currentPosition] ?? null;
732  if ($nextChar === null) {
733  if ($currentIdentifierCharCount) {
734  $identifierToken = new ‪IdentifierToken(TokenType::T_IDENTIFIER, $currentIdentifierBody, $this->currentLineNumber, $currentIdentifierStartPosition);
735  $this->tokenStream->append($identifierToken);
736  $this->identifierStream->append($identifierToken);
737  }
739  return null;
740  }
741  $nextTwoChars = $nextChar . ($splitLine[$currentPosition + 1] ?? null);
742  if ($currentPosition > 0
743  && ($nextChar === ' ' || $nextChar === "\t" || $nextChar === '=' || $nextChar === '<' || $nextChar === '>' || $nextChar === '{' || $nextTwoChars === ':=' || $nextChar === '(')
744  ) {
745  if ($currentIdentifierCharCount) {
746  $identifierToken = new ‪IdentifierToken(TokenType::T_IDENTIFIER, $currentIdentifierBody, $this->currentLineNumber, $currentIdentifierStartPosition);
747  $this->tokenStream->append($identifierToken);
748  $this->identifierStream->append($identifierToken);
749  }
750  break;
751  }
752  if ($nextTwoChars === '\\.') {
753  // A quoted dot is part of *this* identifier
754  $currentIdentifierBody .= '.';
755  $currentPosition += 2;
756  $currentIdentifierCharCount++;
757  } elseif ($nextChar === '.') {
758  if ($currentIdentifierCharCount) {
759  $identifierToken = new ‪IdentifierToken(TokenType::T_IDENTIFIER, $currentIdentifierBody, $this->currentLineNumber, $currentIdentifierStartPosition);
760  $this->tokenStream->append($identifierToken);
761  $this->identifierStream->append($identifierToken);
762  $currentIdentifierCharCount = 0;
763  $currentIdentifierBody = '';
764  }
765  $this->tokenStream->append(new ‪Token(TokenType::T_DOT, '.', $this->currentLineNumber, $this->currentColumnInLine + $currentPosition));
766  $currentPosition++;
767  $currentIdentifierStartPosition = $this->currentColumnInLine + $currentPosition;
768  } else {
769  $currentIdentifierBody .= $nextChar;
770  $currentIdentifierCharCount++;
771  $currentPosition++;
772  }
773  }
774  return $currentPosition;
775  }
776 
777  private function ‪parseOperatorFunction(): void
778  {
779  $this->tokenStream->append(new ‪Token(TokenType::T_OPERATOR_FUNCTION, ':=', $this->currentLineNumber, $this->currentColumnInLine));
780  $this->currentColumnInLine += 2;
781  $this->currentLineString = substr($this->currentLineString, 2);
783  if ($this->currentLineString === '') {
785  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
786  return;
787  }
788  $functionName = '';
789  $functionNameStartPosition = ‪$this->currentColumnInLine;
790  $functionNameCharCount = 0;
791  $functionChars = mb_str_split($this->currentLineString, 1, 'UTF-8');
792  while (true) {
793  $nextChar = $functionChars[$functionNameCharCount] ?? null;
794  if ($nextChar === null) {
795  // end of chars
796  if ($functionNameCharCount) {
797  $this->tokenStream->append(new ‪Token(TokenType::T_FUNCTION_NAME, $functionName, $this->currentLineNumber, $functionNameStartPosition));
798  }
800  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
801  return;
802  }
803  if ($nextChar === '(') {
804  if ($functionNameCharCount) {
805  $functionNameToken = new ‪Token(TokenType::T_FUNCTION_NAME, $functionName, $this->currentLineNumber, $functionNameStartPosition);
806  $this->tokenStream->append($functionNameToken);
807  $this->tokenStream->append(new ‪Token(TokenType::T_FUNCTION_VALUE_START, '(', $this->currentLineNumber, $this->currentColumnInLine + $functionNameCharCount));
808  $functionNameCharCount++;
809  break;
810  }
811  $this->‪makeComment();
812  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
813  return;
814  }
815  $functionName .= $nextChar;
816  $functionNameCharCount++;
817  }
818  $functionBodyStartPosition = $functionNameCharCount;
819  $functionBody = '';
820  $functionBodyCharCount = 0;
821  $functionValueToken = false;
822  while (true) {
823  $nextChar = $functionChars[$functionBodyStartPosition + $functionBodyCharCount] ?? null;
824  if ($nextChar === null) {
825  if ($functionBodyCharCount) {
826  $this->tokenStream->append(new ‪Token(TokenType::T_VALUE, $functionBody, $this->currentLineNumber, $functionBodyCharCount));
827  }
829  $this->lineStream->append((new ‪InvalidLine())->setTokenStream($this->tokenStream));
830  return;
831  }
832  if ($nextChar === ')') {
833  if ($functionBodyCharCount) {
834  $functionValueToken = new ‪Token(TokenType::T_VALUE, $functionBody, $this->currentLineNumber, $this->currentColumnInLine + $functionNameCharCount);
835  $this->tokenStream->append($functionValueToken);
836  }
837  $this->tokenStream->append(new ‪Token(TokenType::T_FUNCTION_VALUE_STOP, ')', $this->currentLineNumber, $this->currentColumnInLine + $functionNameCharCount + $functionBodyCharCount));
838  $functionBodyCharCount++;
839  break;
840  }
841  $functionBody .= $nextChar;
842  $functionBodyCharCount++;
843  }
844  $this->currentColumnInLine = $this->currentColumnInLine + $functionNameCharCount + $functionBodyCharCount;
845  $this->currentLineString = substr($this->currentLineString, $functionNameCharCount + $functionBodyCharCount);
847  $this->‪makeComment();
848  $line = (new ‪IdentifierFunctionLine())
849  ->setIdentifierTokenStream($this->identifierStream)
850  ->setFunctionNameToken($functionNameToken)
851  ->setTokenStream($this->tokenStream);
852  if ($functionValueToken) {
853  $line->setFunctionValueToken($functionValueToken);
854  }
855  $this->lineStream->append($line);
856  }
857 
858  private function ‪parseValueForConstants(): void
859  {
860  if (!str_contains($this->currentLineString, '{$')) {
861  $valueToken = new ‪Token(TokenType::T_VALUE, $this->currentLineString, $this->currentLineNumber, $this->currentColumnInLine);
862  $this->tokenStream->append($valueToken);
863  $this->valueStream->append($valueToken);
864  return;
865  }
866  $splitLine = mb_str_split($this->currentLineString, 1, 'UTF-8');
867  $isInConstant = false;
868  $currentPosition = 0;
869  $currentString = '';
870  $currentStringLength = 0;
871  $lastTokenEndPosition = 0;
872  while (true) {
873  $char = $splitLine[$currentPosition] ?? null;
874  if ($char === null) {
875  if ($currentStringLength) {
876  $valueToken = new ‪Token(TokenType::T_VALUE, $currentString, $this->currentLineNumber, $this->currentColumnInLine + $lastTokenEndPosition);
877  $this->tokenStream->append($valueToken);
878  $this->valueStream->append($valueToken);
879  }
880  break;
881  }
882  $nextTwoChars = $char . ($splitLine[$currentPosition + 1] ?? '');
883  if ($nextTwoChars === '{$') {
884  $isInConstant = true;
885  if ($currentStringLength) {
886  $valueToken = new ‪Token(TokenType::T_VALUE, $currentString, $this->currentLineNumber, $this->currentColumnInLine + $lastTokenEndPosition);
887  $this->tokenStream->append($valueToken);
888  $this->valueStream->append($valueToken);
889  $lastTokenEndPosition = $currentPosition;
890  }
891  $currentString = '{$';
892  $currentPosition += 2;
893  continue;
894  }
895  if ($isInConstant && $char === '}') {
896  $valueToken = new ‪Token(TokenType::T_CONSTANT, $currentString . '}', $this->currentLineNumber, $this->currentColumnInLine + $lastTokenEndPosition);
897  $this->tokenStream->append($valueToken);
898  if (!$this->valueStream instanceof ‪ConstantAwareTokenStream) {
899  $this->valueStream = (new ‪ConstantAwareTokenStream())->setAll($this->valueStream->getAll());
900  }
901  $this->valueStream->append($valueToken);
902  $currentPosition++;
903  $currentString = '';
904  $currentStringLength = 0;
905  $lastTokenEndPosition = $currentPosition;
906  $isInConstant = false;
907  continue;
908  }
909  $currentPosition++;
910  $currentStringLength++;
911  $currentString .= $char;
912  }
913  }
914 }
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Line\CommentLine
Definition: CommentLine.php:29
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Token\T_IMPORT_KEYWORD_OLD_STOP
‪@ T_IMPORT_KEYWORD_OLD_STOP
Definition: TokenType.php:71
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\parseMultilineComment
‪parseMultilineComment()
Definition: LosslessTokenizer.php:206
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Line\ConditionElseLine
Definition: ConditionElseLine.php:25
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\parseOperatorUnset
‪parseOperatorUnset()
Definition: LosslessTokenizer.php:627
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\$lineStream
‪LineStream $lineStream
Definition: LosslessTokenizer.php:62
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\$identifierStream
‪IdentifierTokenStream $identifierStream
Definition: LosslessTokenizer.php:65
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Line\IdentifierUnsetLine
Definition: IdentifierUnsetLine.php:31
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\parseOperatorCopy
‪parseOperatorCopy()
Definition: LosslessTokenizer.php:637
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer
Definition: LosslessTokenizer.php:61
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Token\Token
Definition: Token.php:29
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Line\IdentifierAssignmentLine
Definition: IdentifierAssignmentLine.php:37
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Token\TokenStreamInterface\append
‪append(TokenInterface $token)
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Line\IdentifierCopyLine
Definition: IdentifierCopyLine.php:37
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\createBlockStopLine
‪createBlockStopLine()
Definition: LosslessTokenizer.php:324
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\createMultilineCommentLine
‪createMultilineCommentLine()
Definition: LosslessTokenizer.php:200
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\createConditionLine
‪createConditionLine()
Definition: LosslessTokenizer.php:237
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Token\TokenType
‪TokenType
Definition: TokenType.php:26
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Token\IdentifierTokenStream
Definition: IdentifierTokenStream.php:44
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Line\BlockCloseLine
Definition: BlockCloseLine.php:25
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Line\ImportLine
Definition: ImportLine.php:33
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Line\ImportOldLine
Definition: ImportOldLine.php:32
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Line\ConditionStopLine
Definition: ConditionStopLine.php:26
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\createEmptyLine
‪createEmptyLine()
Definition: LosslessTokenizer.php:139
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\parseIdentifierUntilStopChar
‪parseIdentifierUntilStopChar(array $splitLine, bool $isRelative=false)
Definition: LosslessTokenizer.php:720
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\parseBlockStart
‪parseBlockStart()
Definition: LosslessTokenizer.php:333
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\parseIdentifierAtEndOfLine
‪parseIdentifierAtEndOfLine()
Definition: LosslessTokenizer.php:679
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\$currentLineString
‪string $currentLineString
Definition: LosslessTokenizer.php:70
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Line\IdentifierReferenceLine
Definition: IdentifierReferenceLine.php:35
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\parseTabsAndWhitespaces
‪parseTabsAndWhitespaces()
Definition: LosslessTokenizer.php:147
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\tokenize
‪tokenize(string $source)
Definition: LosslessTokenizer.php:74
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Token\TokenStreamInterface
Definition: TokenStreamInterface.php:30
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\parseImportOld
‪parseImportOld()
Definition: LosslessTokenizer.php:418
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\parseValueForConstants
‪parseValueForConstants()
Definition: LosslessTokenizer.php:858
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\parseOperatorReference
‪parseOperatorReference()
Definition: LosslessTokenizer.php:658
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Line\IdentifierFunctionLine
Definition: IdentifierFunctionLine.php:34
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\$currentLinebreakCallback
‪closure $currentLinebreakCallback
Definition: LosslessTokenizer.php:71
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\$tokenStream
‪TokenStreamInterface $tokenStream
Definition: LosslessTokenizer.php:64
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Line\IdentifierBlockOpenLine
Definition: IdentifierBlockOpenLine.php:31
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\parseDoubleSlashComment
‪parseDoubleSlashComment()
Definition: LosslessTokenizer.php:194
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\parseOperatorMultilineAssignment
‪parseOperatorMultilineAssignment()
Definition: LosslessTokenizer.php:543
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Token\TokenStream
Definition: TokenStream.php:26
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\parseHashComment
‪parseHashComment()
Definition: LosslessTokenizer.php:182
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\$lines
‪array $lines
Definition: LosslessTokenizer.php:68
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Line\EmptyLine
Definition: EmptyLine.php:32
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Token\ConstantAwareTokenStream
Definition: ConstantAwareTokenStream.php:29
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\splitLines
‪splitLines($source)
Definition: LosslessTokenizer.php:122
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\parseOperatorFunction
‪parseOperatorFunction()
Definition: LosslessTokenizer.php:777
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Token\IdentifierTokenStream\append
‪append(TokenInterface $token)
Definition: IdentifierTokenStream.php:78
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Line\ConditionLine
Definition: ConditionLine.php:29
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\$currentColumnInLine
‪int $currentColumnInLine
Definition: LosslessTokenizer.php:72
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\$valueStream
‪TokenStreamInterface $valueStream
Definition: LosslessTokenizer.php:66
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\makeComment
‪makeComment()
Definition: LosslessTokenizer.php:157
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\parseOperatorAssignment
‪parseOperatorAssignment()
Definition: LosslessTokenizer.php:531
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Token\IdentifierToken
Definition: IdentifierToken.php:34
‪TYPO3\CMS\Core\TypoScript\Tokenizer\TokenizerInterface
Definition: TokenizerInterface.php:40
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\createDoubleSlashCommentLine
‪createDoubleSlashCommentLine()
Definition: LosslessTokenizer.php:188
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\createHashCommentLine
‪createHashCommentLine()
Definition: LosslessTokenizer.php:176
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\parseIdentifier
‪parseIdentifier()
Definition: LosslessTokenizer.php:467
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\parseImportLine
‪parseImportLine()
Definition: LosslessTokenizer.php:354
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer\$currentLineNumber
‪int $currentLineNumber
Definition: LosslessTokenizer.php:69
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Line\LineStream
Definition: LineStream.php:29
‪TYPO3\CMS\Core\TypoScript\Tokenizer
‪TYPO3\CMS\Core\TypoScript\Tokenizer\Line\InvalidLine
Definition: InvalidLine.php:33