summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--extmod/modujson.c71
-rw-r--r--py/builtin.h1
-rw-r--r--py/builtintables.c3
-rw-r--r--py/mpconfig.h4
-rw-r--r--py/obj.h3
-rw-r--r--py/objbool.c14
-rw-r--r--py/objdict.c7
-rw-r--r--py/objlist.c5
-rw-r--r--py/objnone.c6
-rw-r--r--py/objstr.c32
-rw-r--r--py/objstrunicode.c36
-rw-r--r--py/objtuple.c19
-rw-r--r--py/py.mk1
-rw-r--r--py/qstrdefs.h5
-rw-r--r--stmhal/mpconfigport.h1
-rw-r--r--tests/extmod/ujson_dumps.py23
-rwxr-xr-xtests/run-tests10
-rw-r--r--unix/mpconfigport.h1
18 files changed, 227 insertions, 15 deletions
diff --git a/extmod/modujson.c b/extmod/modujson.c
new file mode 100644
index 0000000000..2772f7d123
--- /dev/null
+++ b/extmod/modujson.c
@@ -0,0 +1,71 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "mpconfig.h"
+#include "misc.h"
+#include "qstr.h"
+#include "obj.h"
+#include "runtime.h"
+
+#if MICROPY_PY_UJSON
+
+STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) {
+ vstr_t vstr;
+ vstr_init(&vstr, 8);
+ mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))vstr_printf, &vstr, obj, PRINT_JSON);
+ mp_obj_t ret = mp_obj_new_str(vstr.buf, vstr.len, false);
+ vstr_clear(&vstr);
+ return ret;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_dumps_obj, mod_ujson_dumps);
+
+STATIC const mp_map_elem_t mp_module_ujson_globals_table[] = {
+ { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ujson) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_dumps), (mp_obj_t)&mod_ujson_dumps_obj },
+};
+
+STATIC const mp_obj_dict_t mp_module_ujson_globals = {
+ .base = {&mp_type_dict},
+ .map = {
+ .all_keys_are_qstrs = 1,
+ .table_is_fixed_array = 1,
+ .used = MP_ARRAY_SIZE(mp_module_ujson_globals_table),
+ .alloc = MP_ARRAY_SIZE(mp_module_ujson_globals_table),
+ .table = (mp_map_elem_t*)mp_module_ujson_globals_table,
+ },
+};
+
+const mp_obj_module_t mp_module_ujson = {
+ .base = { &mp_type_module },
+ .name = MP_QSTR_ujson,
+ .globals = (mp_obj_dict_t*)&mp_module_ujson_globals,
+};
+
+#endif //MICROPY_PY_UJSON
diff --git a/py/builtin.h b/py/builtin.h
index 1bb61f6ebc..9c8b2b9be2 100644
--- a/py/builtin.h
+++ b/py/builtin.h
@@ -89,3 +89,4 @@ extern struct _dummy_t mp_sys_stderr_obj;
// extmod modules
extern const mp_obj_module_t mp_module_uctypes;
extern const mp_obj_module_t mp_module_zlibd;
+extern const mp_obj_module_t mp_module_ujson;
diff --git a/py/builtintables.c b/py/builtintables.c
index 08b6b16493..391077d434 100644
--- a/py/builtintables.c
+++ b/py/builtintables.c
@@ -200,6 +200,9 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = {
#if MICROPY_PY_ZLIBD
{ MP_OBJ_NEW_QSTR(MP_QSTR_zlibd), (mp_obj_t)&mp_module_zlibd },
#endif
+#if MICROPY_PY_UJSON
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ujson), (mp_obj_t)&mp_module_ujson },
+#endif
// extra builtin modules as defined by a port
MICROPY_PORT_BUILTIN_MODULES
diff --git a/py/mpconfig.h b/py/mpconfig.h
index adbcb0eb71..cf85533395 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -390,6 +390,10 @@ typedef double mp_float_t;
#define MICROPY_PY_ZLIBD (0)
#endif
+#ifndef MICROPY_PY_UJSON
+#define MICROPY_PY_UJSON (0)
+#endif
+
/*****************************************************************************/
/* Hooks for a port to add builtins */
diff --git a/py/obj.h b/py/obj.h
index c7745dc9eb..9fee0413ae 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -187,7 +187,8 @@ typedef enum {
PRINT_STR = 0,
PRINT_REPR = 1,
PRINT_EXC = 2, // Special format for printing exception in unhandled exception message
- PRINT_EXC_SUBCLASS = 4, // Internal flag for printing exception subclasses
+ PRINT_JSON = 3,
+ PRINT_EXC_SUBCLASS = 0x80, // Internal flag for printing exception subclasses
} mp_print_kind_t;
typedef void (*mp_print_fun_t)(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o, mp_print_kind_t kind);
diff --git a/py/objbool.c b/py/objbool.c
index dbe84d92e2..e6b5230f74 100644
--- a/py/objbool.c
+++ b/py/objbool.c
@@ -41,10 +41,18 @@ typedef struct _mp_obj_bool_t {
STATIC void bool_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_bool_t *self = self_in;
- if (self->value) {
- print(env, "True");
+ if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
+ if (self->value) {
+ print(env, "true");
+ } else {
+ print(env, "false");
+ }
} else {
- print(env, "False");
+ if (self->value) {
+ print(env, "True");
+ } else {
+ print(env, "False");
+ }
}
}
diff --git a/py/objdict.c b/py/objdict.c
index a378bf6db8..a624320427 100644
--- a/py/objdict.c
+++ b/py/objdict.c
@@ -60,6 +60,9 @@ STATIC mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, mp_uint_t *cur) {
STATIC void dict_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_dict_t *self = self_in;
bool first = true;
+ if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) {
+ kind = PRINT_REPR;
+ }
print(env, "{");
mp_uint_t cur = 0;
mp_map_elem_t *next = NULL;
@@ -68,9 +71,9 @@ STATIC void dict_print(void (*print)(void *env, const char *fmt, ...), void *env
print(env, ", ");
}
first = false;
- mp_obj_print_helper(print, env, next->key, PRINT_REPR);
+ mp_obj_print_helper(print, env, next->key, kind);
print(env, ": ");
- mp_obj_print_helper(print, env, next->value, PRINT_REPR);
+ mp_obj_print_helper(print, env, next->value, kind);
}
print(env, "}");
}
diff --git a/py/objlist.c b/py/objlist.c
index 59390f371f..789a1600d3 100644
--- a/py/objlist.c
+++ b/py/objlist.c
@@ -49,12 +49,15 @@ STATIC mp_obj_t list_pop(mp_uint_t n_args, const mp_obj_t *args);
STATIC void list_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_list_t *o = o_in;
+ if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) {
+ kind = PRINT_REPR;
+ }
print(env, "[");
for (mp_uint_t i = 0; i < o->len; i++) {
if (i > 0) {
print(env, ", ");
}
- mp_obj_print_helper(print, env, o->items[i], PRINT_REPR);
+ mp_obj_print_helper(print, env, o->items[i], kind);
}
print(env, "]");
}
diff --git a/py/objnone.c b/py/objnone.c
index a8d6071435..01536dcb34 100644
--- a/py/objnone.c
+++ b/py/objnone.c
@@ -38,7 +38,11 @@ typedef struct _mp_obj_none_t {
} mp_obj_none_t;
STATIC void none_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
- print(env, "None");
+ if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
+ print(env, "null");
+ } else {
+ print(env, "None");
+ }
}
STATIC mp_obj_t none_unary_op(mp_uint_t op, mp_obj_t o_in) {
diff --git a/py/objstr.c b/py/objstr.c
index b2afcdc98e..130af8a6af 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -92,9 +92,41 @@ void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *e
print(env, "%c", quote_char);
}
+#if MICROPY_PY_UJSON
+STATIC void str_print_json(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, mp_uint_t str_len) {
+ print(env, "\"");
+ for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) {
+ if (*s == '"' || *s == '\\' || *s == '/') {
+ print(env, "\\%c", *s);
+ } else if (32 <= *s && *s <= 126) {
+ print(env, "%c", *s);
+ } else if (*s == '\b') {
+ print(env, "\\b");
+ } else if (*s == '\f') {
+ print(env, "\\f");
+ } else if (*s == '\n') {
+ print(env, "\\n");
+ } else if (*s == '\r') {
+ print(env, "\\r");
+ } else if (*s == '\t') {
+ print(env, "\\t");
+ } else {
+ print(env, "\\u%04x", *s);
+ }
+ }
+ print(env, "\"");
+}
+#endif
+
STATIC void str_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
GET_STR_DATA_LEN(self_in, str_data, str_len);
bool is_bytes = MP_OBJ_IS_TYPE(self_in, &mp_type_bytes);
+ #if MICROPY_PY_UJSON
+ if (kind == PRINT_JSON) {
+ str_print_json(print, env, str_data, str_len);
+ return;
+ }
+ #endif
if (kind == PRINT_STR && !is_bytes) {
print(env, "%.*s", str_len, str_data);
} else {
diff --git a/py/objstrunicode.c b/py/objstrunicode.c
index 8231eb9b16..0ee7f1dc9a 100644
--- a/py/objstrunicode.c
+++ b/py/objstrunicode.c
@@ -91,8 +91,44 @@ STATIC void uni_print_quoted(void (*print)(void *env, const char *fmt, ...), voi
print(env, "%c", quote_char);
}
+#if MICROPY_PY_UJSON
+STATIC void uni_print_json(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len) {
+ print(env, "\"");
+ const byte *s = str_data, *top = str_data + str_len;
+ while (s < top) {
+ unichar ch;
+ ch = utf8_get_char(s);
+ s = utf8_next_char(s);
+ if (ch == '"' || ch == '\\' || ch == '/') {
+ print(env, "\\%c", ch);
+ } else if (32 <= ch && ch <= 126) {
+ print(env, "%c", ch);
+ } else if (*s == '\b') {
+ print(env, "\\b");
+ } else if (*s == '\f') {
+ print(env, "\\f");
+ } else if (*s == '\n') {
+ print(env, "\\n");
+ } else if (*s == '\r') {
+ print(env, "\\r");
+ } else if (*s == '\t') {
+ print(env, "\\t");
+ } else {
+ print(env, "\\u%04x", ch);
+ }
+ }
+ print(env, "\"");
+}
+#endif
+
STATIC void uni_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
GET_STR_DATA_LEN(self_in, str_data, str_len);
+ #if MICROPY_PY_UJSON
+ if (kind == PRINT_JSON) {
+ uni_print_json(print, env, str_data, str_len);
+ return;
+ }
+ #endif
if (kind == PRINT_STR) {
print(env, "%.*s", str_len, str_data);
} else {
diff --git a/py/objtuple.c b/py/objtuple.c
index 6abe7d2c64..2793e4838d 100644
--- a/py/objtuple.c
+++ b/py/objtuple.c
@@ -43,17 +43,26 @@ STATIC mp_obj_t mp_obj_new_tuple_iterator(mp_obj_tuple_t *tuple, mp_uint_t cur);
void mp_obj_tuple_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_tuple_t *o = o_in;
- print(env, "(");
+ if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
+ print(env, "[");
+ } else {
+ print(env, "(");
+ kind = PRINT_REPR;
+ }
for (mp_uint_t i = 0; i < o->len; i++) {
if (i > 0) {
print(env, ", ");
}
- mp_obj_print_helper(print, env, o->items[i], PRINT_REPR);
+ mp_obj_print_helper(print, env, o->items[i], kind);
}
- if (o->len == 1) {
- print(env, ",");
+ if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
+ print(env, "]");
+ } else {
+ if (o->len == 1) {
+ print(env, ",");
+ }
+ print(env, ")");
}
- print(env, ")");
}
STATIC mp_obj_t mp_obj_tuple_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
diff --git a/py/py.mk b/py/py.mk
index e2288d3821..fb59b89729 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -112,6 +112,7 @@ PY_O_BASENAME = \
pfenv_printf.o \
../extmod/moductypes.o \
../extmod/modzlibd.o \
+ ../extmod/modujson.o \
# prepend the build destination prefix to the py object files
PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME))
diff --git a/py/qstrdefs.h b/py/qstrdefs.h
index d41029a1fa..41ffa1d201 100644
--- a/py/qstrdefs.h
+++ b/py/qstrdefs.h
@@ -463,3 +463,8 @@ Q(deleter)
Q(zlibd)
Q(decompress)
#endif
+
+#if MICROPY_PY_UJSON
+Q(ujson)
+Q(dumps)
+#endif
diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h
index bfd399a76e..5e6faa4df2 100644
--- a/stmhal/mpconfigport.h
+++ b/stmhal/mpconfigport.h
@@ -57,6 +57,7 @@
#define MICROPY_PY_IO_FILEIO (1)
#define MICROPY_PY_UCTYPES (1)
#define MICROPY_PY_ZLIBD (1)
+#define MICROPY_PY_UJSON (1)
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0)
diff --git a/tests/extmod/ujson_dumps.py b/tests/extmod/ujson_dumps.py
new file mode 100644
index 0000000000..6e858fd3f9
--- /dev/null
+++ b/tests/extmod/ujson_dumps.py
@@ -0,0 +1,23 @@
+try:
+ import ujson as json
+except ImportError:
+ import json
+
+print(json.dumps(False))
+print(json.dumps(True))
+print(json.dumps(None))
+print(json.dumps(1))
+print(json.dumps(1.2))
+print(json.dumps('abc'))
+print(json.dumps('\x01\x7e\x7f\x80\u1234'))
+print(json.dumps([]))
+print(json.dumps([1]))
+print(json.dumps([1, 2]))
+print(json.dumps([1, True]))
+print(json.dumps(()))
+print(json.dumps((1,)))
+print(json.dumps((1, 2)))
+print(json.dumps((1, (2, 3))))
+print(json.dumps({}))
+print(json.dumps({"a":1}))
+print(json.dumps({"a":(2,[3,None])}))
diff --git a/tests/run-tests b/tests/run-tests
index 34f855d08d..a96f3773e4 100755
--- a/tests/run-tests
+++ b/tests/run-tests
@@ -3,6 +3,7 @@
import os
import subprocess
import sys
+import platform
import argparse
from glob import glob
@@ -37,6 +38,11 @@ def run_tests(pyb, tests, args):
if pyb is not None:
skip_tests.add('float/float_divmod.py') # tested by float/float_divmod_relaxed.py instead
+ # Some tests are known to fail on 64-bit machines
+ if pyb is None and platform.architecture()[0] == '64bit':
+ skip_tests.add('extmod/uctypes_ptr_le.py')
+ skip_tests.add('extmod/uctypes_ptr_native_le.py')
+
# Some tests are known to fail with native emitter
# Remove them from the below when they work
if args.emit == 'native':
@@ -153,10 +159,10 @@ def main():
if args.test_dirs is None:
if pyb is None:
# run PC tests
- test_dirs = ('basics', 'micropython', 'float', 'import', 'io', 'misc', 'unicode', 'unix')
+ test_dirs = ('basics', 'micropython', 'float', 'import', 'io', 'misc', 'unicode', 'extmod', 'unix')
else:
# run pyboard tests
- test_dirs = ('basics', 'micropython', 'float', 'misc', 'pyb', 'pybnative', 'inlineasm')
+ test_dirs = ('basics', 'micropython', 'float', 'misc', 'extmod', 'pyb', 'pybnative', 'inlineasm')
else:
# run tests from these directories
test_dirs = args.test_dirs
diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h
index 38da3fcbcb..56f66750f5 100644
--- a/unix/mpconfigport.h
+++ b/unix/mpconfigport.h
@@ -58,6 +58,7 @@
#define MICROPY_PY_UCTYPES (1)
#define MICROPY_PY_ZLIBD (1)
+#define MICROPY_PY_UJSON (1)
// Define to MICROPY_ERROR_REPORTING_DETAILED to get function, etc.
// names in exception messages (may require more RAM).