summaryrefslogtreecommitdiff
path: root/py
diff options
context:
space:
mode:
authorScott Shawcroft <scott@tannewt.org>2018-11-30 14:40:01 -0800
committerScott Shawcroft <scott@tannewt.org>2018-11-30 14:40:01 -0800
commit95e03092630bbad9949c5fe32cd51e7c29bc065b (patch)
tree484cb7535142eaabe873bc10552bbfa1b48ab43b /py
parent754d6afd163ae5f295444166863b5d11afd1b2e4 (diff)
parentab94344baee1a5d73d3890de16319cab1e2616de (diff)
Merge remote-tracking branch 'adafruit/master' into mini_sam
Diffstat (limited to 'py')
-rw-r--r--py/builtinhelp.c14
-rw-r--r--[-rwxr-xr-x]py/builtinimport.c10
-rw-r--r--py/emitinlinethumb.c34
-rw-r--r--py/makeqstrdata.py3
-rw-r--r--py/mkenv.mk2
-rw-r--r--py/mkrules.mk2
-rw-r--r--py/modsys.c2
-rw-r--r--py/moduerrno.c37
-rw-r--r--py/mperrno.h3
-rw-r--r--py/obj.h1
-rw-r--r--py/objboundmeth.c3
-rw-r--r--py/objexcept.c201
-rw-r--r--py/py.mk4
13 files changed, 257 insertions, 59 deletions
diff --git a/py/builtinhelp.c b/py/builtinhelp.c
index 4cea7e6d5..9a3407a16 100644
--- a/py/builtinhelp.c
+++ b/py/builtinhelp.c
@@ -27,6 +27,7 @@
#include <stdio.h>
#include <string.h>
+#include "genhdr/mpversion.h"
#include "py/builtin.h"
#include "py/mpconfig.h"
#include "py/objmodule.h"
@@ -133,7 +134,10 @@ STATIC void mp_help_print_modules(void) {
}
// let the user know there may be other modules available from the filesystem
- mp_print_str(MP_PYTHON_PRINTER, "Plus any modules on the filesystem\n");
+ const compressed_string_t* compressed = translate("Plus any modules on the filesystem\n");
+ char decompressed[compressed->length];
+ decompress(compressed, decompressed);
+ mp_print_str(MP_PYTHON_PRINTER, decompressed);
}
#endif
@@ -174,8 +178,12 @@ STATIC void mp_help_print_obj(const mp_obj_t obj) {
STATIC mp_obj_t mp_builtin_help(size_t n_args, const mp_obj_t *args) {
if (n_args == 0) {
- // print a general help message
- mp_print_str(MP_PYTHON_PRINTER, MICROPY_PY_BUILTINS_HELP_TEXT);
+ // print a general help message. Translate only works on single strings on one line.
+ const compressed_string_t* compressed =
+ translate("Welcome to Adafruit CircuitPython %s!\n\nPlease visit learn.adafruit.com/category/circuitpython for project guides.\n\nTo list built-in modules please do `help(\"modules\")`.\n");
+ char decompressed[compressed->length];
+ decompress(compressed, decompressed);
+ mp_printf(MP_PYTHON_PRINTER, decompressed, MICROPY_GIT_TAG);
} else {
// try to print something sensible about the given object
mp_help_print_obj(args[0]);
diff --git a/py/builtinimport.c b/py/builtinimport.c
index fee875b60..6ed0a7594 100755..100644
--- a/py/builtinimport.c
+++ b/py/builtinimport.c
@@ -155,11 +155,9 @@ STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex) {
#endif
#if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_MODULE_FROZEN_MPY
-STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code) {
+STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code, const char *filename) {
#if MICROPY_PY___FILE__
- // TODO
- //qstr source_name = lex->source_name;
- //mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name));
+ mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(qstr_from_str(filename)));
#endif
// execute the module in its context
@@ -222,7 +220,7 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
// its data) in the list of frozen files, execute it.
#if MICROPY_MODULE_FROZEN_MPY
if (frozen_type == MP_FROZEN_MPY) {
- do_execute_raw_code(module_obj, modref);
+ do_execute_raw_code(module_obj, modref, file_str);
return;
}
#endif
@@ -235,7 +233,7 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
#if MICROPY_PERSISTENT_CODE_LOAD
if (file_str[file->len - 3] == 'm') {
mp_raw_code_t *raw_code = mp_raw_code_load_file(file_str);
- do_execute_raw_code(module_obj, raw_code);
+ do_execute_raw_code(module_obj, raw_code, file_str);
return;
}
#endif
diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c
index 577f65672..7f0ec6659 100644
--- a/py/emitinlinethumb.c
+++ b/py/emitinlinethumb.c
@@ -59,7 +59,7 @@ struct _emit_inline_asm_t {
qstr *label_lookup;
};
-STATIC void emit_inline_thumb_error_msg(emit_inline_asm_t *emit, const char *msg) {
+STATIC void emit_inline_thumb_error_msg(emit_inline_asm_t *emit, const compressed_string_t *msg) {
*emit->error_slot = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg);
}
@@ -99,17 +99,17 @@ STATIC void emit_inline_thumb_end_pass(emit_inline_asm_t *emit, mp_uint_t type_s
STATIC mp_uint_t emit_inline_thumb_count_params(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params) {
if (n_params > 4) {
- emit_inline_thumb_error_msg(emit, "can only have up to 4 parameters to Thumb assembly");
+ emit_inline_thumb_error_msg(emit, translate("can only have up to 4 parameters to Thumb assembly"));
return 0;
}
for (mp_uint_t i = 0; i < n_params; i++) {
if (!MP_PARSE_NODE_IS_ID(pn_params[i])) {
- emit_inline_thumb_error_msg(emit, "parameters must be registers in sequence r0 to r3");
+ emit_inline_thumb_error_msg(emit, translate("parameters must be registers in sequence r0 to r3"));
return 0;
}
const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i]));
if (!(strlen(p) == 2 && p[0] == 'r' && p[1] == '0' + i)) {
- emit_inline_thumb_error_msg(emit, "parameters must be registers in sequence r0 to r3");
+ emit_inline_thumb_error_msg(emit, translate("parameters must be registers in sequence r0 to r3"));
return 0;
}
}
@@ -185,7 +185,7 @@ STATIC mp_uint_t get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_n
if (r->reg > max_reg) {
emit_inline_thumb_error_exc(emit,
mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
- "'%s' expects at most r%d", op, max_reg));
+ translate("'%s' expects at most r%d"), op, max_reg));
return 0;
} else {
return r->reg;
@@ -194,7 +194,7 @@ STATIC mp_uint_t get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_n
}
emit_inline_thumb_error_exc(emit,
mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
- "'%s' expects a register", op));
+ translate("'%s' expects a register"), op));
return 0;
}
@@ -208,7 +208,7 @@ STATIC mp_uint_t get_arg_special_reg(emit_inline_asm_t *emit, const char *op, mp
}
emit_inline_thumb_error_exc(emit,
mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
- "'%s' expects a special register", op));
+ translate("'%s' expects a special register"), op));
return 0;
}
@@ -227,7 +227,7 @@ STATIC mp_uint_t get_arg_vfpreg(emit_inline_asm_t *emit, const char *op, mp_pars
if (regno > 31) {
emit_inline_thumb_error_exc(emit,
mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
- "'%s' expects at most r%d", op, 31));
+ translate("'%s' expects at most r%d"), op, 31));
return 0;
} else {
return regno;
@@ -236,7 +236,7 @@ STATIC mp_uint_t get_arg_vfpreg(emit_inline_asm_t *emit, const char *op, mp_pars
malformed:
emit_inline_thumb_error_exc(emit,
mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
- "'%s' expects an FPU register", op));
+ translate("'%s' expects an FPU register"), op));
return 0;
}
#endif
@@ -289,19 +289,19 @@ STATIC mp_uint_t get_arg_reglist(emit_inline_asm_t *emit, const char *op, mp_par
return reglist;
bad_arg:
- emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects {r0, r1, ...}", op));
+ emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, translate("'%s' expects {r0, r1, ...}"), op));
return 0;
}
STATIC uint32_t get_arg_i(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, uint32_t fit_mask) {
mp_obj_t o;
if (!mp_parse_node_get_int_maybe(pn, &o)) {
- emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects an integer", op));
+ emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, translate("'%s' expects an integer"), op));
return 0;
}
uint32_t i = mp_obj_get_int_truncated(o);
if ((i & (~fit_mask)) != 0) {
- emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' integer 0x%x does not fit in mask 0x%x", op, i, fit_mask));
+ emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, translate("'%s' integer 0x%x does not fit in mask 0x%x"), op, i, fit_mask));
return 0;
}
return i;
@@ -325,13 +325,13 @@ STATIC bool get_arg_addr(emit_inline_asm_t *emit, const char *op, mp_parse_node_
return true;
bad_arg:
- emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects an address of the form [a, b]", op));
+ emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, translate("'%s' expects an address of the form [a, b]"), op));
return false;
}
STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) {
if (!MP_PARSE_NODE_IS_ID(pn)) {
- emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects a label", op));
+ emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, translate("'%s' expects a label"), op));
return 0;
}
qstr label_qstr = MP_PARSE_NODE_LEAF_ARG(pn);
@@ -342,7 +342,7 @@ STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_
}
// only need to have the labels on the last pass
if (emit->pass == MP_PASS_EMIT) {
- emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "label '%q' not defined", label_qstr));
+ emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, translate("label '%q' not defined"), label_qstr));
}
return 0;
}
@@ -803,11 +803,11 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
return;
unknown_op:
- emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "unsupported Thumb instruction '%s' with %d arguments", op_str, n_args));
+ emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, translate("unsupported Thumb instruction '%s' with %d arguments"), op_str, n_args));
return;
branch_not_in_range:
- emit_inline_thumb_error_msg(emit, "branch not in range");
+ emit_inline_thumb_error_msg(emit, translate("branch not in range"));
return;
}
diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py
index b0a043ee3..5b5ec1c37 100644
--- a/py/makeqstrdata.py
+++ b/py/makeqstrdata.py
@@ -349,8 +349,7 @@ def print_qstr_data(encoding_table, qcfgs, qstrs, i18ns):
total_text_compressed_size += len(compressed)
decompressed = decompress(encoding_table, len(translation_encoded), compressed).decode("utf-8")
for c in C_ESCAPES:
- decompressed.replace(c, C_ESCAPES[c])
- #print("// \"{}\"".format(translation))
+ decompressed = decompressed.replace(c, C_ESCAPES[c])
print("TRANSLATION(\"{}\", {}, {{ {} }}) // {}".format(original, len(translation_encoded)+1, ", ".join(["0x{:02x}".format(x) for x in compressed]), decompressed))
total_text_size += len(translation.encode("utf-8"))
diff --git a/py/mkenv.mk b/py/mkenv.mk
index facb8a3c2..b76dd60f8 100644
--- a/py/mkenv.mk
+++ b/py/mkenv.mk
@@ -72,7 +72,7 @@ endif
MAKE_FROZEN = $(PYTHON) $(TOP)/tools/make-frozen.py
MPY_CROSS = $(TOP)/mpy-cross/mpy-cross
-MPY_TOOL = $(PYTHON) $(TOP)/tools/mpy-tool.py
+MPY_TOOL = $(PYTHON3) $(TOP)/tools/mpy-tool.py
PREPROCESS_FROZEN_MODULES = PYTHONPATH=$(TOP)/tools/python-semver $(TOP)/tools/preprocess_frozen_modules.py
all:
diff --git a/py/mkrules.mk b/py/mkrules.mk
index e619f2bdd..aa94ba412 100644
--- a/py/mkrules.mk
+++ b/py/mkrules.mk
@@ -130,7 +130,7 @@ xargs -n1 "$(abspath $(MPY_CROSS))" $(MPY_CROSS_FLAGS)
# to build frozen_mpy.c from all .mpy files
# You need to define MPY_TOOL_LONGINT_IMPL in mpconfigport.mk
# if the default will not work (mpz is the default).
-$(BUILD)/frozen_mpy.c: $(BUILD)/frozen_mpy $(BUILD)/genhdr/qstrdefs.generated.h
+$(BUILD)/frozen_mpy.c: $(BUILD)/frozen_mpy $(BUILD)/genhdr/qstrdefs.generated.h $(TOP)/tools/mpy-tool.py
$(STEPECHO) "Creating $@"
$(Q)$(MPY_TOOL) $(MPY_TOOL_LONGINT_IMPL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(shell $(FIND) -L $(BUILD)/frozen_mpy -type f -name '*.mpy') > $@
endif
diff --git a/py/modsys.c b/py/modsys.c
index e32841923..68e048d91 100644
--- a/py/modsys.c
+++ b/py/modsys.c
@@ -135,7 +135,7 @@ STATIC mp_obj_t mp_sys_exc_info(void) {
t->items[0] = MP_OBJ_FROM_PTR(mp_obj_get_type(cur_exc));
t->items[1] = cur_exc;
- t->items[2] = mp_const_none;
+ t->items[2] = mp_obj_exception_get_traceback_obj(cur_exc);
return MP_OBJ_FROM_PTR(t);
}
MP_DEFINE_CONST_FUN_OBJ_0(mp_sys_exc_info_obj, mp_sys_exc_info);
diff --git a/py/moduerrno.c b/py/moduerrno.c
index 255c1a73e..c1feafaa1 100644
--- a/py/moduerrno.c
+++ b/py/moduerrno.c
@@ -136,19 +136,28 @@ const char* mp_errno_to_str(mp_obj_t errno_val) {
#endif //MICROPY_PY_UERRNO
-// For commonly encountered errors, return human readable strings
-const compressed_string_t* mp_common_errno_to_str(mp_obj_t errno_val) {
- if (MP_OBJ_IS_SMALL_INT(errno_val)) {
- switch (MP_OBJ_SMALL_INT_VALUE(errno_val)) {
- case EPERM: return translate("Permission denied");
- case ENOENT: return translate("No such file/directory");
- case EIO: return translate("Input/output error");
- case EACCES: return translate("Permission denied");
- case EEXIST: return translate("File exists");
- case ENODEV: return translate("Unsupported operation");
- case EINVAL: return translate("Invalid argument");
- case EROFS: return translate("Read-only filesystem");
- }
+// For commonly encountered errors, return human readable strings, otherwise try errno name
+const char *mp_common_errno_to_str(mp_obj_t errno_val, char *buf, size_t len) {
+ if (!MP_OBJ_IS_SMALL_INT(errno_val)) {
+ return NULL;
+ }
+
+ const compressed_string_t* desc = NULL;
+ switch (MP_OBJ_SMALL_INT_VALUE(errno_val)) {
+ case EPERM: desc = translate("Permission denied"); break;
+ case ENOENT: desc = translate("No such file/directory"); break;
+ case EIO: desc = translate("Input/output error"); break;
+ case EACCES: desc = translate("Permission denied"); break;
+ case EEXIST: desc = translate("File exists"); break;
+ case ENODEV: desc = translate("Unsupported operation"); break;
+ case EINVAL: desc = translate("Invalid argument"); break;
+ case EROFS: desc = translate("Read-only filesystem"); break;
}
- return NULL;
+ if (desc != NULL && desc->length <= len) {
+ decompress(desc, buf);
+ return buf;
+ }
+
+ const char *msg = mp_errno_to_str(errno_val);
+ return msg[0] != '\0' ? msg : NULL;
}
diff --git a/py/mperrno.h b/py/mperrno.h
index 876b090b5..911a9b413 100644
--- a/py/mperrno.h
+++ b/py/mperrno.h
@@ -141,7 +141,6 @@
#endif
const char* mp_errno_to_str(mp_obj_t errno_val);
-// For commonly encountered errors, return compressed human readable strings
-const compressed_string_t* mp_common_errno_to_str(mp_obj_t errno_val);
+const char *mp_common_errno_to_str(mp_obj_t errno_val, char *buf, size_t len);
#endif // MICROPY_INCLUDED_PY_MPERRNO_H
diff --git a/py/obj.h b/py/obj.h
index 59cce0836..8b6772873 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -717,6 +717,7 @@ bool mp_obj_exception_match(mp_obj_t exc, mp_const_obj_t exc_type);
void mp_obj_exception_clear_traceback(mp_obj_t self_in);
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qstr block);
void mp_obj_exception_get_traceback(mp_obj_t self_in, size_t *n, size_t **values);
+mp_obj_t mp_obj_exception_get_traceback_obj(mp_obj_t self_in);
mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in);
mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args);
mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in);
diff --git a/py/objboundmeth.c b/py/objboundmeth.c
index b0df6a68a..a05680d41 100644
--- a/py/objboundmeth.c
+++ b/py/objboundmeth.c
@@ -92,6 +92,9 @@ STATIC void bound_meth_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
if (attr == MP_QSTR___name__) {
mp_obj_bound_meth_t *o = MP_OBJ_TO_PTR(self_in);
dest[0] = MP_OBJ_NEW_QSTR(mp_obj_fun_get_name(o->meth));
+ } else if (attr == MP_QSTR___func__) {
+ mp_obj_bound_meth_t *o = MP_OBJ_TO_PTR(self_in);
+ dest[0] = o->meth;
}
}
#endif
diff --git a/py/objexcept.c b/py/objexcept.c
index 8bd6245a4..c54e5fd4a 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -30,6 +30,7 @@
#include <stdio.h>
#include "py/objlist.h"
+#include "py/objnamedtuple.h"
#include "py/objstr.h"
#include "py/objtuple.h"
#include "py/objtype.h"
@@ -113,17 +114,11 @@ void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kin
return;
} else if (o->args->len == 1) {
// try to provide a nice OSError error message
- if (o->base.type == &mp_type_OSError && MP_OBJ_IS_SMALL_INT(o->args->items[0])) {
- const compressed_string_t* common = mp_common_errno_to_str(o->args->items[0]);
- const char* msg;
+ if (MP_OBJ_IS_SMALL_INT(o->args->items[0]) &&
+ mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(o->base.type), MP_OBJ_FROM_PTR(&mp_type_OSError))) {
char decompressed[50];
- if (common != NULL && common->length <= 50) {
- decompress(common, decompressed);
- msg = decompressed;
- } else {
- msg = mp_errno_to_str(o->args->items[0]);
- }
- if (msg[0] != '\0') {
+ const char *msg = mp_common_errno_to_str(o->args->items[0], decompressed, sizeof(decompressed));
+ if (msg != NULL) {
mp_printf(print, "[Errno " INT_FMT "] %s", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), msg);
return;
}
@@ -214,6 +209,31 @@ void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
dest[0] = MP_OBJ_FROM_PTR(self->args);
} else if (self->base.type == &mp_type_StopIteration && attr == MP_QSTR_value) {
dest[0] = mp_obj_exception_get_value(self_in);
+ #if MICROPY_CPYTHON_COMPAT
+ } else if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(self->base.type), MP_OBJ_FROM_PTR(&mp_type_OSError))) {
+ if (attr == MP_QSTR_errno) {
+ dest[0] = mp_obj_exception_get_value(self_in);
+ } else if (attr == MP_QSTR_strerror) {
+ if (self->args->len > 1) {
+ dest[0] = self->args->items[1];
+ } else if (self->args->len > 0) {
+ char decompressed[50];
+ const char *msg = mp_common_errno_to_str(self->args->items[0], decompressed, sizeof(decompressed));
+ if (msg != NULL) {
+ dest[0] = mp_obj_new_str(msg, strlen(msg));
+ } else {
+ dest[0] = mp_const_none;
+ }
+ } else {
+ dest[0] = mp_const_none;
+ }
+ } else if (attr == MP_QSTR_filename) {
+ dest[0] = self->args->len > 2 ? self->args->items[2] : mp_const_none;
+ // skip winerror
+ } else if (attr == MP_QSTR_filename2) {
+ dest[0] = self->args->len > 4 ? self->args->items[4] : mp_const_none;
+ }
+ #endif
}
}
@@ -531,3 +551,164 @@ void mp_obj_exception_get_traceback(mp_obj_t self_in, size_t *n, size_t **values
*values = self->traceback_data;
}
}
+
+#if MICROPY_PY_SYS_EXC_INFO
+STATIC const mp_obj_namedtuple_type_t code_type_obj = {
+ .base = {
+ .base = {
+ .type = &mp_type_type
+ },
+ .name = MP_QSTR_code,
+ .print = namedtuple_print,
+ .make_new = namedtuple_make_new,
+ .unary_op = mp_obj_tuple_unary_op,
+ .binary_op = mp_obj_tuple_binary_op,
+ .attr = namedtuple_attr,
+ .subscr = mp_obj_tuple_subscr,
+ .getiter = mp_obj_tuple_getiter,
+ .parent = &mp_type_tuple,
+ },
+ .n_fields = 15,
+ .fields = {
+ MP_QSTR_co_argcount,
+ MP_QSTR_co_kwonlyargcount,
+ MP_QSTR_co_nlocals,
+ MP_QSTR_co_stacksize,
+ MP_QSTR_co_flags,
+ MP_QSTR_co_code,
+ MP_QSTR_co_consts,
+ MP_QSTR_co_names,
+ MP_QSTR_co_varnames,
+ MP_QSTR_co_freevars,
+ MP_QSTR_co_cellvars,
+ MP_QSTR_co_filename,
+ MP_QSTR_co_name,
+ MP_QSTR_co_firstlineno,
+ MP_QSTR_co_lnotab,
+ },
+};
+
+STATIC mp_obj_t code_make_new(qstr file, qstr block) {
+ mp_obj_t elems[15] = {
+ mp_obj_new_int(0), // co_argcount
+ mp_obj_new_int(0), // co_kwonlyargcount
+ mp_obj_new_int(0), // co_nlocals
+ mp_obj_new_int(0), // co_stacksize
+ mp_obj_new_int(0), // co_flags
+ mp_obj_new_bytearray(0, NULL), // co_code
+ mp_obj_new_tuple(0, NULL), // co_consts
+ mp_obj_new_tuple(0, NULL), // co_names
+ mp_obj_new_tuple(0, NULL), // co_varnames
+ mp_obj_new_tuple(0, NULL), // co_freevars
+ mp_obj_new_tuple(0, NULL), // co_cellvars
+ MP_OBJ_NEW_QSTR(file), // co_filename
+ MP_OBJ_NEW_QSTR(block), // co_name
+ mp_obj_new_int(1), // co_firstlineno
+ mp_obj_new_bytearray(0, NULL), // co_lnotab
+ };
+
+ return namedtuple_make_new((const mp_obj_type_t*)&code_type_obj, 15, 0, elems);
+}
+
+STATIC const mp_obj_namedtuple_type_t frame_type_obj = {
+ .base = {
+ .base = {
+ .type = &mp_type_type
+ },
+ .name = MP_QSTR_frame,
+ .print = namedtuple_print,
+ .make_new = namedtuple_make_new,
+ .unary_op = mp_obj_tuple_unary_op,
+ .binary_op = mp_obj_tuple_binary_op,
+ .attr = namedtuple_attr,
+ .subscr = mp_obj_tuple_subscr,
+ .getiter = mp_obj_tuple_getiter,
+ .parent = &mp_type_tuple,
+ },
+ .n_fields = 8,
+ .fields = {
+ MP_QSTR_f_back,
+ MP_QSTR_f_builtins,
+ MP_QSTR_f_code,
+ MP_QSTR_f_globals,
+ MP_QSTR_f_lasti,
+ MP_QSTR_f_lineno,
+ MP_QSTR_f_locals,
+ MP_QSTR_f_trace,
+ },
+};
+
+STATIC mp_obj_t frame_make_new(mp_obj_t f_code, int f_lineno) {
+ mp_obj_t elems[8] = {
+ mp_const_none, // f_back
+ mp_obj_new_dict(0), // f_builtins
+ f_code, // f_code
+ mp_obj_new_dict(0), // f_globals
+ mp_obj_new_int(0), // f_lasti
+ mp_obj_new_int(f_lineno), // f_lineno
+ mp_obj_new_dict(0), // f_locals
+ mp_const_none, // f_trace
+ };
+
+ return namedtuple_make_new((const mp_obj_type_t*)&frame_type_obj, 8, 0, elems);
+}
+
+STATIC const mp_obj_namedtuple_type_t traceback_type_obj = {
+ .base = {
+ .base = {
+ .type = &mp_type_type
+ },
+ .name = MP_QSTR_traceback,
+ .print = namedtuple_print,
+ .make_new = namedtuple_make_new,
+ .unary_op = mp_obj_tuple_unary_op,
+ .binary_op = mp_obj_tuple_binary_op,
+ .attr = namedtuple_attr,
+ .subscr = mp_obj_tuple_subscr,
+ .getiter = mp_obj_tuple_getiter,
+ .parent = &mp_type_tuple,
+ },
+ .n_fields = 4,
+ .fields = {
+ MP_QSTR_tb_frame,
+ MP_QSTR_tb_lasti,
+ MP_QSTR_tb_lineno,
+ MP_QSTR_tb_next,
+ },
+};
+
+STATIC mp_obj_t traceback_from_values(size_t *values, mp_obj_t tb_next) {
+ int lineno = values[1];
+
+ mp_obj_t elems[4] = {
+ frame_make_new(code_make_new(values[0], values[2]), lineno),
+ mp_obj_new_int(0),
+ mp_obj_new_int(lineno),
+ tb_next,
+ };
+
+ return namedtuple_make_new((const mp_obj_type_t*)&traceback_type_obj, 4, 0, elems);
+};
+
+mp_obj_t mp_obj_exception_get_traceback_obj(mp_obj_t self_in) {
+ mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in);
+
+ if (!mp_obj_is_exception_instance(self)) {
+ return mp_const_none;
+ }
+
+ size_t n, *values;
+ mp_obj_exception_get_traceback(self, &n, &values);
+ if (n == 0) {
+ return mp_const_none;
+ }
+
+ mp_obj_t tb_next = mp_const_none;
+
+ for (size_t i = 0; i < n; i += 3) {
+ tb_next = traceback_from_values(&values[i], tb_next);
+ }
+
+ return tb_next;
+}
+#endif
diff --git a/py/py.mk b/py/py.mk
index 9874dde4d..c640e6cff 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -307,7 +307,7 @@ $(HEADER_BUILD)/qstrdefs.preprocessed.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEF
# qstr data
$(HEADER_BUILD)/qstrdefs.enum.h: $(PY_SRC)/makeqstrdata.py $(HEADER_BUILD)/qstrdefs.preprocessed.h
$(STEPECHO) "GEN $@"
- $(PYTHON3) $(PY_SRC)/makeqstrdata.py $(HEADER_BUILD)/qstrdefs.preprocessed.h > $@
+ $(Q)$(PYTHON3) $(PY_SRC)/makeqstrdata.py $(HEADER_BUILD)/qstrdefs.preprocessed.h > $@
# Adding an order only dependency on $(HEADER_BUILD) causes $(HEADER_BUILD) to get
# created before we run the script to generate the .h
@@ -315,7 +315,7 @@ $(HEADER_BUILD)/qstrdefs.enum.h: $(PY_SRC)/makeqstrdata.py $(HEADER_BUILD)/qstrd
# the lines in "" and then unwrap after the preprocessor is finished.
$(HEADER_BUILD)/qstrdefs.generated.h: $(PY_SRC)/makeqstrdata.py $(HEADER_BUILD)/$(TRANSLATION).mo $(HEADER_BUILD)/qstrdefs.preprocessed.h
$(STEPECHO) "GEN $@"
- $(PYTHON3) $(PY_SRC)/makeqstrdata.py --compression_filename $(HEADER_BUILD)/compression.generated.h --translation $(HEADER_BUILD)/$(TRANSLATION).mo $(HEADER_BUILD)/qstrdefs.preprocessed.h > $@
+ $(Q)$(PYTHON3) $(PY_SRC)/makeqstrdata.py --compression_filename $(HEADER_BUILD)/compression.generated.h --translation $(HEADER_BUILD)/$(TRANSLATION).mo $(HEADER_BUILD)/qstrdefs.preprocessed.h > $@
$(PY_BUILD)/qstr.o: $(HEADER_BUILD)/qstrdefs.generated.h