|
16 | 16 | use DevTheorem\HandlebarsParser\Ast\InverseChain; |
17 | 17 | use DevTheorem\HandlebarsParser\Ast\Literal; |
18 | 18 | use DevTheorem\HandlebarsParser\Ast\MustacheStatement; |
| 19 | +use DevTheorem\HandlebarsParser\Ast\Node; |
19 | 20 | use DevTheorem\HandlebarsParser\Ast\OpenBlock; |
20 | 21 | use DevTheorem\HandlebarsParser\Ast\OpenHelper; |
21 | 22 | use DevTheorem\HandlebarsParser\Ast\OpenPartialBlock; |
@@ -167,13 +168,14 @@ protected function postprocessTokens(array $tokens): array |
167 | 168 |
|
168 | 169 | if ($numTokens === 0) { |
169 | 170 | // empty input - just add sentinel token |
170 | | - return [new Token(Lexer::T_EOF, "\0", 0)]; |
| 171 | + return [new Token(Lexer::T_EOF, "\0", 0, 0)]; |
171 | 172 | } |
172 | 173 |
|
173 | 174 | $lastToken = $tokens[$numTokens - 1]; |
174 | 175 |
|
175 | 176 | // Add sentinel token |
176 | | - $tokens[] = new Token(Lexer::T_EOF, "\0", $lastToken->line); |
| 177 | + $column = $lastToken->column + strlen($lastToken->text); |
| 178 | + $tokens[] = new Token(Lexer::T_EOF, "\0", $lastToken->line, $column); |
177 | 179 | return $tokens; |
178 | 180 | } |
179 | 181 |
|
@@ -384,6 +386,12 @@ protected function getErrorMessage(int $symbol, int $state, int $line): string |
384 | 386 | return "Parse error on line $line" . $expectedString . ', got ' . $this->symbolToName[$symbol]; |
385 | 387 | } |
386 | 388 |
|
| 389 | + private function getNodeError(string $message, Node $node): string |
| 390 | + { |
| 391 | + $start = $node->loc->start; |
| 392 | + return $message . ' - ' . $start->line . ':' . $start->column; |
| 393 | + } |
| 394 | + |
387 | 395 | /** |
388 | 396 | * Get limited number of expected tokens in given state. |
389 | 397 | * |
@@ -505,7 +513,10 @@ protected function locInfo(int $tokenStartPos, int $tokenEndPos): SourceLocation |
505 | 513 | $source .= $token->text; |
506 | 514 | } |
507 | 515 |
|
508 | | - return new SourceLocation($source, new Position($startToken->line, -1), new Position($endToken->line, -1)); |
| 516 | + $start = new Position($startToken->line, $startToken->column); |
| 517 | + $end = new Position($endToken->line, $endToken->column + strlen($endToken->text) - 1); |
| 518 | + |
| 519 | + return new SourceLocation($source, $start, $end); |
509 | 520 | } |
510 | 521 |
|
511 | 522 | protected function id(string $token): string |
@@ -539,7 +550,7 @@ protected function prepareProgram(array $statements, ?SourceLocation $loc = null |
539 | 550 | $lastLoc = $statements[count($statements) - 1]->loc; |
540 | 551 | $loc = new SourceLocation($firstLoc->source, $firstLoc->start, $lastLoc->end); |
541 | 552 | } else { |
542 | | - $loc = new SourceLocation('', new Position(0, -1), new Position(0, -1)); |
| 553 | + $loc = new SourceLocation('', new Position(0, 0), new Position(0, 0)); |
543 | 554 | } |
544 | 555 | } |
545 | 556 |
|
@@ -579,7 +590,8 @@ private function validateClose(OpenHelper $open, CloseBlock|string $close): void |
579 | 590 | } |
580 | 591 |
|
581 | 592 | if ($open->path->original !== $close) { |
582 | | - throw new \Exception("{$open->path->original} doesn't match {$close}"); |
| 593 | + $msg = $this->getNodeError("{$open->path->original} doesn't match {$close}", $open->path); |
| 594 | + throw new \Exception($msg); |
583 | 595 | } |
584 | 596 | } |
585 | 597 |
|
@@ -610,7 +622,8 @@ protected function preparePath(bool $data, SubExpression|null $sexpr, array $par |
610 | 622 |
|
611 | 623 | if (!$isLiteral && ($part === '..' || $part === '.' || $part === 'this')) { |
612 | 624 | if (count($tail) > 0) { |
613 | | - throw new \Exception('Invalid path: ' . $original); |
| 625 | + $msg = $this->getNodeError("Invalid path: $original", new Node('', $loc)); |
| 626 | + throw new \Exception($msg); |
614 | 627 | } elseif ($part === '..') { |
615 | 628 | $depth++; |
616 | 629 | } |
|
0 commit comments