Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
py/objnamedtuple.c@10:33521d742af1, 2016-04-27 (annotated)
- Committer:
- Colin Hogben
- Date:
- Wed Apr 27 22:11:29 2016 +0100
- Revision:
- 10:33521d742af1
- Parent:
- 0:5868e8752d44
Update README and version
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| pythontech | 0:5868e8752d44 | 1 | /* |
| pythontech | 0:5868e8752d44 | 2 | * This file is part of the Micro Python project, http://micropython.org/ |
| pythontech | 0:5868e8752d44 | 3 | * |
| pythontech | 0:5868e8752d44 | 4 | * The MIT License (MIT) |
| pythontech | 0:5868e8752d44 | 5 | * |
| pythontech | 0:5868e8752d44 | 6 | * Copyright (c) 2013, 2014 Damien P. George |
| pythontech | 0:5868e8752d44 | 7 | * Copyright (c) 2014 Paul Sokolovsky |
| pythontech | 0:5868e8752d44 | 8 | * |
| pythontech | 0:5868e8752d44 | 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| pythontech | 0:5868e8752d44 | 10 | * of this software and associated documentation files (the "Software"), to deal |
| pythontech | 0:5868e8752d44 | 11 | * in the Software without restriction, including without limitation the rights |
| pythontech | 0:5868e8752d44 | 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| pythontech | 0:5868e8752d44 | 13 | * copies of the Software, and to permit persons to whom the Software is |
| pythontech | 0:5868e8752d44 | 14 | * furnished to do so, subject to the following conditions: |
| pythontech | 0:5868e8752d44 | 15 | * |
| pythontech | 0:5868e8752d44 | 16 | * The above copyright notice and this permission notice shall be included in |
| pythontech | 0:5868e8752d44 | 17 | * all copies or substantial portions of the Software. |
| pythontech | 0:5868e8752d44 | 18 | * |
| pythontech | 0:5868e8752d44 | 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| pythontech | 0:5868e8752d44 | 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| pythontech | 0:5868e8752d44 | 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| pythontech | 0:5868e8752d44 | 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| pythontech | 0:5868e8752d44 | 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| pythontech | 0:5868e8752d44 | 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| pythontech | 0:5868e8752d44 | 25 | * THE SOFTWARE. |
| pythontech | 0:5868e8752d44 | 26 | */ |
| pythontech | 0:5868e8752d44 | 27 | |
| pythontech | 0:5868e8752d44 | 28 | #include <string.h> |
| pythontech | 0:5868e8752d44 | 29 | |
| pythontech | 0:5868e8752d44 | 30 | #include "py/nlr.h" |
| pythontech | 0:5868e8752d44 | 31 | #include "py/objtuple.h" |
| pythontech | 0:5868e8752d44 | 32 | #include "py/runtime.h" |
| pythontech | 0:5868e8752d44 | 33 | #include "py/objstr.h" |
| pythontech | 0:5868e8752d44 | 34 | |
| pythontech | 0:5868e8752d44 | 35 | #if MICROPY_PY_COLLECTIONS |
| pythontech | 0:5868e8752d44 | 36 | |
| pythontech | 0:5868e8752d44 | 37 | typedef struct _mp_obj_namedtuple_type_t { |
| pythontech | 0:5868e8752d44 | 38 | mp_obj_type_t base; |
| pythontech | 0:5868e8752d44 | 39 | mp_uint_t n_fields; |
| pythontech | 0:5868e8752d44 | 40 | qstr fields[]; |
| pythontech | 0:5868e8752d44 | 41 | } mp_obj_namedtuple_type_t; |
| pythontech | 0:5868e8752d44 | 42 | |
| pythontech | 0:5868e8752d44 | 43 | typedef struct _mp_obj_namedtuple_t { |
| pythontech | 0:5868e8752d44 | 44 | mp_obj_tuple_t tuple; |
| pythontech | 0:5868e8752d44 | 45 | } mp_obj_namedtuple_t; |
| pythontech | 0:5868e8752d44 | 46 | |
| pythontech | 0:5868e8752d44 | 47 | STATIC mp_uint_t namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name) { |
| pythontech | 0:5868e8752d44 | 48 | for (mp_uint_t i = 0; i < type->n_fields; i++) { |
| pythontech | 0:5868e8752d44 | 49 | if (type->fields[i] == name) { |
| pythontech | 0:5868e8752d44 | 50 | return i; |
| pythontech | 0:5868e8752d44 | 51 | } |
| pythontech | 0:5868e8752d44 | 52 | } |
| pythontech | 0:5868e8752d44 | 53 | return -1; |
| pythontech | 0:5868e8752d44 | 54 | } |
| pythontech | 0:5868e8752d44 | 55 | |
| pythontech | 0:5868e8752d44 | 56 | STATIC void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { |
| pythontech | 0:5868e8752d44 | 57 | (void)kind; |
| pythontech | 0:5868e8752d44 | 58 | mp_obj_namedtuple_t *o = MP_OBJ_TO_PTR(o_in); |
| pythontech | 0:5868e8752d44 | 59 | mp_printf(print, "%q", o->tuple.base.type->name); |
| pythontech | 0:5868e8752d44 | 60 | const qstr *fields = ((mp_obj_namedtuple_type_t*)o->tuple.base.type)->fields; |
| pythontech | 0:5868e8752d44 | 61 | mp_obj_attrtuple_print_helper(print, fields, &o->tuple); |
| pythontech | 0:5868e8752d44 | 62 | } |
| pythontech | 0:5868e8752d44 | 63 | |
| pythontech | 0:5868e8752d44 | 64 | STATIC void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { |
| pythontech | 0:5868e8752d44 | 65 | if (dest[0] == MP_OBJ_NULL) { |
| pythontech | 0:5868e8752d44 | 66 | // load attribute |
| pythontech | 0:5868e8752d44 | 67 | mp_obj_namedtuple_t *self = MP_OBJ_TO_PTR(self_in); |
| pythontech | 0:5868e8752d44 | 68 | int id = namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr); |
| pythontech | 0:5868e8752d44 | 69 | if (id == -1) { |
| pythontech | 0:5868e8752d44 | 70 | return; |
| pythontech | 0:5868e8752d44 | 71 | } |
| pythontech | 0:5868e8752d44 | 72 | dest[0] = self->tuple.items[id]; |
| pythontech | 0:5868e8752d44 | 73 | } else { |
| pythontech | 0:5868e8752d44 | 74 | // delete/store attribute |
| pythontech | 0:5868e8752d44 | 75 | // provide more detailed error message than we'd get by just returning |
| pythontech | 0:5868e8752d44 | 76 | nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "can't set attribute")); |
| pythontech | 0:5868e8752d44 | 77 | } |
| pythontech | 0:5868e8752d44 | 78 | } |
| pythontech | 0:5868e8752d44 | 79 | |
| pythontech | 0:5868e8752d44 | 80 | STATIC mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { |
| pythontech | 0:5868e8752d44 | 81 | const mp_obj_namedtuple_type_t *type = (const mp_obj_namedtuple_type_t*)type_in; |
| pythontech | 0:5868e8752d44 | 82 | size_t num_fields = type->n_fields; |
| pythontech | 0:5868e8752d44 | 83 | if (n_args + n_kw != num_fields) { |
| pythontech | 0:5868e8752d44 | 84 | if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { |
| pythontech | 0:5868e8752d44 | 85 | mp_arg_error_terse_mismatch(); |
| pythontech | 0:5868e8752d44 | 86 | } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL) { |
| pythontech | 0:5868e8752d44 | 87 | nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, |
| pythontech | 0:5868e8752d44 | 88 | "function takes %d positional arguments but %d were given", |
| pythontech | 0:5868e8752d44 | 89 | num_fields, n_args + n_kw)); |
| pythontech | 0:5868e8752d44 | 90 | } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED) { |
| pythontech | 0:5868e8752d44 | 91 | nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, |
| pythontech | 0:5868e8752d44 | 92 | "%q() takes %d positional arguments but %d were given", |
| pythontech | 0:5868e8752d44 | 93 | type->base.name, num_fields, n_args + n_kw)); |
| pythontech | 0:5868e8752d44 | 94 | } |
| pythontech | 0:5868e8752d44 | 95 | } |
| pythontech | 0:5868e8752d44 | 96 | |
| pythontech | 0:5868e8752d44 | 97 | mp_obj_t *arg_objects; |
| pythontech | 0:5868e8752d44 | 98 | if (n_args == num_fields) { |
| pythontech | 0:5868e8752d44 | 99 | arg_objects = (mp_obj_t*)args; |
| pythontech | 0:5868e8752d44 | 100 | } else { |
| pythontech | 0:5868e8752d44 | 101 | size_t alloc_size = sizeof(mp_obj_t) * num_fields; |
| pythontech | 0:5868e8752d44 | 102 | arg_objects = alloca(alloc_size); |
| pythontech | 0:5868e8752d44 | 103 | memset(arg_objects, 0, alloc_size); |
| pythontech | 0:5868e8752d44 | 104 | |
| pythontech | 0:5868e8752d44 | 105 | for (mp_uint_t i = 0; i < n_args; i++) { |
| pythontech | 0:5868e8752d44 | 106 | arg_objects[i] = args[i]; |
| pythontech | 0:5868e8752d44 | 107 | } |
| pythontech | 0:5868e8752d44 | 108 | |
| pythontech | 0:5868e8752d44 | 109 | for (mp_uint_t i = n_args; i < n_args + 2 * n_kw; i += 2) { |
| pythontech | 0:5868e8752d44 | 110 | qstr kw = mp_obj_str_get_qstr(args[i]); |
| pythontech | 0:5868e8752d44 | 111 | int id = namedtuple_find_field(type, kw); |
| pythontech | 0:5868e8752d44 | 112 | if (id == -1) { |
| pythontech | 0:5868e8752d44 | 113 | if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { |
| pythontech | 0:5868e8752d44 | 114 | mp_arg_error_terse_mismatch(); |
| pythontech | 0:5868e8752d44 | 115 | } else { |
| pythontech | 0:5868e8752d44 | 116 | nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, |
| pythontech | 0:5868e8752d44 | 117 | "unexpected keyword argument '%q'", kw)); |
| pythontech | 0:5868e8752d44 | 118 | } |
| pythontech | 0:5868e8752d44 | 119 | } |
| pythontech | 0:5868e8752d44 | 120 | if (arg_objects[id] != MP_OBJ_NULL) { |
| pythontech | 0:5868e8752d44 | 121 | if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { |
| pythontech | 0:5868e8752d44 | 122 | mp_arg_error_terse_mismatch(); |
| pythontech | 0:5868e8752d44 | 123 | } else { |
| pythontech | 0:5868e8752d44 | 124 | nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, |
| pythontech | 0:5868e8752d44 | 125 | "function got multiple values for argument '%q'", kw)); |
| pythontech | 0:5868e8752d44 | 126 | } |
| pythontech | 0:5868e8752d44 | 127 | } |
| pythontech | 0:5868e8752d44 | 128 | arg_objects[id] = args[i + 1]; |
| pythontech | 0:5868e8752d44 | 129 | } |
| pythontech | 0:5868e8752d44 | 130 | } |
| pythontech | 0:5868e8752d44 | 131 | |
| pythontech | 0:5868e8752d44 | 132 | mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_fields, arg_objects)); |
| pythontech | 0:5868e8752d44 | 133 | tuple->base.type = type_in; |
| pythontech | 0:5868e8752d44 | 134 | return MP_OBJ_FROM_PTR(tuple); |
| pythontech | 0:5868e8752d44 | 135 | } |
| pythontech | 0:5868e8752d44 | 136 | |
| pythontech | 0:5868e8752d44 | 137 | STATIC const mp_rom_obj_tuple_t namedtuple_base_tuple = {{&mp_type_tuple}, 1, {MP_ROM_PTR(&mp_type_tuple)}}; |
| pythontech | 0:5868e8752d44 | 138 | |
| pythontech | 0:5868e8752d44 | 139 | STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, mp_uint_t n_fields, mp_obj_t *fields) { |
| pythontech | 0:5868e8752d44 | 140 | mp_obj_namedtuple_type_t *o = m_new_obj_var(mp_obj_namedtuple_type_t, qstr, n_fields); |
| pythontech | 0:5868e8752d44 | 141 | memset(&o->base, 0, sizeof(o->base)); |
| pythontech | 0:5868e8752d44 | 142 | o->base.base.type = &mp_type_type; |
| pythontech | 0:5868e8752d44 | 143 | o->base.name = name; |
| pythontech | 0:5868e8752d44 | 144 | o->base.print = namedtuple_print; |
| pythontech | 0:5868e8752d44 | 145 | o->base.make_new = namedtuple_make_new; |
| pythontech | 0:5868e8752d44 | 146 | o->base.unary_op = mp_obj_tuple_unary_op; |
| pythontech | 0:5868e8752d44 | 147 | o->base.binary_op = mp_obj_tuple_binary_op; |
| pythontech | 0:5868e8752d44 | 148 | o->base.attr = namedtuple_attr; |
| pythontech | 0:5868e8752d44 | 149 | o->base.subscr = mp_obj_tuple_subscr; |
| pythontech | 0:5868e8752d44 | 150 | o->base.getiter = mp_obj_tuple_getiter; |
| pythontech | 0:5868e8752d44 | 151 | o->base.bases_tuple = (mp_obj_tuple_t*)(mp_rom_obj_tuple_t*)&namedtuple_base_tuple; |
| pythontech | 0:5868e8752d44 | 152 | o->n_fields = n_fields; |
| pythontech | 0:5868e8752d44 | 153 | for (mp_uint_t i = 0; i < n_fields; i++) { |
| pythontech | 0:5868e8752d44 | 154 | o->fields[i] = mp_obj_str_get_qstr(fields[i]); |
| pythontech | 0:5868e8752d44 | 155 | } |
| pythontech | 0:5868e8752d44 | 156 | return MP_OBJ_FROM_PTR(o); |
| pythontech | 0:5868e8752d44 | 157 | } |
| pythontech | 0:5868e8752d44 | 158 | |
| pythontech | 0:5868e8752d44 | 159 | STATIC mp_obj_t new_namedtuple_type(mp_obj_t name_in, mp_obj_t fields_in) { |
| pythontech | 0:5868e8752d44 | 160 | qstr name = mp_obj_str_get_qstr(name_in); |
| pythontech | 0:5868e8752d44 | 161 | mp_uint_t n_fields; |
| pythontech | 0:5868e8752d44 | 162 | mp_obj_t *fields; |
| pythontech | 0:5868e8752d44 | 163 | #if MICROPY_CPYTHON_COMPAT |
| pythontech | 0:5868e8752d44 | 164 | if (MP_OBJ_IS_STR(fields_in)) { |
| pythontech | 0:5868e8752d44 | 165 | fields_in = mp_obj_str_split(1, &fields_in); |
| pythontech | 0:5868e8752d44 | 166 | } |
| pythontech | 0:5868e8752d44 | 167 | #endif |
| pythontech | 0:5868e8752d44 | 168 | if (!MP_OBJ_IS_TYPE(fields_in, &mp_type_list)) { |
| pythontech | 0:5868e8752d44 | 169 | nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "list required")); |
| pythontech | 0:5868e8752d44 | 170 | } |
| pythontech | 0:5868e8752d44 | 171 | mp_obj_list_get(fields_in, &n_fields, &fields); |
| pythontech | 0:5868e8752d44 | 172 | return mp_obj_new_namedtuple_type(name, n_fields, fields); |
| pythontech | 0:5868e8752d44 | 173 | } |
| pythontech | 0:5868e8752d44 | 174 | MP_DEFINE_CONST_FUN_OBJ_2(mp_namedtuple_obj, new_namedtuple_type); |
| pythontech | 0:5868e8752d44 | 175 | |
| pythontech | 0:5868e8752d44 | 176 | #endif // MICROPY_PY_COLLECTIONS |