3030
3131#include "mpconfig.h"
3232#include "misc.h"
33+ #include "nlr.h"
3334#include "qstr.h"
3435#include "obj.h"
36+ #include "objlist.h"
37+ #include "parsenum.h"
3538#include "runtime.h"
3639
3740#if MICROPY_PY_UJSON
@@ -46,9 +49,184 @@ STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) {
4649}
4750STATIC MP_DEFINE_CONST_FUN_OBJ_1 (mod_ujson_dumps_obj , mod_ujson_dumps );
4851
52+ STATIC mp_obj_t mod_ujson_loads (mp_obj_t obj ) {
53+ mp_uint_t len ;
54+ const char * s = mp_obj_str_get_data (obj , & len );
55+ const char * top = s + len ;
56+ vstr_t vstr ;
57+ vstr_init (& vstr , 8 );
58+ mp_obj_list_t * stack = NULL ;
59+ mp_obj_t stack_top = MP_OBJ_NULL ;
60+ mp_obj_type_t * stack_top_type = NULL ;
61+ mp_obj_t stack_key = MP_OBJ_NULL ;
62+ for (;;) {
63+ cont :
64+ if (s == top ) {
65+ break ;
66+ }
67+ mp_obj_t next = MP_OBJ_NULL ;
68+ bool enter = false;
69+ switch (* s ) {
70+ case ',' :
71+ case ':' :
72+ case ' ' :
73+ s += 1 ;
74+ goto cont ;
75+ case 'n' :
76+ if (s + 3 < top && s [1 ] == 'u' && s [2 ] == 'l' && s [3 ] == 'l' ) {
77+ s += 4 ;
78+ next = mp_const_none ;
79+ } else {
80+ goto fail ;
81+ }
82+ break ;
83+ case 'f' :
84+ if (s + 4 < top && s [1 ] == 'a' && s [2 ] == 'l' && s [3 ] == 's' && s [4 ] == 'e' ) {
85+ s += 5 ;
86+ next = mp_const_false ;
87+ } else {
88+ goto fail ;
89+ }
90+ break ;
91+ case 't' :
92+ if (s + 3 < top && s [1 ] == 'r' && s [2 ] == 'u' && s [3 ] == 'e' ) {
93+ s += 4 ;
94+ next = mp_const_true ;
95+ } else {
96+ goto fail ;
97+ }
98+ break ;
99+ case '"' :
100+ vstr_reset (& vstr );
101+ for (s ++ ; s < top && * s != '"' ; s ++ ) {
102+ byte c = * s ;
103+ if (c == '\\' ) {
104+ s ++ ;
105+ c = * s ;
106+ switch (c ) {
107+ case 'b' : c = '\b' ; break ;
108+ case 'f' : c = '\f' ; break ;
109+ case 'n' : c = '\n' ; break ;
110+ case 'r' : c = '\r' ; break ;
111+ case 't' : c = '\t' ; break ;
112+ case 'u' : if (s + 4 >= top ) { goto fail ; } else { assert (0 ); } //vstr_add_char(&vstr, s[0]
113+ }
114+ }
115+ vstr_add_byte (& vstr , c );
116+ }
117+ if (s == top ) {
118+ goto fail ;
119+ }
120+ s ++ ;
121+ next = mp_obj_new_str (vstr .buf , vstr .len , false);
122+ break ;
123+ case '-' :
124+ case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : case '8' : case '9' : {
125+ bool flt = false;
126+ vstr_reset (& vstr );
127+ for (; s < top ; s ++ ) {
128+ if (* s == '.' || * s == 'E' || * s == 'e' ) {
129+ flt = true;
130+ } else if (* s == '-' || unichar_isdigit (* s )) {
131+ // pass
132+ } else {
133+ break ;
134+ }
135+ vstr_add_byte (& vstr , * s );
136+ }
137+ if (flt ) {
138+ next = mp_parse_num_decimal (vstr .buf , vstr .len , false, false);
139+ } else {
140+ next = mp_parse_num_integer (vstr .buf , vstr .len , 10 );
141+ }
142+ break ;
143+ }
144+ case '[' :
145+ next = mp_obj_new_list (0 , NULL );
146+ enter = true;
147+ s += 1 ;
148+ break ;
149+ case '{' :
150+ next = mp_obj_new_dict (0 );
151+ enter = true;
152+ s += 1 ;
153+ break ;
154+ case '}' :
155+ case ']' : {
156+ s += 1 ;
157+ if (stack_top == MP_OBJ_NULL ) {
158+ // no object at all
159+ goto fail ;
160+ }
161+ if (stack == NULL || stack -> len == 0 ) {
162+ // finished; compound object
163+ goto success ;
164+ }
165+ stack -> len -= 1 ;
166+ stack_top = stack -> items [stack -> len ];
167+ stack_top_type = mp_obj_get_type (stack_top );
168+ goto cont ;
169+ }
170+ default :
171+ goto fail ;
172+ }
173+ if (stack_top == MP_OBJ_NULL ) {
174+ stack_top = next ;
175+ stack_top_type = mp_obj_get_type (stack_top );
176+ if (!enter ) {
177+ // finished; single primitive only
178+ goto success ;
179+ }
180+ } else {
181+ // append to list or dict
182+ if (stack_top_type == & mp_type_list ) {
183+ mp_obj_list_append (stack_top , next );
184+ } else {
185+ if (stack_key == MP_OBJ_NULL ) {
186+ stack_key = next ;
187+ if (enter ) {
188+ goto fail ;
189+ }
190+ } else {
191+ mp_obj_dict_store (stack_top , stack_key , next );
192+ stack_key = MP_OBJ_NULL ;
193+ }
194+ }
195+ if (enter ) {
196+ if (stack == NULL ) {
197+ stack = mp_obj_new_list (1 , & stack_top );
198+ } else {
199+ mp_obj_list_append (stack , stack_top );
200+ }
201+ stack_top = next ;
202+ stack_top_type = mp_obj_get_type (stack_top );
203+ }
204+ }
205+ }
206+ success :
207+ // eat trailing whitespace
208+ while (s < top && unichar_isspace (* s )) {
209+ s ++ ;
210+ }
211+ if (s < top ) {
212+ // unexpected chars
213+ goto fail ;
214+ }
215+ if (stack != NULL && stack -> len != 0 ) {
216+ goto fail ;
217+ }
218+ vstr_clear (& vstr );
219+ return stack_top ;
220+
221+ fail :
222+ nlr_raise (mp_obj_new_exception_msg (& mp_type_ValueError , "syntax error in JSON" ));
223+ }
224+ STATIC MP_DEFINE_CONST_FUN_OBJ_1 (mod_ujson_loads_obj , mod_ujson_loads );
225+
49226STATIC const mp_map_elem_t mp_module_ujson_globals_table [] = {
50227 { MP_OBJ_NEW_QSTR (MP_QSTR___name__ ), MP_OBJ_NEW_QSTR (MP_QSTR_ujson ) },
51228 { MP_OBJ_NEW_QSTR (MP_QSTR_dumps ), (mp_obj_t )& mod_ujson_dumps_obj },
229+ { MP_OBJ_NEW_QSTR (MP_QSTR_loads ), (mp_obj_t )& mod_ujson_loads_obj },
52230};
53231
54232STATIC const mp_obj_dict_t mp_module_ujson_globals = {
0 commit comments