Commit 612045f5 authored by Damien George's avatar Damien George
Browse files

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.
parent 8a9b999f
/*
* 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
...@@ -89,3 +89,4 @@ extern struct _dummy_t mp_sys_stderr_obj; ...@@ -89,3 +89,4 @@ extern struct _dummy_t mp_sys_stderr_obj;
// extmod modules // extmod modules
extern const mp_obj_module_t mp_module_uctypes; 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_zlibd;
extern const mp_obj_module_t mp_module_ujson;
...@@ -200,6 +200,9 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = { ...@@ -200,6 +200,9 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = {
#if MICROPY_PY_ZLIBD #if MICROPY_PY_ZLIBD
{ MP_OBJ_NEW_QSTR(MP_QSTR_zlibd), (mp_obj_t)&mp_module_zlibd }, { MP_OBJ_NEW_QSTR(MP_QSTR_zlibd), (mp_obj_t)&mp_module_zlibd },
#endif #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 // extra builtin modules as defined by a port
MICROPY_PORT_BUILTIN_MODULES MICROPY_PORT_BUILTIN_MODULES
......
...@@ -390,6 +390,10 @@ typedef double mp_float_t; ...@@ -390,6 +390,10 @@ typedef double mp_float_t;
#define MICROPY_PY_ZLIBD (0) #define MICROPY_PY_ZLIBD (0)
#endif #endif
#ifndef MICROPY_PY_UJSON
#define MICROPY_PY_UJSON (0)
#endif
/*****************************************************************************/ /*****************************************************************************/
/* Hooks for a port to add builtins */ /* Hooks for a port to add builtins */
......
...@@ -187,7 +187,8 @@ typedef enum { ...@@ -187,7 +187,8 @@ typedef enum {
PRINT_STR = 0, PRINT_STR = 0,
PRINT_REPR = 1, PRINT_REPR = 1,
PRINT_EXC = 2, // Special format for printing exception in unhandled exception message 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; } 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); typedef void (*mp_print_fun_t)(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o, mp_print_kind_t kind);
......
...@@ -41,10 +41,18 @@ typedef struct _mp_obj_bool_t { ...@@ -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) { 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; mp_obj_bool_t *self = self_in;
if (self->value) { if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
print(env, "True"); if (self->value) {
print(env, "true");
} else {
print(env, "false");
}
} else { } else {
print(env, "False"); if (self->value) {
print(env, "True");
} else {
print(env, "False");
}
} }
} }
......
...@@ -60,6 +60,9 @@ STATIC mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, mp_uint_t *cur) { ...@@ -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) { 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; mp_obj_dict_t *self = self_in;
bool first = true; bool first = true;
if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) {
kind = PRINT_REPR;
}
print(env, "{"); print(env, "{");
mp_uint_t cur = 0; mp_uint_t cur = 0;
mp_map_elem_t *next = NULL; mp_map_elem_t *next = NULL;
...@@ -68,9 +71,9 @@ STATIC void dict_print(void (*print)(void *env, const char *fmt, ...), void *env ...@@ -68,9 +71,9 @@ STATIC void dict_print(void (*print)(void *env, const char *fmt, ...), void *env
print(env, ", "); print(env, ", ");
} }
first = false; first = false;
mp_obj_print_helper(print, env, next->key, PRINT_REPR); mp_obj_print_helper(print, env, next->key, kind);
print(env, ": "); print(env, ": ");
mp_obj_print_helper(print, env, next->value, PRINT_REPR); mp_obj_print_helper(print, env, next->value, kind);
} }
print(env, "}"); print(env, "}");
} }
......
...@@ -49,12 +49,15 @@ STATIC mp_obj_t list_pop(mp_uint_t n_args, const mp_obj_t *args); ...@@ -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) { 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; mp_obj_list_t *o = o_in;
if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) {
kind = PRINT_REPR;
}
print(env, "["); print(env, "[");
for (mp_uint_t i = 0; i < o->len; i++) { for (mp_uint_t i = 0; i < o->len; i++) {
if (i > 0) { if (i > 0) {
print(env, ", "); 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, "]"); print(env, "]");
} }
......
...@@ -38,7 +38,11 @@ typedef struct _mp_obj_none_t { ...@@ -38,7 +38,11 @@ typedef struct _mp_obj_none_t {
} 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) { 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) { STATIC mp_obj_t none_unary_op(mp_uint_t op, mp_obj_t o_in) {
......
...@@ -92,9 +92,41 @@ void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *e ...@@ -92,9 +92,41 @@ void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *e
print(env, "%c", quote_char); 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) { 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); GET_STR_DATA_LEN(self_in, str_data, str_len);
bool is_bytes = MP_OBJ_IS_TYPE(self_in, &mp_type_bytes); 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) { if (kind == PRINT_STR && !is_bytes) {
print(env, "%.*s", str_len, str_data); print(env, "%.*s", str_len, str_data);
} else { } else {
......
...@@ -91,8 +91,44 @@ STATIC void uni_print_quoted(void (*print)(void *env, const char *fmt, ...), voi ...@@ -91,8 +91,44 @@ STATIC void uni_print_quoted(void (*print)(void *env, const char *fmt, ...), voi
print(env, "%c", quote_char); 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) { 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); 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) { if (kind == PRINT_STR) {
print(env, "%.*s", str_len, str_data); print(env, "%.*s", str_len, str_data);
} else { } else {
......
...@@ -43,17 +43,26 @@ STATIC mp_obj_t mp_obj_new_tuple_iterator(mp_obj_tuple_t *tuple, mp_uint_t cur); ...@@ -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) { 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; 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++) { for (mp_uint_t i = 0; i < o->len; i++) {
if (i > 0) { if (i > 0) {
print(env, ", "); 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) { if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
print(env, ","); 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) { 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) {
......
...@@ -112,6 +112,7 @@ PY_O_BASENAME = \ ...@@ -112,6 +112,7 @@ PY_O_BASENAME = \
pfenv_printf.o \ pfenv_printf.o \
../extmod/moductypes.o \ ../extmod/moductypes.o \
../extmod/modzlibd.o \ ../extmod/modzlibd.o \
../extmod/modujson.o \
# prepend the build destination prefix to the py object files # prepend the build destination prefix to the py object files
PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME)) PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME))
......
...@@ -463,3 +463,8 @@ Q(deleter) ...@@ -463,3 +463,8 @@ Q(deleter)
Q(zlibd) Q(zlibd)
Q(decompress) Q(decompress)
#endif #endif
#if MICROPY_PY_UJSON
Q(ujson)
Q(dumps)
#endif
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
#define MICROPY_PY_IO_FILEIO (1) #define MICROPY_PY_IO_FILEIO (1)
#define MICROPY_PY_UCTYPES (1) #define MICROPY_PY_UCTYPES (1)
#define MICROPY_PY_ZLIBD (1) #define MICROPY_PY_ZLIBD (1)
#define MICROPY_PY_UJSON (1)
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0) #define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0)
......
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])}))
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
import os import os
import subprocess import subprocess
import sys import sys
import platform
import argparse import argparse
from glob import glob from glob import glob
...@@ -37,6 +38,11 @@ def run_tests(pyb, tests, args): ...@@ -37,6 +38,11 @@ def run_tests(pyb, tests, args):
if pyb is not None: if pyb is not None:
skip_tests.add('float/float_divmod.py') # tested by float/float_divmod_relaxed.py instead 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 # Some tests are known to fail with native emitter
# Remove them from the below when they work # Remove them from the below when they work
if args.emit == 'native': if args.emit == 'native':
...@@ -153,10 +159,10 @@ def main(): ...@@ -153,10 +159,10 @@ def main():
if args.test_dirs is None: if args.test_dirs is None:
if pyb is None: if pyb is None:
# run PC tests # 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: else:
# run pyboard tests # run pyboard tests
test_dirs = ('basics', 'micropython', 'float', 'misc', 'pyb', 'pybnative', 'inlineasm') test_dirs = ('basics', 'micropython', 'float', 'misc', 'extmod', 'pyb', 'pybnative', 'inlineasm')
else: else:
# run tests from these directories # run tests from these directories
test_dirs = args.test_dirs test_dirs = args.test_dirs
......
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
#define MICROPY_PY_UCTYPES (1) #define MICROPY_PY_UCTYPES (1)
#define MICROPY_PY_ZLIBD (1) #define MICROPY_PY_ZLIBD (1)
#define MICROPY_PY_UJSON (1)
// Define to MICROPY_ERROR_REPORTING_DETAILED to get function, etc. // Define to MICROPY_ERROR_REPORTING_DETAILED to get function, etc.
// names in exception messages (may require more RAM). // names in exception messages (may require more RAM).
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment