@@ -21,9 +21,10 @@ const (
2121
2222// Lexer represents a lexical analyzer for TSL
2323type Lexer struct {
24- input string
25- pos int // current position
26- start int // start of current token
24+ input string // original input string
25+ runes []rune // input as runes for proper UTF-8 handling
26+ pos int // current position (rune index)
27+ start int // start of current token (rune index)
2728 tokens []Token
2829 current int // current token index
2930}
5859func NewLexer (input string ) * Lexer {
5960 return & Lexer {
6061 input : input ,
62+ runes : []rune (input ),
6163 pos : 0 ,
6264 start : 0 ,
6365 tokens : make ([]Token , 0 ),
@@ -80,38 +82,38 @@ func (l *Lexer) Tokenize() error {
8082
8183// isAtEnd checks if we're at the end of input
8284func (l * Lexer ) isAtEnd () bool {
83- return l .pos >= len (l .input )
85+ return l .pos >= len (l .runes )
8486}
8587
8688// peek returns the current character without advancing
8789func (l * Lexer ) peek () rune {
8890 if l .isAtEnd () {
8991 return 0
9092 }
91- return rune ( l . input [l .pos ])
93+ return l . runes [l .pos ]
9294}
9395
9496// peekNext returns the next character without advancing
9597func (l * Lexer ) peekNext () rune {
96- if l .pos + 1 >= len (l .input ) {
98+ if l .pos + 1 >= len (l .runes ) {
9799 return 0
98100 }
99- return rune ( l . input [l .pos + 1 ])
101+ return l . runes [l .pos + 1 ]
100102}
101103
102104// advance consumes and returns the current character
103105func (l * Lexer ) advance () rune {
104106 if l .isAtEnd () {
105107 return 0
106108 }
107- c := rune ( l . input [l .pos ])
109+ c := l . runes [l .pos ]
108110 l .pos ++
109111 return c
110112}
111113
112114// match checks if current character matches expected and advances if so
113115func (l * Lexer ) match (expected rune ) bool {
114- if l .isAtEnd () || rune ( l . input [l .pos ]) != expected {
116+ if l .isAtEnd () || l . runes [l .pos ] != expected {
115117 return false
116118 }
117119 l .pos ++
@@ -227,11 +229,11 @@ func (l *Lexer) scanToken() error {
227229// isDateTimePattern checks if the current position starts a date or time pattern
228230func (l * Lexer ) isDateTimePattern () bool {
229231 // Look ahead to see if this matches a date or RFC3339 pattern
230- remaining := l .input [l .pos :]
232+ remaining := l .runes [l .pos :]
231233
232234 // Try to match date pattern (YYYY-MM-DD)
233235 if len (remaining ) >= 10 {
234- dateCandidate := remaining [:10 ]
236+ dateCandidate := string ( remaining [:10 ])
235237 if datePattern .MatchString (dateCandidate ) {
236238 // Check if it continues as RFC3339 (has T after date)
237239 if len (remaining ) > 10 && remaining [10 ] == 'T' {
@@ -240,12 +242,12 @@ func (l *Lexer) isDateTimePattern() bool {
240242 c := remaining [i ]
241243 if c == ' ' || c == '\t' || c == '\n' || c == ')' || c == ',' {
242244 // End of potential timestamp
243- candidate := remaining [:i ]
245+ candidate := string ( remaining [:i ])
244246 return rfc3339Pattern .MatchString (candidate )
245247 }
246248 }
247249 // Check the whole remaining string
248- return rfc3339Pattern .MatchString (remaining )
250+ return rfc3339Pattern .MatchString (string ( remaining ) )
249251 }
250252 return true // Just a date
251253 }
@@ -267,7 +269,7 @@ func (l *Lexer) scanDateTime() error {
267269 l .advance ()
268270 }
269271
270- value := l . input [start :l .pos ]
272+ value := string ( l . runes [start :l .pos ])
271273
272274 // Check if it's a date or RFC3339 format
273275 if rfc3339Pattern .MatchString (value ) {
@@ -391,7 +393,7 @@ func (l *Lexer) scanNumber() error {
391393 }
392394 }
393395
394- value := l . input [start :l .pos ]
396+ value := string ( l . runes [start :l .pos ])
395397 l .addToken (NUMERIC_LITERAL , value )
396398 return nil
397399}
@@ -430,7 +432,7 @@ func (l *Lexer) scanIdentifier() error {
430432 }
431433 }
432434
433- value := l . input [start :l .pos ]
435+ value := string ( l . runes [start :l .pos ])
434436
435437 // Check if it's a keyword (case-insensitive)
436438 lowerValue := strings .ToLower (value )
@@ -446,7 +448,7 @@ func (l *Lexer) scanIdentifier() error {
446448// NextToken returns the next token for the parser
447449func (l * Lexer ) NextToken () Token {
448450 if l .current >= len (l .tokens ) {
449- return Token {Type : EOF , Value : "" , Position : len (l .input )}
451+ return Token {Type : EOF , Value : "" , Position : len (l .runes )}
450452 }
451453 token := l .tokens [l .current ]
452454 l .current ++
@@ -456,7 +458,7 @@ func (l *Lexer) NextToken() Token {
456458// Peek returns the current token without advancing
457459func (l * Lexer ) PeekToken () Token {
458460 if l .current >= len (l .tokens ) {
459- return Token {Type : EOF , Value : "" , Position : len (l .input )}
461+ return Token {Type : EOF , Value : "" , Position : len (l .runes )}
460462 }
461463 return l .tokens [l .current ]
462464}
0 commit comments