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