@@ -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 )
0 commit comments