77 current_pos_datetime int
88}
99
10+ @[inline]
11+ fn (p &DateTimeParser) matches_at (chars string ) bool {
12+ end := p.current_pos_datetime + chars.len
13+ if end > p.datetime.len {
14+ return false
15+ }
16+ for i in 0 .. chars.len {
17+ if p.datetime[p.current_pos_datetime + i] != chars[i] {
18+ return false
19+ }
20+ }
21+ return true
22+ }
23+
1024fn (mut p DateTimeParser) next (length int ) ! string {
1125 if p.current_pos_datetime + length > p.datetime.len {
1226 return error ('end of string' )
@@ -24,38 +38,61 @@ fn (mut p DateTimeParser) peek(length int) !string {
2438}
2539
2640fn (mut p DateTimeParser) must_be_int (length int ) ! int {
27- val := p.next (length)!
28- if ! val.contains_only ('0123456789' ) {
29- return error ('expected int, found: ${val }' )
41+ end := p.current_pos_datetime + length
42+ if end > p.datetime.len {
43+ return error ('end of string' )
44+ }
45+ mut val := 0
46+ for i in p.current_pos_datetime .. end {
47+ ch := p.datetime[i]
48+ if ch < `0` || ch > `9` {
49+ return error ('expected int, found: ${p .datetime [p .current_pos_datetime ..end ]}' )
50+ }
51+ val = val * 10 + int (ch - `0` )
3052 }
31- return val.int ()
53+ p.current_pos_datetime = end
54+ return val
3255}
3356
3457fn (mut p DateTimeParser) must_be_int_with_minimum_length (min int , max int , allow_leading_zero bool ) ! int {
35- mut length := max + 1 - min
36- mut val := ''
37- for _ in 0 .. length {
38- tok := p. peek ( 1 ) or { break }
39- if ! tok. contains_only ( '0123456789' ) {
58+ max_len := max + 1 - min
59+ start := p.current_pos_datetime
60+ mut end := start
61+ for _ in 0 .. max_len {
62+ if end > = p.datetime.len {
4063 break
4164 }
42- p.next (1 )!
43- val + = tok
65+ ch := p.datetime[end]
66+ if ch < `0` || ch > `9` {
67+ break
68+ }
69+ end++
4470 }
45- if val.len < min {
46- return error ('expected int with a minimum length of ${min }, found: ${val . len }' )
71+ if end - start < min {
72+ return error ('expected int with a minimum length of ${min }, found: ${end - start }' )
4773 }
48- if ! allow_leading_zero && val. starts_with ( '0' ) {
74+ if ! allow_leading_zero && p.datetime[start] == `0` {
4975 return error ('0 is not allowed for this format' )
5076 }
51- return val.int ()
77+ mut val := 0
78+ for i in start .. end {
79+ val = val * 10 + int (p.datetime[i] - `0` )
80+ }
81+ p.current_pos_datetime = end
82+ return val
5283}
5384
5485fn (mut p DateTimeParser) must_be_string (must string ) ! {
55- val := p.next (must.len)!
56- if val != must {
57- return error ('invalid string: "${val }"!="${must }" at: ${p .current_pos_datetime }' )
86+ start := p.current_pos_datetime
87+ end := p.current_pos_datetime + must.len
88+ if end > p.datetime.len {
89+ return error ('end of string' )
90+ }
91+ if ! p.matches_at (must) {
92+ p.current_pos_datetime = end
93+ return error ('invalid string: "${p .datetime [start ..end ]}"!="${must }" at: ${p .current_pos_datetime }' )
5894 }
95+ p.current_pos_datetime = end
5996}
6097
6198fn (mut p DateTimeParser) must_be_string_one_of (oneof []string ) ! string {
@@ -70,22 +107,19 @@ fn (mut p DateTimeParser) must_be_string_one_of(oneof []string) !string {
70107
71108fn (mut p DateTimeParser) must_be_valid_month () ! int {
72109 for v in long_months {
73- if p.current_pos_datetime + v.len < p.datetime.len {
74- month_name := p.datetime[p.current_pos_datetime..p.current_pos_datetime + v.len]
75- if v == month_name {
76- p.current_pos_datetime + = v.len
77- return long_months.index (month_name) + 1
78- }
110+ if p.current_pos_datetime + v.len < p.datetime.len && p.matches_at (v) {
111+ p.current_pos_datetime + = v.len
112+ return long_months.index (v) + 1
79113 }
80114 }
81115 return error_invalid_time (0 , 'invalid month name, at: ${p .current_pos_datetime }' )
82116}
83117
84118fn (mut p DateTimeParser) must_be_valid_three_letter_month () ! int {
85119 if p.current_pos_datetime + 3 < p.datetime.len {
86- letters := p.datetime[p.current_pos_datetime..p.current_pos_datetime + 3 ]
87120 for m := 1 ; m < = long_months.len; m++ {
88- if months_string[(m - 1 ) * 3 ..m * 3 ] == letters {
121+ token := months_string[(m - 1 ) * 3 ..m * 3 ]
122+ if p.matches_at (token) {
89123 p.current_pos_datetime + = 3
90124 return m
91125 }
@@ -96,22 +130,19 @@ fn (mut p DateTimeParser) must_be_valid_three_letter_month() !int {
96130
97131fn (mut p DateTimeParser) must_be_valid_week_day () ! string {
98132 for v in long_days {
99- if p.current_pos_datetime + v.len < p.datetime.len {
100- weekday := p.datetime[p.current_pos_datetime..p.current_pos_datetime + v.len]
101- if v == weekday {
102- p.current_pos_datetime + = v.len
103- return weekday
104- }
133+ if p.current_pos_datetime + v.len < p.datetime.len && p.matches_at (v) {
134+ p.current_pos_datetime + = v.len
135+ return v
105136 }
106137 }
107138 return error_invalid_time (0 , 'invalid weekday, at: ${p .current_pos_datetime }' )
108139}
109140
110141fn (mut p DateTimeParser) must_be_valid_two_letter_week_day () ! int {
111142 if p.current_pos_datetime + 2 < p.datetime.len {
112- letters := p.datetime[p.current_pos_datetime..p.current_pos_datetime + 2 ]
113143 for d := 1 ; d < = long_days.len; d++ {
114- if days_string[(d - 1 ) * 3 ..d * 3 - 1 ] == letters {
144+ token := days_string[(d - 1 ) * 3 ..d * 3 - 1 ]
145+ if p.matches_at (token) {
115146 p.current_pos_datetime + = 2
116147 return d
117148 }
@@ -122,9 +153,9 @@ fn (mut p DateTimeParser) must_be_valid_two_letter_week_day() !int {
122153
123154fn (mut p DateTimeParser) must_be_valid_three_letter_week_day () ! int {
124155 if p.current_pos_datetime + 3 < p.datetime.len {
125- letters := p.datetime[p.current_pos_datetime..p.current_pos_datetime + 3 ]
126156 for d := 1 ; d < = long_days.len; d++ {
127- if days_string[(d - 1 ) * 3 ..d * 3 ] == letters {
157+ token := days_string[(d - 1 ) * 3 ..d * 3 ]
158+ if p.matches_at (token) {
128159 p.current_pos_datetime + = 3
129160 return d
130161 }
@@ -135,18 +166,17 @@ fn (mut p DateTimeParser) must_be_valid_three_letter_week_day() !int {
135166
136167fn extract_tokens (s string ) ! []string {
137168 mut tokens := []string {}
138- mut current := ''
139- for r in s {
140- if current.contains_only (r.ascii_str ()) || current == '' {
141- current + = r.ascii_str ()
142- } else {
143- tokens << current
144- current = r.ascii_str ()
145- }
169+ if s.len == 0 {
170+ return tokens
146171 }
147- if current != '' {
148- tokens << current
172+ mut start := 0
173+ for i := 1 ; i < s.len; i++ {
174+ if s[i] != s[i - 1 ] {
175+ tokens << s[start..i]
176+ start = i
177+ }
149178 }
179+ tokens << s[start..s.len]
150180 return tokens
151181}
152182
0 commit comments