Skip to content

Commit 39d477e

Browse files
committed
added Position to Token
1 parent 09e1f43 commit 39d477e

File tree

4 files changed

+54
-19
lines changed

4 files changed

+54
-19
lines changed

src/Neon/Lexer.php

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,27 +56,45 @@ public function tokenize(string $input): TokenStream
5656
}
5757

5858
$types = array_keys(self::Patterns);
59-
$offset = 0;
59+
$position = new Position;
6060

6161
$tokens = [];
6262
foreach ($matches as $match) {
6363
$type = $types[count($match) - 2];
64-
$tokens[] = new Token($type === Token::Char ? $match[0] : $type, $match[0]);
65-
$offset += strlen($match[0]);
64+
$tokens[] = new Token($type === Token::Char ? $match[0] : $type, $match[0], $position);
65+
$position = $this->advance($position, $match[0]);
6666
}
6767

68-
$tokens[] = new Token(Token::End, '');
68+
$tokens[] = new Token(Token::End, '', $position);
6969

7070
$stream = new TokenStream($tokens);
71-
if ($offset !== strlen($input)) {
72-
$s = str_replace("\n", '\n', substr($input, $offset, 40));
71+
if ($position->offset !== strlen($input)) {
72+
$s = str_replace("\n", '\n', substr($input, $position->offset, 40));
7373
$stream->error("Unexpected '$s'", count($tokens) - 1);
7474
}
7575

7676
return $stream;
7777
}
7878

7979

80+
private function advance(Position $position, string $str): Position
81+
{
82+
if ($lines = substr_count($str, "\n")) {
83+
return new Position(
84+
$position->line + $lines,
85+
strlen($str) - strrpos($str, "\n"),
86+
$position->offset + strlen($str),
87+
);
88+
} else {
89+
return new Position(
90+
$position->line,
91+
$position->column + strlen($str),
92+
$position->offset + strlen($str),
93+
);
94+
}
95+
}
96+
97+
8098
public static function requiresDelimiters(string $s): bool
8199
{
82100
return preg_match('~[\x00-\x1F]|^[+-.]?\d|^(true|false|yes|no|on|off|null)$~Di', $s)

src/Neon/Position.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/**
4+
* This file is part of the Nette Framework (https://nette.org)
5+
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace Nette\Neon;
11+
12+
13+
final class Position
14+
{
15+
public function __construct(
16+
public /*readonly*/ int $line = 1,
17+
public /*readonly*/ int $column = 1,
18+
public /*readonly*/ int $offset = 0,
19+
) {
20+
}
21+
22+
23+
public function __toString(): string
24+
{
25+
return "on line $this->line" . ($this->column ? " at column $this->column" : '');
26+
}
27+
}

src/Neon/Token.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ final class Token
2525
public function __construct(
2626
public int|string $type,
2727
public string $text,
28+
public Position $position,
2829
) {
2930
}
3031

src/Neon/TokenStream.php

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -74,21 +74,10 @@ public function getIndentation(): string
7474
public function error(?string $message = null, ?int $pos = null): void
7575
{
7676
$pos ??= $this->index;
77-
$input = '';
78-
foreach ($this->tokens as $i => $token) {
79-
if ($i >= $pos) {
80-
break;
81-
}
82-
83-
$input .= $token->text;
84-
}
85-
86-
$line = substr_count($input, "\n") + 1;
87-
$col = strlen($input) - strrpos("\n" . $input, "\n") + 1;
8877
$token = $this->tokens[$pos];
8978
$message ??= 'Unexpected ' . ($token->type === Token::End
9079
? 'end'
91-
: "'" . str_replace("\n", '<new line>', substr($this->tokens[$pos]->text, 0, 40)) . "'");
92-
throw new Exception("$message on line $line at column $col");
80+
: "'" . str_replace("\n", '<new line>', substr($token->text, 0, 40)) . "'");
81+
throw new Exception("$message $token->position");
9382
}
9483
}

0 commit comments

Comments
 (0)