@@ -110,8 +110,45 @@ impl Scanner {
110110 pub ( crate ) fn step ( & mut self , c : char ) -> Op {
111111 self . position += 1 ;
112112 match self . state {
113- State :: BeginValue => self . begin_value ( c) ,
113+ State :: BeginValue
114+ | State :: BeginValueOrEmpty
115+ | State :: BeginStringOrEmpty
116+ | State :: BeginString
117+ | State :: EndValue
118+ | State :: EndTop => self . step_structural_state ( c) ,
119+ State :: InString
120+ | State :: InStringEsc
121+ | State :: InStringEscU
122+ | State :: InStringEscU1
123+ | State :: InStringEscU12
124+ | State :: InStringEscU123 => self . step_string_state ( c) ,
125+ State :: Neg
126+ | State :: Num0
127+ | State :: Num1
128+ | State :: Dot
129+ | State :: Dot0
130+ | State :: Exp
131+ | State :: ExpSign
132+ | State :: Exp0 => self . step_number_state ( c) ,
133+ State :: T
134+ | State :: Tr
135+ | State :: Tru
136+ | State :: F
137+ | State :: Fa
138+ | State :: Fal
139+ | State :: Fals
140+ | State :: N
141+ | State :: Nu
142+ | State :: Nul => self . step_literal_state ( c) ,
143+ State :: Error => Op :: Error ,
144+ }
145+ }
146+
147+ // --- Helper methods ---
114148
149+ fn step_structural_state ( & mut self , c : char ) -> Op {
150+ match self . state {
151+ State :: BeginValue => self . begin_value ( c) ,
115152 State :: BeginValueOrEmpty => {
116153 if is_space ( c) {
117154 return Op :: SkipSpace ;
@@ -121,7 +158,6 @@ impl Scanner {
121158 }
122159 self . begin_value ( c)
123160 }
124-
125161 State :: BeginStringOrEmpty => {
126162 if is_space ( c) {
127163 return Op :: SkipSpace ;
@@ -136,105 +172,43 @@ impl Scanner {
136172 }
137173 self . begin_string ( c)
138174 }
139-
140175 State :: BeginString => self . begin_string ( c) ,
141176 State :: EndValue => self . end_value ( c) ,
142177 State :: EndTop => self . end_top ( c) ,
178+ _ => unreachable ! ( "non-structural JSON scanner state" ) ,
179+ }
180+ }
143181
144- State :: InString => match c {
145- '"' => {
146- self . state = State :: EndValue ;
147- Op :: Continue
148- }
149- '\\' => {
150- self . state = State :: InStringEsc ;
151- Op :: Continue
152- }
153- '\x00' ..'\x20' => self . error ( c, "in string literal" ) ,
154- _ => Op :: Continue ,
155- } ,
156-
157- State :: InStringEsc => match c {
158- 'b' | 'f' | 'n' | 'r' | 't' | '\\' | '/' | '"' => {
159- self . state = State :: InString ;
160- Op :: Continue
161- }
162- 'u' => {
163- self . state = State :: InStringEscU ;
164- Op :: Continue
165- }
166- _ => self . error ( c, "in string escape code" ) ,
167- } ,
168-
182+ fn step_string_state ( & mut self , c : char ) -> Op {
183+ match self . state {
184+ State :: InString => self . in_string ( c) ,
185+ State :: InStringEsc => self . in_string_escape ( c) ,
169186 // Four hex digits for \uXXXX
170187 State :: InStringEscU => self . hex_digit ( c, State :: InStringEscU1 ) ,
171188 State :: InStringEscU1 => self . hex_digit ( c, State :: InStringEscU12 ) ,
172189 State :: InStringEscU12 => self . hex_digit ( c, State :: InStringEscU123 ) ,
173190 State :: InStringEscU123 => self . hex_digit ( c, State :: InString ) ,
191+ _ => unreachable ! ( "non-string JSON scanner state" ) ,
192+ }
193+ }
174194
175- State :: Neg => {
176- if c == '0' {
177- self . state = State :: Num0 ;
178- Op :: Continue
179- } else if ( '1' ..='9' ) . contains ( & c) {
180- self . state = State :: Num1 ;
181- Op :: Continue
182- } else {
183- self . error ( c, "in numeric literal" )
184- }
185- }
186-
195+ fn step_number_state ( & mut self , c : char ) -> Op {
196+ match self . state {
197+ State :: Neg => self . neg ( c) ,
187198 // Non-zero integer: keep consuming digits, then fall through to Num0 logic.
188- State :: Num1 => {
189- if c. is_ascii_digit ( ) {
190- Op :: Continue
191- } else {
192- self . num0 ( c)
193- }
194- }
195-
196- State :: Num0 => self . num0 ( c) ,
197-
198- State :: Dot => {
199- if c. is_ascii_digit ( ) {
200- self . state = State :: Dot0 ;
201- Op :: Continue
202- } else {
203- self . error ( c, "after decimal point in numeric literal" )
204- }
205- }
206-
207- State :: Dot0 => {
208- if c. is_ascii_digit ( ) {
209- Op :: Continue
210- } else if c == 'e' || c == 'E' {
211- self . state = State :: Exp ;
212- Op :: Continue
213- } else {
214- self . end_value ( c)
215- }
216- }
217-
218- State :: Exp => {
219- if c == '+' || c == '-' {
220- self . state = State :: ExpSign ;
221- Op :: Continue
222- } else {
223- self . exp_sign ( c)
224- }
225- }
226-
199+ State :: Num1 | State :: Exp0 if c. is_ascii_digit ( ) => Op :: Continue ,
200+ State :: Num1 | State :: Num0 => self . num0 ( c) ,
201+ State :: Dot => self . dot ( c) ,
202+ State :: Dot0 => self . dot0 ( c) ,
203+ State :: Exp => self . exp ( c) ,
227204 State :: ExpSign => self . exp_sign ( c) ,
205+ State :: Exp0 => self . end_value ( c) ,
206+ _ => unreachable ! ( "non-number JSON scanner state" ) ,
207+ }
208+ }
228209
229- State :: Exp0 => {
230- if c. is_ascii_digit ( ) {
231- Op :: Continue
232- } else {
233- self . end_value ( c)
234- }
235- }
236-
237- // Literal keywords: "true", "false", "null"
210+ fn step_literal_state ( & mut self , c : char ) -> Op {
211+ match self . state {
238212 State :: T => self . lit ( c, 'r' , State :: Tr , "in literal true (expecting 'r')" ) ,
239213 State :: Tr => self . lit ( c, 'u' , State :: Tru , "in literal true (expecting 'u')" ) ,
240214 State :: Tru => self . lit_end ( c, 'e' , "in literal true (expecting 'e')" ) ,
@@ -245,12 +219,79 @@ impl Scanner {
245219 State :: N => self . lit ( c, 'u' , State :: Nu , "in literal null (expecting 'u')" ) ,
246220 State :: Nu => self . lit ( c, 'l' , State :: Nul , "in literal null (expecting 'l')" ) ,
247221 State :: Nul => self . lit_end ( c, 'l' , "in literal null (expecting 'l')" ) ,
222+ _ => unreachable ! ( "non-literal JSON scanner state" ) ,
223+ }
224+ }
248225
249- State :: Error => Op :: Error ,
226+ fn in_string ( & mut self , c : char ) -> Op {
227+ match c {
228+ '"' => {
229+ self . state = State :: EndValue ;
230+ Op :: Continue
231+ }
232+ '\\' => {
233+ self . state = State :: InStringEsc ;
234+ Op :: Continue
235+ }
236+ '\x00' ..'\x20' => self . error ( c, "in string literal" ) ,
237+ _ => Op :: Continue ,
250238 }
251239 }
252240
253- // --- Helper methods ---
241+ fn in_string_escape ( & mut self , c : char ) -> Op {
242+ match c {
243+ 'b' | 'f' | 'n' | 'r' | 't' | '\\' | '/' | '"' => {
244+ self . state = State :: InString ;
245+ Op :: Continue
246+ }
247+ 'u' => {
248+ self . state = State :: InStringEscU ;
249+ Op :: Continue
250+ }
251+ _ => self . error ( c, "in string escape code" ) ,
252+ }
253+ }
254+
255+ fn neg ( & mut self , c : char ) -> Op {
256+ if c == '0' {
257+ self . state = State :: Num0 ;
258+ Op :: Continue
259+ } else if ( '1' ..='9' ) . contains ( & c) {
260+ self . state = State :: Num1 ;
261+ Op :: Continue
262+ } else {
263+ self . error ( c, "in numeric literal" )
264+ }
265+ }
266+
267+ fn dot ( & mut self , c : char ) -> Op {
268+ if c. is_ascii_digit ( ) {
269+ self . state = State :: Dot0 ;
270+ Op :: Continue
271+ } else {
272+ self . error ( c, "after decimal point in numeric literal" )
273+ }
274+ }
275+
276+ fn dot0 ( & mut self , c : char ) -> Op {
277+ if c. is_ascii_digit ( ) {
278+ Op :: Continue
279+ } else if c == 'e' || c == 'E' {
280+ self . state = State :: Exp ;
281+ Op :: Continue
282+ } else {
283+ self . end_value ( c)
284+ }
285+ }
286+
287+ fn exp ( & mut self , c : char ) -> Op {
288+ if c == '+' || c == '-' {
289+ self . state = State :: ExpSign ;
290+ Op :: Continue
291+ } else {
292+ self . exp_sign ( c)
293+ }
294+ }
254295
255296 fn begin_value ( & mut self , c : char ) -> Op {
256297 if is_space ( c) {
0 commit comments