Skip to content

Commit 612045f

Browse files
committed
py: Add native json printing using existing print framework.
Also add start of ujson module with dumps implemented. Enabled in unix and stmhal ports. Test passes on both.
1 parent 8a9b999 commit 612045f

File tree

18 files changed

+227
-15
lines changed

18 files changed

+227
-15
lines changed

extmod/modujson.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* This file is part of the Micro Python project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2014 Damien P. George
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include <stdio.h>
28+
#include <unistd.h>
29+
#include <string.h>
30+
31+
#include "mpconfig.h"
32+
#include "misc.h"
33+
#include "qstr.h"
34+
#include "obj.h"
35+
#include "runtime.h"
36+
37+
#if MICROPY_PY_UJSON
38+
39+
STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) {
40+
vstr_t vstr;
41+
vstr_init(&vstr, 8);
42+
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))vstr_printf, &vstr, obj, PRINT_JSON);
43+
mp_obj_t ret = mp_obj_new_str(vstr.buf, vstr.len, false);
44+
vstr_clear(&vstr);
45+
return ret;
46+
}
47+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_dumps_obj, mod_ujson_dumps);
48+
49+
STATIC const mp_map_elem_t mp_module_ujson_globals_table[] = {
50+
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ujson) },
51+
{ MP_OBJ_NEW_QSTR(MP_QSTR_dumps), (mp_obj_t)&mod_ujson_dumps_obj },
52+
};
53+
54+
STATIC const mp_obj_dict_t mp_module_ujson_globals = {
55+
.base = {&mp_type_dict},
56+
.map = {
57+
.all_keys_are_qstrs = 1,
58+
.table_is_fixed_array = 1,
59+
.used = MP_ARRAY_SIZE(mp_module_ujson_globals_table),
60+
.alloc = MP_ARRAY_SIZE(mp_module_ujson_globals_table),
61+
.table = (mp_map_elem_t*)mp_module_ujson_globals_table,
62+
},
63+
};
64+
65+
const mp_obj_module_t mp_module_ujson = {
66+
.base = { &mp_type_module },
67+
.name = MP_QSTR_ujson,
68+
.globals = (mp_obj_dict_t*)&mp_module_ujson_globals,
69+
};
70+
71+
#endif //MICROPY_PY_UJSON

py/builtin.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,4 @@ extern struct _dummy_t mp_sys_stderr_obj;
8989
// extmod modules
9090
extern const mp_obj_module_t mp_module_uctypes;
9191
extern const mp_obj_module_t mp_module_zlibd;
92+
extern const mp_obj_module_t mp_module_ujson;

py/builtintables.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,9 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = {
200200
#if MICROPY_PY_ZLIBD
201201
{ MP_OBJ_NEW_QSTR(MP_QSTR_zlibd), (mp_obj_t)&mp_module_zlibd },
202202
#endif
203+
#if MICROPY_PY_UJSON
204+
{ MP_OBJ_NEW_QSTR(MP_QSTR_ujson), (mp_obj_t)&mp_module_ujson },
205+
#endif
203206

204207
// extra builtin modules as defined by a port
205208
MICROPY_PORT_BUILTIN_MODULES

py/mpconfig.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,10 @@ typedef double mp_float_t;
390390
#define MICROPY_PY_ZLIBD (0)
391391
#endif
392392

393+
#ifndef MICROPY_PY_UJSON
394+
#define MICROPY_PY_UJSON (0)
395+
#endif
396+
393397
/*****************************************************************************/
394398
/* Hooks for a port to add builtins */
395399

py/obj.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ typedef enum {
187187
PRINT_STR = 0,
188188
PRINT_REPR = 1,
189189
PRINT_EXC = 2, // Special format for printing exception in unhandled exception message
190-
PRINT_EXC_SUBCLASS = 4, // Internal flag for printing exception subclasses
190+
PRINT_JSON = 3,
191+
PRINT_EXC_SUBCLASS = 0x80, // Internal flag for printing exception subclasses
191192
} mp_print_kind_t;
192193

193194
typedef void (*mp_print_fun_t)(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o, mp_print_kind_t kind);

py/objbool.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,18 @@ typedef struct _mp_obj_bool_t {
4141

4242
STATIC void bool_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
4343
mp_obj_bool_t *self = self_in;
44-
if (self->value) {
45-
print(env, "True");
44+
if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
45+
if (self->value) {
46+
print(env, "true");
47+
} else {
48+
print(env, "false");
49+
}
4650
} else {
47-
print(env, "False");
51+
if (self->value) {
52+
print(env, "True");
53+
} else {
54+
print(env, "False");
55+
}
4856
}
4957
}
5058

py/objdict.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ STATIC mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, mp_uint_t *cur) {
6060
STATIC void dict_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
6161
mp_obj_dict_t *self = self_in;
6262
bool first = true;
63+
if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) {
64+
kind = PRINT_REPR;
65+
}
6366
print(env, "{");
6467
mp_uint_t cur = 0;
6568
mp_map_elem_t *next = NULL;
@@ -68,9 +71,9 @@ STATIC void dict_print(void (*print)(void *env, const char *fmt, ...), void *env
6871
print(env, ", ");
6972
}
7073
first = false;
71-
mp_obj_print_helper(print, env, next->key, PRINT_REPR);
74+
mp_obj_print_helper(print, env, next->key, kind);
7275
print(env, ": ");
73-
mp_obj_print_helper(print, env, next->value, PRINT_REPR);
76+
mp_obj_print_helper(print, env, next->value, kind);
7477
}
7578
print(env, "}");
7679
}

py/objlist.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,15 @@ STATIC mp_obj_t list_pop(mp_uint_t n_args, const mp_obj_t *args);
4949

5050
STATIC void list_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
5151
mp_obj_list_t *o = o_in;
52+
if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) {
53+
kind = PRINT_REPR;
54+
}
5255
print(env, "[");
5356
for (mp_uint_t i = 0; i < o->len; i++) {
5457
if (i > 0) {
5558
print(env, ", ");
5659
}
57-
mp_obj_print_helper(print, env, o->items[i], PRINT_REPR);
60+
mp_obj_print_helper(print, env, o->items[i], kind);
5861
}
5962
print(env, "]");
6063
}

py/objnone.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ typedef struct _mp_obj_none_t {
3838
} mp_obj_none_t;
3939

4040
STATIC void none_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
41-
print(env, "None");
41+
if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
42+
print(env, "null");
43+
} else {
44+
print(env, "None");
45+
}
4246
}
4347

4448
STATIC mp_obj_t none_unary_op(mp_uint_t op, mp_obj_t o_in) {

py/objstr.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,41 @@ void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *e
9292
print(env, "%c", quote_char);
9393
}
9494

95+
#if MICROPY_PY_UJSON
96+
STATIC void str_print_json(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, mp_uint_t str_len) {
97+
print(env, "\"");
98+
for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) {
99+
if (*s == '"' || *s == '\\' || *s == '/') {
100+
print(env, "\\%c", *s);
101+
} else if (32 <= *s && *s <= 126) {
102+
print(env, "%c", *s);
103+
} else if (*s == '\b') {
104+
print(env, "\\b");
105+
} else if (*s == '\f') {
106+
print(env, "\\f");
107+
} else if (*s == '\n') {
108+
print(env, "\\n");
109+
} else if (*s == '\r') {
110+
print(env, "\\r");
111+
} else if (*s == '\t') {
112+
print(env, "\\t");
113+
} else {
114+
print(env, "\\u%04x", *s);
115+
}
116+
}
117+
print(env, "\"");
118+
}
119+
#endif
120+
95121
STATIC void str_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
96122
GET_STR_DATA_LEN(self_in, str_data, str_len);
97123
bool is_bytes = MP_OBJ_IS_TYPE(self_in, &mp_type_bytes);
124+
#if MICROPY_PY_UJSON
125+
if (kind == PRINT_JSON) {
126+
str_print_json(print, env, str_data, str_len);
127+
return;
128+
}
129+
#endif
98130
if (kind == PRINT_STR && !is_bytes) {
99131
print(env, "%.*s", str_len, str_data);
100132
} else {

0 commit comments

Comments
 (0)