py: Overhaul and simplify printf/pfenv mechanism.

Previous to this patch the printing mechanism was a bit of a tangled
mess.  This patch attempts to consolidate printing into one interface.

All (non-debug) printing now uses the mp_print* family of functions,
mainly mp_printf.  All these functions take an mp_print_t structure as
their first argument, and this structure defines the printing backend
through the "print_strn" function of said structure.

Printing from the uPy core can reach the platform-defined print code via
two paths: either through mp_sys_stdout_obj (defined pert port) in
conjunction with mp_stream_write; or through the mp_plat_print structure
which uses the MP_PLAT_PRINT_STRN macro to define how string are printed
on the platform.  The former is only used when MICROPY_PY_IO is defined.

With this new scheme printing is generally more efficient (less layers
to go through, less arguments to pass), and, given an mp_print_t*
structure, one can call mp_print_str for efficiency instead of
mp_printf("%s", ...).  Code size is also reduced by around 200 bytes on
Thumb2 archs.
crypto-aes
Damien George 8 years ago
parent 56beb01724
commit 7f9d1d6ab9

@ -6,7 +6,6 @@
#include "py/compile.h"
#include "py/runtime.h"
#include "py/repl.h"
#include "py/pfenv.h"
void do_str(const char *src) {
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
@ -23,7 +22,7 @@ void do_str(const char *src) {
nlr_pop();
} else {
// uncaught exception
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
}
}

@ -37,9 +37,9 @@
#include "pybpin.h"
#include MICROPY_HAL_H
STATIC void pin_named_pins_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void pin_named_pins_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
pin_named_pins_obj_t *self = self_in;
print(env, "<Pin.%s>", qstr_str(self->name));
mp_printf(print, "<Pin.%s>", qstr_str(self->name));
}
const mp_obj_type_t pin_cpu_pins_obj_type = {

@ -691,19 +691,19 @@ STATIC mp_obj_t wlan_make_new (mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_k
return &wlan_obj;
}
STATIC void wlan_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void wlan_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
wlan_obj_t *self = self_in;
print(env, "<WLAN, mode=%u", self->mode);
mp_printf(print, "<WLAN, mode=%u", self->mode);
// only print the bssid if in station mode
if (self->mode != ROLE_AP && GET_STATUS_BIT(self->status, STATUS_BIT_CONNECTION)) {
print(env, ", connected to: ssid=%s, bssid=%02x:%02x:%02x:%02x:%02x:%02x", self->ssid,
mp_printf(print, ", connected to: ssid=%s, bssid=%02x:%02x:%02x:%02x:%02x:%02x", self->ssid,
self->bssid[0], self->bssid[1], self->bssid[2], self->bssid[3], self->bssid[4], self->bssid[5]);
}
else {
print(env, ", ssid=%s", self->ssid);
mp_printf(print, ", ssid=%s", self->ssid);
}
print(env, ", security=%u>", self->security);
mp_printf(print, ", security=%u>", self->security);
}
/// \method connect(ssid, security=OPEN, key=None, bssid=None)

@ -100,9 +100,9 @@ STATIC pyb_adc_obj_t pyb_adc_obj[PYB_ADC_NUM_CHANNELS];
/******************************************************************************/
/* Micro Python bindings : adc object */
STATIC void adc_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_adc_obj_t *self = self_in;
print(env, "<ADC, channel=%u>", self->num);
mp_printf(print, "<ADC, channel=%u>", self->num);
}
/// \classmethod \constructor(channel)

@ -294,13 +294,13 @@ STATIC mp_obj_t pyb_i2c_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n
return (mp_obj_t)self;
}
STATIC void pyb_i2c_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void pyb_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_i2c_obj_t *self = self_in;
if (self->baudrate > 0) {
print(env, "<I2C0, I2C.MASTER, baudrate=%u>)", self->baudrate);
mp_printf(print, "<I2C0, I2C.MASTER, baudrate=%u>)", self->baudrate);
}
else {
print(env, "<I2C0>");
mp_print_str(print, "<I2C0>");
}
}

@ -429,14 +429,14 @@ STATIC mp_obj_t pin_obj_init_helper(pin_obj_t *self, mp_uint_t n_args, const mp_
/// \method print()
/// Return a string describing the pin object.
STATIC void pin_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
pin_obj_t *self = self_in;
uint32_t af = MAP_PinModeGet(self->pin_num);
uint32_t type = pin_get_type(self);
uint32_t strength = pin_get_strenght(self);
// pin name
print(env, "<Pin.cpu.%s, af=%u", qstr_str(self->name), af);
mp_printf(print, "<Pin.cpu.%s, af=%u", qstr_str(self->name), af);
if (af == PIN_MODE_0) {
// IO mode
@ -447,7 +447,7 @@ STATIC void pin_print(void (*print)(void *env, const char *fmt, ...), void *env,
} else {
mode_qst = MP_QSTR_OUT;
}
print(env, ", mode=Pin.%s", qstr_str(mode_qst)); // safe because mode_qst has no formatting chars
mp_printf(print, ", mode=Pin.%s", qstr_str(mode_qst));
}
// pin type
@ -465,7 +465,7 @@ STATIC void pin_print(void (*print)(void *env, const char *fmt, ...), void *env,
} else {
type_qst = MP_QSTR_OD_PD;
}
print(env, ", pull=Pin.%s", qstr_str(type_qst));
mp_printf(print, ", pull=Pin.%s", qstr_str(type_qst));
// Strength
qstr str_qst;
@ -476,7 +476,7 @@ STATIC void pin_print(void (*print)(void *env, const char *fmt, ...), void *env,
} else {
str_qst = MP_QSTR_S6MA;
}
print(env, ", strength=Pin.%s>", qstr_str(str_qst));
mp_printf(print, ", strength=Pin.%s>", qstr_str(str_qst));
}
/// \classmethod \constructor(id, ...)

@ -163,15 +163,15 @@ STATIC void pybspi_transfer (pyb_spi_obj_t *self, const char *txdata, char *rxda
/******************************************************************************/
/* Micro Python bindings */
/******************************************************************************/
STATIC void pyb_spi_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void pyb_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_spi_obj_t *self = self_in;
if (self->baudrate > 0) {
print(env, "<SPI0, SPI.MASTER, baudrate=%u, config=%u, submode=%u, bits=%u>",
mp_printf(print, "<SPI0, SPI.MASTER, baudrate=%u, config=%u, submode=%u, bits=%u>",
self->baudrate, self->config, self->submode, (self->wlen * 8));
}
else {
print(env, "<SPI0>");
mp_print_str(print, "<SPI0>");
}
}

@ -312,37 +312,37 @@ STATIC void uart_callback_disable (mp_obj_t self_in) {
/******************************************************************************/
/* Micro Python bindings */
STATIC void pyb_uart_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_uart_obj_t *self = self_in;
if (self->baudrate > 0) {
print(env, "<UART%u, baudrate=%u, bits=", self->uart_id, self->baudrate);
mp_printf(print, "<UART%u, baudrate=%u, bits=", self->uart_id, self->baudrate);
switch (self->config & UART_CONFIG_WLEN_MASK) {
case UART_CONFIG_WLEN_5:
print(env, "5");
mp_print_str(print, "5");
break;
case UART_CONFIG_WLEN_6:
print(env, "6");
mp_print_str(print, "6");
break;
case UART_CONFIG_WLEN_7:
print(env, "7");
mp_print_str(print, "7");
break;
case UART_CONFIG_WLEN_8:
print(env, "8");
mp_print_str(print, "8");
break;
default:
break;
}
if ((self->config & UART_CONFIG_PAR_MASK) == UART_CONFIG_PAR_NONE) {
print(env, ", parity=None");
mp_print_str(print, ", parity=None");
} else {
print(env, ", parity=%u", (self->config & UART_CONFIG_PAR_MASK) == UART_CONFIG_PAR_EVEN ? 0 : 1);
mp_printf(print, ", parity=%u", (self->config & UART_CONFIG_PAR_MASK) == UART_CONFIG_PAR_EVEN ? 0 : 1);
}
print(env, ", stop=%u, timeout=%u, timeout_char=%u, read_buf_len=%u>",
mp_printf(print, ", stop=%u, timeout=%u, timeout_char=%u, read_buf_len=%u>",
(self->config & UART_CONFIG_STOP_MASK) == UART_CONFIG_STOP_ONE ? 1 : 2,
self->timeout, self->timeout_char, self->read_buf_len);
}
else {
print(env, "<UART%u>", self->uart_id);
mp_printf(print, "<UART%u>", self->uart_id);
}
}

@ -146,6 +146,9 @@ typedef void *machine_ptr_t; // must be of pointer size
typedef const void *machine_const_ptr_t; // must be of pointer size
typedef long mp_off_t;
void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len);
#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
#define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq()
#define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state)

@ -32,7 +32,6 @@
#include "py/obj.h"
#include "py/gc.h"
#include "py/runtime.h"
#include "py/pfenv.h"
#include MICROPY_HAL_H
#include "queue.h"
#include "user_interface.h"
@ -52,7 +51,7 @@ mp_obj_t call_function_1_protected(mp_obj_t fun, mp_obj_t arg) {
if (nlr_push(&nlr) == 0) {
return mp_call_function_1(fun, arg);
} else {
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
return (mp_obj_t)nlr.ret_val;
}
}

@ -65,11 +65,11 @@ STATIC const pyb_pin_obj_t pyb_pin_obj[] = {
{{&pyb_pin_type}, 15, 15, PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO15},
};
STATIC void pyb_pin_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void pyb_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_pin_obj_t *self = self_in;
// pin name
print(env, "Pin(%u)", self->pin_id);
mp_printf(print, "Pin(%u)", self->pin_id);
}
// pin.init(mode, pull=Pin.PULL_NONE, af=-1)

@ -52,6 +52,9 @@ typedef void *machine_ptr_t; // must be of pointer size
typedef const void *machine_const_ptr_t; // must be of pointer size
typedef long mp_off_t;
void mp_hal_stdout_tx_strn_cooked(const char *str, mp_uint_t len);
#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
// extra built in names to add to the global namespace
extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
#define MICROPY_PORT_BUILTINS \

@ -137,7 +137,7 @@ STATIC mp_obj_t uctypes_struct_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_u
return o;
}
STATIC void uctypes_struct_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void uctypes_struct_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_uctypes_struct_t *self = self_in;
const char *typen = "unk";
@ -154,7 +154,7 @@ STATIC void uctypes_struct_print(void (*print)(void *env, const char *fmt, ...),
} else {
typen = "ERROR";
}
print(env, "<struct %s %p>", typen, self->addr);
mp_printf(print, "<struct %s %p>", typen, self->addr);
}
// Get size of any type descriptor

@ -35,8 +35,9 @@
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_print_t print;
vstr_init_print(&vstr, 8, &print);
mp_obj_print_helper(&print, obj, PRINT_JSON);
return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_dumps_obj, mod_ujson_dumps);

@ -51,10 +51,10 @@ typedef struct _mp_obj_match_t {
} mp_obj_match_t;
STATIC void match_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void match_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_match_t *self = self_in;
print(env, "<match num=%d>", self->num_matches);
mp_printf(print, "<match num=%d>", self->num_matches);
}
STATIC mp_obj_t match_group(mp_obj_t self_in, mp_obj_t no_in) {
@ -86,10 +86,10 @@ STATIC const mp_obj_type_t match_type = {
.locals_dict = (mp_obj_t)&match_locals_dict,
};
STATIC void re_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void re_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_re_t *self = self_in;
print(env, "<re %p>", self);
mp_printf(print, "<re %p>", self);
}
STATIC mp_obj_t re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {

@ -6,7 +6,6 @@
#include "py/compile.h"
#include "py/runtime.h"
#include "py/repl.h"
#include "py/pfenv.h"
#include "py/gc.h"
#include "pyexec.h"
@ -26,7 +25,7 @@ void do_str(const char *src) {
nlr_pop();
} else {
// uncaught exception
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
}
}

@ -60,6 +60,9 @@ typedef void *machine_ptr_t; // must be of pointer size
typedef const void *machine_const_ptr_t; // must be of pointer size
typedef long mp_off_t;
void mp_hal_stdout_tx_strn_cooked(const char *str, mp_uint_t len);
#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
// extra built in names to add to the global namespace
extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
#define MICROPY_PORT_BUILTINS \

@ -41,9 +41,9 @@ STATIC const pyb_led_obj_t pyb_led_obj[] = {
#define NUM_LED MP_ARRAY_SIZE(pyb_led_obj)
#define LED_ID(obj) ((obj) - &pyb_led_obj[0] + 1)
void pyb_led_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
void pyb_led_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_led_obj_t *self = self_in;
print(env, "LED(%u)", LED_ID(self));
mp_printf(print, "LED(%u)", LED_ID(self));
}
STATIC mp_obj_t pyb_led_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {

@ -40,9 +40,9 @@ STATIC const pyb_switch_obj_t pyb_switch_obj[] = {
#define NUM_SWITCH MP_ARRAY_SIZE(pyb_switch_obj)
#define SWITCH_ID(obj) ((obj) - &pyb_switch_obj[0] + 1)
void pyb_switch_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
void pyb_switch_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_switch_obj_t *self = self_in;
print(env, "Switch(%u)", SWITCH_ID(self));
mp_printf(print, "Switch(%u)", SWITCH_ID(self));
}
STATIC mp_obj_t pyb_switch_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {

@ -86,6 +86,9 @@ typedef void *machine_ptr_t; // must be pointer size
typedef const void *machine_const_ptr_t; // must be pointer size
typedef int mp_off_t;
void mp_hal_stdout_tx_strn_cooked(const char *str, mp_uint_t len);
#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
// extra builtin names to add to the global namespace
extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
#define MICROPY_PORT_BUILTINS \

@ -147,6 +147,8 @@ typedef struct _vstr_t {
void vstr_init(vstr_t *vstr, size_t alloc);
void vstr_init_len(vstr_t *vstr, size_t len);
void vstr_init_fixed_buf(vstr_t *vstr, size_t alloc, char *buf);
struct _mp_print_t;
void vstr_init_print(vstr_t *vstr, size_t alloc, struct _mp_print_t *print);
void vstr_clear(vstr_t *vstr);
vstr_t *vstr_new(void);
vstr_t *vstr_new_size(size_t alloc);

@ -35,7 +35,6 @@
#include "py/runtime.h"
#include "py/builtin.h"
#include "py/stream.h"
#include "py/pfenv.h"
#if MICROPY_PY_BUILTINS_FLOAT
#include <math.h>
@ -413,9 +412,7 @@ STATIC mp_obj_t mp_builtin_print(mp_uint_t n_args, const mp_obj_t *args, mp_map_
stream_obj = file_elem->value;
}
pfenv_t pfenv;
pfenv.data = stream_obj;
pfenv.print_strn = (void (*)(void *, const char *, mp_uint_t))mp_stream_write;
mp_print_t print = {stream_obj, (mp_print_strn_t)mp_stream_write};
#endif
for (mp_uint_t i = 0; i < n_args; i++) {
if (i > 0) {
@ -426,7 +423,7 @@ STATIC mp_obj_t mp_builtin_print(mp_uint_t n_args, const mp_obj_t *args, mp_map_
#endif
}
#if MICROPY_PY_IO
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))pfenv_printf, &pfenv, args[i], PRINT_STR);
mp_obj_print_helper(&print, args[i], PRINT_STR);
#else
mp_obj_print(args[i], PRINT_STR);
#endif
@ -443,10 +440,8 @@ MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_print_obj, 0, mp_builtin_print);
STATIC mp_obj_t mp_builtin___repl_print__(mp_obj_t o) {
if (o != mp_const_none) {
#if MICROPY_PY_IO
pfenv_t pfenv;
pfenv.data = &mp_sys_stdout_obj;
pfenv.print_strn = (void (*)(void *, const char *, mp_uint_t))mp_stream_write;
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))pfenv_printf, &pfenv, o, PRINT_REPR);
mp_print_t print = {&mp_sys_stdout_obj, (mp_print_strn_t)mp_stream_write};
mp_obj_print_helper(&print, o, PRINT_REPR);
mp_stream_write(&mp_sys_stdout_obj, "\n", 1);
#else
mp_obj_print(o, PRINT_REPR);
@ -459,8 +454,9 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin___repl_print___obj, mp_builtin___repl_print
STATIC mp_obj_t mp_builtin_repr(mp_obj_t o_in) {
vstr_t vstr;
vstr_init(&vstr, 16);
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))vstr_printf, &vstr, o_in, PRINT_REPR);
mp_print_t print;
vstr_init_print(&vstr, 16, &print);
mp_obj_print_helper(&print, o_in, PRINT_REPR);
return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_repr_obj, mp_builtin_repr);

@ -31,7 +31,6 @@
#include "py/objtuple.h"
#include "py/objstr.h"
#include "py/objint.h"
#include "py/pfenv.h"
#include "py/stream.h"
#if MICROPY_PY_SYS
@ -78,12 +77,10 @@ STATIC mp_obj_t mp_sys_print_exception(mp_uint_t n_args, const mp_obj_t *args) {
stream_obj = args[1];
}
pfenv_t pfenv;
pfenv.data = stream_obj;
pfenv.print_strn = (void (*)(void *, const char *, mp_uint_t))mp_stream_write;
mp_obj_print_exception((void (*)(void *env, const char *fmt, ...))pfenv_printf, &pfenv, args[0]);
mp_print_t print = {stream_obj, (mp_print_strn_t)mp_stream_write};
mp_obj_print_exception(&print, args[0]);
#else
mp_obj_print_exception(printf_wrapper, NULL, args[0]);
mp_obj_print_exception(&mp_plat_print, args[0]);
#endif
return mp_const_none;

@ -691,7 +691,7 @@ typedef double mp_float_t;
#define MICROPY_MAKE_POINTER_CALLABLE(p) (p)
#endif
// If these MP_PLAT_* macros are overridden then the memory allocated by them
// If these MP_PLAT_*_EXEC macros are overridden then the memory allocated by them
// must be somehow reachable for marking by the GC, since the native code
// generators store pointers to GC managed memory in the code.
#ifndef MP_PLAT_ALLOC_EXEC
@ -702,6 +702,11 @@ typedef double mp_float_t;
#define MP_PLAT_FREE_EXEC(ptr, size) m_del(byte, ptr, size)
#endif
// This macro is used to do all output (except when MICROPY_PY_IO is defined)
#ifndef MP_PLAT_PRINT_STRN
#define MP_PLAT_PRINT_STRN(str, len) printf("%.*s", (int)len, str)
#endif
#ifndef MP_SSIZE_MAX
#define MP_SSIZE_MAX SSIZE_MAX
#endif

@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2013-2015 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
@ -24,11 +24,16 @@
* THE SOFTWARE.
*/
#include <assert.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "py/mpprint.h"
#include "py/obj.h"
#include "py/objint.h"
#include "py/pfenv.h"
#include "py/runtime.h"
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
#include <stdio.h>
@ -41,11 +46,22 @@
static const char pad_spaces[] = " ";
static const char pad_zeroes[] = "0000000000000000";
void pfenv_vstr_add_strn(void *data, const char *str, mp_uint_t len) {
vstr_add_strn(data, str, len);
STATIC void plat_print_strn(void *env, const char *str, mp_uint_t len) {
(void)env;
MP_PLAT_PRINT_STRN(str, len);
}
int pfenv_print_strn(const pfenv_t *pfenv, const char *str, mp_uint_t len, int flags, char fill, int width) {
const mp_print_t mp_plat_print = {NULL, plat_print_strn};
int mp_print_str(const mp_print_t *print, const char *str) {
mp_uint_t len = strlen(str);
if (len) {
print->print_strn(print->data, str, len);
}
return len;
}
int mp_print_strn(const mp_print_t *print, const char *str, mp_uint_t len, int flags, char fill, int width) {
int left_pad = 0;
int right_pad = 0;
int pad = width - len;
@ -53,7 +69,7 @@ int pfenv_print_strn(const pfenv_t *pfenv, const char *str, mp_uint_t len, int f
int total_chars_printed = 0;
const char *pad_chars;
if (!fill || fill == ' ' ) {
if (!fill || fill == ' ') {
pad_chars = pad_spaces;
pad_size = sizeof(pad_spaces) - 1;
} else if (fill == '0') {
@ -82,12 +98,12 @@ int pfenv_print_strn(const pfenv_t *pfenv, const char *str, mp_uint_t len, int f
if (p > pad_size) {
p = pad_size;
}
pfenv->print_strn(pfenv->data, pad_chars, p);
print->print_strn(print->data, pad_chars, p);
left_pad -= p;
}
}
if (len) {
pfenv->print_strn(pfenv->data, str, len);
print->print_strn(print->data, str, len);
total_chars_printed += len;
}
if (right_pad > 0) {
@ -97,7 +113,7 @@ int pfenv_print_strn(const pfenv_t *pfenv, const char *str, mp_uint_t len, int f
if (p > pad_size) {
p = pad_size;
}
pfenv->print_strn(pfenv->data, pad_chars, p);
print->print_strn(print->data, pad_chars, p);
right_pad -= p;
}
}
@ -109,8 +125,8 @@ int pfenv_print_strn(const pfenv_t *pfenv, const char *str, mp_uint_t len, int f
#define INT_BUF_SIZE (sizeof(mp_int_t) * 4)
// This function is used by stmhal port to implement printf.
// It needs to be a separate function to pfenv_print_mp_int, since converting to a mp_int looses the MSB.
int pfenv_print_int(const pfenv_t *pfenv, mp_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width) {
// It needs to be a separate function to mp_print_mp_int, since converting to a mp_int looses the MSB.
int mp_print_int(const mp_print_t *print, mp_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width) {
char sign = 0;
if (sgn) {
if ((mp_int_t)x < 0) {
@ -156,12 +172,12 @@ int pfenv_print_int(const pfenv_t *pfenv, mp_uint_t x, int sgn, int base, int ba
int len = 0;
if (flags & PF_FLAG_PAD_AFTER_SIGN) {
if (sign) {
len += pfenv_print_strn(pfenv, &sign, 1, flags, fill, 1);
len += mp_print_strn(print, &sign, 1, flags, fill, 1);
width--;
}
if (prefix_char) {
len += pfenv_print_strn(pfenv, "0", 1, flags, fill, 1);
len += pfenv_print_strn(pfenv, &prefix_char, 1, flags, fill, 1);
len += mp_print_strn(print, "0", 1, flags, fill, 1);
len += mp_print_strn(print, &prefix_char, 1, flags, fill, 1);
width -= 2;
}
} else {
@ -174,11 +190,11 @@ int pfenv_print_int(const pfenv_t *pfenv, mp_uint_t x, int sgn, int base, int ba
}
}
len += pfenv_print_strn(pfenv, b, buf + INT_BUF_SIZE - b, flags, fill, width);
len += mp_print_strn(print, b, buf + INT_BUF_SIZE - b, flags, fill, width);
return len;
}
int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int base, int base_char, int flags, char fill, int width, int prec) {
int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char, int flags, char fill, int width, int prec) {
if (!MP_OBJ_IS_INT(x)) {
// This will convert booleans to int, or raise an error for
// non-integer types.
@ -282,16 +298,16 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int base, int base_char
int len = 0;
if (spaces_before) {
len += pfenv_print_strn(pfenv, "", 0, 0, ' ', spaces_before);
len += mp_print_strn(print, "", 0, 0, ' ', spaces_before);
}
if (flags & PF_FLAG_PAD_AFTER_SIGN) {
// pad after sign implies pad after prefix as well.
if (sign) {
len += pfenv_print_strn(pfenv, &sign, 1, 0, 0, 1);
len += mp_print_strn(print, &sign, 1, 0, 0, 1);
width--;
}
if (prefix_len) {
len += pfenv_print_strn(pfenv, prefix, prefix_len, 0, 0, 1);
len += mp_print_strn(print, prefix, prefix_len, 0, 0, 1);
width -= prefix_len;
}
}
@ -299,10 +315,10 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int base, int base_char
width = prec;
}
len += pfenv_print_strn(pfenv, str, fmt_size, flags, fill, width);
len += mp_print_strn(print, str, fmt_size, flags, fill, width);
if (spaces_after) {
len += pfenv_print_strn(pfenv, "", 0, 0, ' ', spaces_after);
len += mp_print_strn(print, "", 0, 0, ' ', spaces_after);
}
if (buf != stack_buf) {
@ -312,7 +328,7 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int base, int base_char
}
#if MICROPY_PY_BUILTINS_FLOAT
int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, char fill, int width, int prec) {
int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, char fill, int width, int prec) {
char buf[32];
char sign = '\0';
int chrs = 0;
@ -361,7 +377,7 @@ int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, c
if (*s <= '9' || (flags & PF_FLAG_PAD_NAN_INF)) {
// We have a number, or we have a inf/nan and PAD_NAN_INF is set
// With '{:06e}'.format(float('-inf')) you get '-00inf'
chrs += pfenv_print_strn(pfenv, &buf[0], 1, 0, 0, 1);
chrs += mp_print_strn(print, &buf[0], 1, 0, 0, 1);
width--;
len--;
}
@ -373,8 +389,168 @@ int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, c
// so suppress the zero fill.
fill = ' ';
}
chrs += pfenv_print_strn(pfenv, s, len, flags, fill, width);
chrs += mp_print_strn(print, s, len, flags, fill, width);
return chrs;
}
#endif
int mp_printf(const mp_print_t *print, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
int ret = mp_vprintf(print, fmt, ap);
va_end(ap);
return ret;
}
int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
int chrs = 0;
for (;;) {
{
const char *f = fmt;
while (*f != '\0' && *f != '%') {
++f; // XXX UTF8 advance char
}
if (f > fmt) {
print->print_strn(print->data, fmt, f - fmt);
chrs += f - fmt;
fmt = f;
}
}
if (*fmt == '\0') {
break;
}
// move past % character
++fmt;
// parse flags, if they exist
int flags = 0;
char fill = ' ';
while (*fmt != '\0') {
if (*fmt == '-') flags |= PF_FLAG_LEFT_ADJUST;
else if (*fmt == '+') flags |= PF_FLAG_SHOW_SIGN;
else if (*fmt == ' ') flags |= PF_FLAG_SPACE_SIGN;
else if (*fmt == '!') flags |= PF_FLAG_NO_TRAILZ;
else if (*fmt == '0') {
flags |= PF_FLAG_PAD_AFTER_SIGN;
fill = '0';
} else break;
++fmt;
}
// parse width, if it exists
int width = 0;
for (; '0' <= *fmt && *fmt <= '9'; ++fmt) {
width = width * 10 + *fmt - '0';
}
// parse precision, if it exists
int prec = -1;
if (*fmt == '.') {
++fmt;
if (*fmt == '*') {
++fmt;
prec = va_arg(args, int);
} else {
prec = 0;
for (; '0' <= *fmt && *fmt <= '9'; ++fmt) {
prec = prec * 10 + *fmt - '0';
}
}
if (prec < 0) {
prec = 0;
}
}
// parse long specifiers (current not used)
//bool long_arg = false;
if (*fmt == 'l') {
++fmt;
//long_arg = true;
}
if (*fmt == '\0') {
break;
}
switch (*fmt) {
case 'b':
if (va_arg(args, int)) {
chrs += mp_print_strn(print, "true", 4, flags, fill, width);
} else {
chrs += mp_print_strn(print, "false", 5, flags, fill, width);
}
break;
case 'c':
{
char str = va_arg(args, int);
chrs += mp_print_strn(print, &str, 1, flags, fill, width);
break;
}
case 's':
{
const char *str = va_arg(args, const char*);
if (str) {
if (prec < 0) {
prec = strlen(str);
}
chrs += mp_print_strn(print, str, prec, flags, fill, width);
} else {
chrs += mp_print_strn(print, "(null)", 6, flags, fill, width);
}
break;
}
case 'u':
chrs += mp_print_int(print, va_arg(args, int), 0, 10, 'a', flags, fill, width);
break;
case 'd':
chrs += mp_print_int(print, va_arg(args, int), 1, 10, 'a', flags, fill, width);
break;
case 'x':
chrs += mp_print_int(print, va_arg(args, int), 0, 16, 'a', flags, fill, width);
break;
case 'X':
chrs += mp_print_int(print, va_arg(args, int), 0, 16, 'A', flags, fill, width);
break;
case 'p':
case 'P': // don't bother to handle upcase for 'P'
chrs += mp_print_int(print, va_arg(args, unsigned int), 0, 16, 'a', flags, fill, width);
break;
#if MICROPY_PY_BUILTINS_FLOAT
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
{
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
mp_float_t f = va_arg(args, double);
chrs += mp_print_float(print, f, *fmt, flags, fill, width, prec);
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
// Currently mp_print_float uses snprintf, but snprintf
// itself may be implemented in terms of mp_vprintf() for
// some ports. So, for extra caution, this case is handled
// with assert below. Note that currently ports which
// use MICROPY_FLOAT_IMPL_DOUBLE, don't call mp_vprintf()
// with float format specifier at all.
// TODO: resolve this completely
assert(0);
//#error Calling mp_print_float with double not supported from within printf
#else
#error Unknown MICROPY FLOAT IMPL
#endif
break;
}
#endif
default:
print->print_strn(print->data, fmt, 1);
chrs += 1;
break;
}
++fmt;
}
return chrs;
}

@ -23,12 +23,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __MICROPY_INCLUDED_PY_PFENV_H__
#define __MICROPY_INCLUDED_PY_PFENV_H__
#ifndef __MICROPY_INCLUDED_PY_MPPRINT_H__
#define __MICROPY_INCLUDED_PY_MPPRINT_H__
#include <stdarg.h>
#include "py/obj.h"
#include "py/mpconfig.h"
#define PF_FLAG_LEFT_ADJUST (0x001)
#define PF_FLAG_SHOW_SIGN (0x002)
@ -42,24 +40,28 @@
#define PF_FLAG_PAD_NAN_INF (0x200)
#define PF_FLAG_SHOW_OCTAL_LETTER (0x400)
typedef struct _pfenv_t {
typedef void (*mp_print_strn_t)(void *data, const char *str, mp_uint_t len);
typedef struct _mp_print_t {
void *data;
void (*print_strn)(void *, const char *str, mp_uint_t len);
} pfenv_t;
mp_print_strn_t print_strn;
} mp_print_t;
void pfenv_vstr_add_strn(void *data, const char *str, mp_uint_t len);
// Wrapper for platform print function, which wraps MP_PLAT_PRINT_STRN.
// All (non-debug) prints go through this interface (except some which
// go through mp_sys_stdout_obj if MICROPY_PY_IO is defined).
extern const mp_print_t mp_plat_print;
int pfenv_print_strn(const pfenv_t *pfenv, const char *str, mp_uint_t len, int flags, char fill, int width);
int pfenv_print_int(const pfenv_t *pfenv, mp_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width);
int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int base, int base_char, int flags, char fill, int width, int prec);
int mp_print_str(const mp_print_t *print, const char *str);
int mp_print_strn(const mp_print_t *print, const char *str, mp_uint_t len, int flags, char fill, int width);
int mp_print_int(const mp_print_t *print, mp_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width);
#if MICROPY_PY_BUILTINS_FLOAT
int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, char fill, int width, int prec);
int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, char fill, int width, int prec);
#endif
int pfenv_vprintf(const pfenv_t *pfenv, const char *fmt, va_list args);
int pfenv_printf(const pfenv_t *pfenv, const char *fmt, ...);
// Wrapper for system printf
void printf_wrapper(void *env, const char *fmt, ...);
int mp_printf(const mp_print_t *print, const char *fmt, ...);
#ifdef va_start
int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args);
#endif
#endif // __MICROPY_INCLUDED_PY_PFENV_H__
#endif // __MICROPY_INCLUDED_PY_MPPRINT_H__

@ -36,7 +36,7 @@
#include "py/runtime0.h"
#include "py/runtime.h"
#include "py/stackctrl.h"
#include "py/pfenv.h"
//#include "py/pfenv.h"
#include "py/stream.h" // for mp_obj_print
mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) {
@ -54,20 +54,20 @@ const char *mp_obj_get_type_str(mp_const_obj_t o_in) {
return qstr_str(mp_obj_get_type(o_in)->name);
}
void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
// There can be data structures nested too deep, or just recursive
MP_STACK_CHECK();
#ifndef NDEBUG
if (o_in == NULL) {
print(env, "(nil)");
mp_print_str(print, "(nil)");
return;
}
#endif
mp_obj_type_t *type = mp_obj_get_type(o_in);
if (type->print != NULL) {
type->print(print, env, o_in, kind);
type->print((mp_print_t*)print, o_in, kind);
} else {
print(env, "<%s>", qstr_str(type->name));
mp_printf(print, "<%s>", qstr_str(type->name));
}
}
@ -75,41 +75,41 @@ void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) {
#if MICROPY_PY_IO
// defined per port; type of these is irrelevant, just need pointer
extern struct _mp_dummy_t mp_sys_stdout_obj;
pfenv_t pfenv;
pfenv.data = &mp_sys_stdout_obj;
pfenv.print_strn = (void (*)(void *, const char *, mp_uint_t))mp_stream_write;
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))pfenv_printf, &pfenv, o_in, kind);
mp_print_t print;
print.data = &mp_sys_stdout_obj;
print.print_strn = (mp_print_strn_t)mp_stream_write;
mp_obj_print_helper(&print, o_in, kind);
#else
mp_obj_print_helper(printf_wrapper, NULL, o_in, kind);
mp_obj_print_helper(&mp_plat_print, o_in, kind);
#endif
}
// helper function to print an exception with traceback
void mp_obj_print_exception(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t exc) {
void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc) {
if (mp_obj_is_exception_instance(exc)) {
mp_uint_t n, *values;
mp_obj_exception_get_traceback(exc, &n, &values);
if (n > 0) {
assert(n % 3 == 0);
print(env, "Traceback (most recent call last):\n");
mp_print_str(print, "Traceback (most recent call last):\n");
for (int i = n - 3; i >= 0; i -= 3) {
#if MICROPY_ENABLE_SOURCE_LINE
print(env, " File \"%s\", line %d", qstr_str(values[i]), (int)values[i + 1]);
mp_printf(print, " File \"%s\", line %d", qstr_str(values[i]), (int)values[i + 1]);
#else
print(env, " File \"%s\"", qstr_str(values[i]));
mp_printf(print, " File \"%s\"", qstr_str(values[i]));
#endif
// the block name can be NULL if it's unknown
qstr block = values[i + 2];
if (block == MP_QSTR_NULL) {
print(env, "\n");
mp_print_str(print, "\n");
} else {
print(env, ", in %s\n", qstr_str(block));
mp_printf(print, ", in %s\n", qstr_str(block));
}
}
}
}
mp_obj_print_helper(print, env, exc, PRINT_EXC);
print(env, "\n");
mp_obj_print_helper(print, exc, PRINT_EXC);
mp_print_str(print, "\n");
}
bool mp_obj_is_true(mp_obj_t arg) {

@ -29,6 +29,7 @@
#include "py/mpconfig.h"
#include "py/misc.h"
#include "py/qstr.h"
#include "py/mpprint.h"
// All Micro Python objects are at least this type
// It must be of pointer size
@ -260,7 +261,7 @@ typedef enum {
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);
typedef void (*mp_print_fun_t)(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind);
typedef mp_obj_t (*mp_make_new_fun_t)(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args);
typedef mp_obj_t (*mp_call_fun_t)(mp_obj_t fun, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args);
typedef mp_obj_t (*mp_unary_op_fun_t)(mp_uint_t op, mp_obj_t);
@ -499,9 +500,9 @@ const char *mp_obj_get_type_str(mp_const_obj_t o_in);
bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo); // arguments should be type objects
mp_obj_t mp_instance_cast_to_native_base(mp_const_obj_t self_in, mp_const_obj_t native_type);
void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind);
void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind);
void mp_obj_print(mp_obj_t o, mp_print_kind_t kind);
void mp_obj_print_exception(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t exc);
void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc);
bool mp_obj_is_true(mp_obj_t arg);
bool mp_obj_is_callable(mp_obj_t o_in);
@ -561,7 +562,7 @@ qstr mp_obj_str_get_qstr(mp_obj_t self_in); // use this if you will anyway conve
const char *mp_obj_str_get_str(mp_obj_t self_in); // use this only if you need the string to be null terminated
const char *mp_obj_str_get_data(mp_obj_t self_in, mp_uint_t *len);
mp_obj_t mp_obj_str_intern(mp_obj_t str);
void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, mp_uint_t str_len, bool is_bytes);
void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, mp_uint_t str_len, bool is_bytes);
#if MICROPY_PY_BUILTINS_FLOAT
// float

@ -76,26 +76,26 @@ STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_ui
// array
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
STATIC void array_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
STATIC void array_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_array_t *o = o_in;
if (o->typecode == BYTEARRAY_TYPECODE) {
print(env, "bytearray(b");
mp_str_print_quoted(print, env, o->items, o->len, true);
mp_print_str(print, "bytearray(b");
mp_str_print_quoted(print, o->items, o->len, true);
} else {
print(env, "array('%c'", o->typecode);
mp_printf(print, "array('%c'", o->typecode);
if (o->len > 0) {
print(env, ", [");
mp_print_str(print, ", [");
for (mp_uint_t i = 0; i < o->len; i++) {
if (i > 0) {
print(env, ", ");
mp_print_str(print, ", ");
}
mp_obj_print_helper(print, env, mp_binary_get_val_array(o->typecode, o->items, i), PRINT_REPR);
mp_obj_print_helper(print, mp_binary_get_val_array(o->typecode, o->items, i), PRINT_REPR);
}
print(env, "]");
mp_print_str(print, "]");
}
}
print(env, ")");
mp_print_str(print, ")");
}
#endif

@ -35,19 +35,19 @@ typedef struct _mp_obj_bool_t {
bool value;
} 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(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_bool_t *self = self_in;
if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
if (self->value) {
print(env, "true");
mp_print_str(print, "true");
} else {
print(env, "false");
mp_print_str(print, "false");
}
} else {
if (self->value) {
print(env, "True");
mp_print_str(print, "True");
} else {
print(env, "False");
mp_print_str(print, "False");
}
}
}

@ -36,14 +36,14 @@ typedef struct _mp_obj_bound_meth_t {
} mp_obj_bound_meth_t;
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
STATIC void bound_meth_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
STATIC void bound_meth_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_bound_meth_t *o = o_in;
print(env, "<bound_method %p ", o);
mp_obj_print_helper(print, env, o->self, PRINT_REPR);
print(env, ".");
mp_obj_print_helper(print, env, o->meth, PRINT_REPR);
print(env, ">");
mp_printf(print, "<bound_method %p ", o);
mp_obj_print_helper(print, o->self, PRINT_REPR);
mp_print_str(print, ".");
mp_obj_print_helper(print, o->meth, PRINT_REPR);
mp_print_str(print, ">");
}
#endif

@ -42,16 +42,16 @@ void mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj) {
}
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
STATIC void cell_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
STATIC void cell_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_cell_t *o = o_in;
print(env, "<cell %p ", o->obj);
mp_printf(print, "<cell %p ", o->obj);
if (o->obj == MP_OBJ_NULL) {
print(env, "(nil)");
mp_print_str(print, "(nil)");
} else {
mp_obj_print_helper(print, env, o->obj, PRINT_REPR);
mp_obj_print_helper(print, o->obj, PRINT_REPR);
}
print(env, ">");
mp_print_str(print, ">");
}
#endif