blob: 1a8b328be5ff809a44c22caacbf41b69b1ae373c [file] [log] [blame]
Damien George04b91472014-05-03 23:27:38 +01001/*
2 * This file is part of the Micro Python project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2013, 2014 Damien P. George
Paul Sokolovskyda9f0922014-05-13 08:44:45 +03007 * Copyright (c) 2014 Paul Sokolovsky
Damien George04b91472014-05-03 23:27:38 +01008 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
Paul Sokolovskyd08fd682014-02-27 22:22:04 +020028#include <string.h>
29
Paul Sokolovskyd08fd682014-02-27 22:22:04 +020030#include "mpconfig.h"
Paul Sokolovskyf54bcbf2014-05-02 17:47:01 +030031#include "misc.h"
Paul Sokolovskyd08fd682014-02-27 22:22:04 +020032#include "nlr.h"
33#include "qstr.h"
34#include "obj.h"
35#include "objtuple.h"
36
Damien Georgeee3fd462014-05-24 23:03:12 +010037#if MICROPY_PY_COLLECTIONS
Damien George107c9fb2014-04-26 10:31:15 +010038
Paul Sokolovskyd08fd682014-02-27 22:22:04 +020039typedef struct _mp_obj_namedtuple_type_t {
40 mp_obj_type_t base;
41 const char *fields;
42} mp_obj_namedtuple_type_t;
43
44typedef struct _mp_obj_namedtuple_t {
45 mp_obj_tuple_t tuple;
46} mp_obj_namedtuple_t;
47
48static inline bool is_end_tok(char c) {
49 return c == ' ' || c == ',';
50}
51
52static inline const char *skip_to_next(const char *p) {
53 while (!is_end_tok(*p)) {
54 if (*p == 0) {
55 return NULL;
56 }
57 p++;
58 }
59 while (is_end_tok(*p)) {
60 if (*p == 0) {
61 return NULL;
62 }
63 p++;
64 }
65 return p;
66}
67
68STATIC uint namedtuple_count_fields(const char *namedef) {
69 uint cnt = 0;
70 while (*namedef != 0) {
71 cnt++;
72 while (!is_end_tok(*namedef) && *namedef != 0) {
73 namedef++;
74 }
75 while (is_end_tok(*namedef) && *namedef != 0) {
76 namedef++;
77 }
78 }
79 return cnt;
80}
81
82STATIC int namedtuple_find_field(const char *name, const char *namedef) {
83 int id = 0;
84 int len = strlen(name);
85 while (namedef) {
86 if (memcmp(name, namedef, len) == 0) {
87 namedef += len;
88 if (*namedef == 0 || is_end_tok(*namedef)) {
89 return id;
90 }
91 }
92 namedef = skip_to_next(namedef);
93 id++;
94 }
95
96 return -1;
97}
98
99STATIC void namedtuple_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
100 mp_obj_namedtuple_t *o = o_in;
101 print(env, "%s(", qstr_str(o->tuple.base.type->name));
102 const char *fields = ((mp_obj_namedtuple_type_t*)o->tuple.base.type)->fields;
103
104 for (int i = 0; i < o->tuple.len; i++) {
105 if (i > 0) {
106 print(env, ", ");
107 }
108 const char *next = fields;
109
110 while (!is_end_tok(*next) && *next != 0) {
111 next++;
112 }
113 print(env, "%.*s=", next - fields, fields);
114 mp_obj_print_helper(print, env, o->tuple.items[i], PRINT_REPR);
115 while (is_end_tok(*next) && *next != 0) {
116 next++;
117 }
118 fields = next;
119 }
120 print(env, ")");
121}
122
123STATIC void namedtuple_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
124 mp_obj_namedtuple_t *self = self_in;
125 const char *fields = ((mp_obj_namedtuple_type_t*)self->tuple.base.type)->fields;
126 int id = namedtuple_find_field(qstr_str(attr), fields);
127 if (id < 0) {
128 return;
129 }
130 dest[0] = self->tuple.items[id];
131}
132
133STATIC bool namedtuple_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
Damien Georgeea13f402014-04-05 18:32:08 +0100134 nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "can't set attribute"));
Paul Sokolovskyd08fd682014-02-27 22:22:04 +0200135}
136
Damien Georgeecc88e92014-08-30 00:35:11 +0100137STATIC mp_obj_t namedtuple_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
Paul Sokolovskyd08fd682014-02-27 22:22:04 +0200138 mp_obj_namedtuple_type_t *type = type_in;
139 uint num_fields = namedtuple_count_fields(type->fields);
140 if (n_args != num_fields) {
141 // Counts include implicit "self"
Damien Georgeea13f402014-04-05 18:32:08 +0100142 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
Paul Sokolovskyd08fd682014-02-27 22:22:04 +0200143 "__new__() takes %d positional arguments but %d were given",
144 num_fields + 1, n_args + 1));
145 }
146 mp_obj_tuple_t *tuple = mp_obj_new_tuple(n_args, args);
147 tuple->base.type = type_in;
148 return tuple;
149}
150
Damien George07ddab52014-03-29 13:15:08 +0000151STATIC const mp_obj_tuple_t namedtuple_base_tuple = {{&mp_type_tuple}, 1, {(mp_obj_t)&mp_type_tuple}};
Paul Sokolovskyd08fd682014-02-27 22:22:04 +0200152
153mp_obj_t mp_obj_new_namedtuple_type(qstr name, const char *fields) {
154 mp_obj_namedtuple_type_t *o = m_new0(mp_obj_namedtuple_type_t, 1);
155 o->base.base.type = &mp_type_type;
156 o->base.name = name;
157 o->base.print = namedtuple_print;
158 o->base.make_new = namedtuple_make_new;
Damien George2323ef92014-05-11 18:00:45 +0100159 o->base.unary_op = mp_obj_tuple_unary_op;
160 o->base.binary_op = mp_obj_tuple_binary_op;
Paul Sokolovskyd08fd682014-02-27 22:22:04 +0200161 o->base.load_attr = namedtuple_load_attr;
162 o->base.store_attr = namedtuple_store_attr;
Damien George2323ef92014-05-11 18:00:45 +0100163 o->base.subscr = mp_obj_tuple_subscr;
164 o->base.getiter = mp_obj_tuple_getiter;
Paul Sokolovskyd08fd682014-02-27 22:22:04 +0200165 o->base.bases_tuple = (mp_obj_t)&namedtuple_base_tuple;
166 o->fields = fields;
167 return o;
168}
169
170STATIC mp_obj_t new_namedtuple_type(mp_obj_t name_in, mp_obj_t fields_in) {
171 qstr name = MP_OBJ_QSTR_VALUE(name_in);
172 const char *fields = mp_obj_str_get_str(fields_in);
173 return mp_obj_new_namedtuple_type(name, fields);
174}
175MP_DEFINE_CONST_FUN_OBJ_2(mp_namedtuple_obj, new_namedtuple_type);
Damien George107c9fb2014-04-26 10:31:15 +0100176
Damien Georgeee3fd462014-05-24 23:03:12 +0100177#endif // MICROPY_PY_COLLECTIONS