Skip to content

Commit f05f232

Browse files
committed
added Position to Token
1 parent b8affec commit f05f232

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
@@ -59,27 +59,45 @@ public function tokenize(string $input): TokenStream
5959
}
6060

6161
$types = array_keys(self::Patterns);
62-
$offset = 0;
62+
$position = new Position;
6363

6464
$tokens = [];
6565
foreach ($matches as $match) {
6666
$type = $types[count($match) - 2];
67-
$tokens[] = new Token($type === Token::Char ? $match[0] : $type, $match[0]);
68-
$offset += strlen($match[0]);
67+
$tokens[] = new Token($type === Token::Char ? $match[0] : $type, $match[0], $position);
68+
$position = $this->advance($position, $match[0]);
6969
}
7070

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

7373
$stream = new TokenStream($tokens);
74-
if ($offset !== strlen($input)) {
75-
$s = str_replace("\n", '\n', substr($input, $offset, 40));
74+
if ($position->offset !== strlen($input)) {
75+
$s = str_replace("\n", '\n', substr($input, $position->offset, 40));
7676
$stream->error("Unexpected '$s'", count($tokens) - 1);
7777
}
7878

7979
return $stream;
8080
}
8181

8282

83+
private function advance(Position $position, string $str): Position
84+
{
85+
if ($lines = substr_count($str, "\n")) {
86+
return new Position(
87+
$position->line + $lines,
88+
strlen($str) - strrpos($str, "\n"),
89+
$position->offset + strlen($str),
90+
);
91+
} else {
92+
return new Position(
93+
$position->line,
94+
$position->column + strlen($str),
95+
$position->offset + strlen($str),
96+
);
97+
}
98+
}
99+
100+
83101
public static function requiresDelimiters(string $s): bool
84102
{
85103
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
@@ -76,21 +76,10 @@ public function getIndentation(): string
7676
public function error(?string $message = null, ?int $pos = null): void
7777
{
7878
$pos ??= $this->index;
79-
$input = '';
80-
foreach ($this->tokens as $i => $token) {
81-
if ($i >= $pos) {
82-
break;
83-
}
84-
85-
$input .= $token->text;
86-
}
87-
88-
$line = substr_count($input, "\n") + 1;
89-
$col = strlen($input) - strrpos("\n" . $input, "\n") + 1;
9079
$token = $this->tokens[$pos];
9180
$message ??= 'Unexpected ' . ($token->type === Token::End
9281
? 'end'
93-
: "'" . str_replace("\n", '<new line>', substr($this->tokens[$pos]->text, 0, 40)) . "'");
94-
throw new Exception("$message on line $line at column $col");
82+
: "'" . str_replace("\n", '<new line>', substr($token->text, 0, 40)) . "'");
83+
throw new Exception("$message $token->position");
9584
}
9685
}

0 commit comments

Comments
 (0)