1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2013, 2014 Damien P. George
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  * THE SOFTWARE.
25  */
26 
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <stdarg.h>
30 #include <assert.h>
31 
32 #include "py/obj.h"
33 #include "py/objtype.h"
34 #include "py/objint.h"
35 #include "py/objstr.h"
36 #include "py/runtime.h"
37 #include "py/stackctrl.h"
38 #include "py/stream.h" // for mp_obj_print
39 
mp_obj_get_type(mp_const_obj_t o_in)40 const mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) {
41     #if MICROPY_OBJ_IMMEDIATE_OBJS && MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A
42 
43     if (mp_obj_is_obj(o_in)) {
44         const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in);
45         return o->type;
46     } else {
47         static const mp_obj_type_t *const types[] = {
48             NULL, &mp_type_int, &mp_type_str, &mp_type_int,
49             NULL, &mp_type_int, &mp_type_NoneType, &mp_type_int,
50             NULL, &mp_type_int, &mp_type_str, &mp_type_int,
51             NULL, &mp_type_int, &mp_type_bool, &mp_type_int,
52         };
53         return types[(uintptr_t)o_in & 0xf];
54     }
55 
56     #elif MICROPY_OBJ_IMMEDIATE_OBJS && MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
57 
58     if (mp_obj_is_small_int(o_in)) {
59         return &mp_type_int;
60     } else if (mp_obj_is_obj(o_in)) {
61         const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in);
62         return o->type;
63     #if MICROPY_PY_BUILTINS_FLOAT
64     } else if ((((mp_uint_t)(o_in)) & 0xff800007) != 0x00000006) {
65         return &mp_type_float;
66     #endif
67     } else {
68         static const mp_obj_type_t *const types[] = {
69             &mp_type_str, &mp_type_NoneType, &mp_type_str, &mp_type_bool,
70         };
71         return types[((uintptr_t)o_in >> 3) & 3];
72     }
73 
74     #else
75 
76     if (mp_obj_is_small_int(o_in)) {
77         return &mp_type_int;
78     } else if (mp_obj_is_qstr(o_in)) {
79         return &mp_type_str;
80         #if MICROPY_PY_BUILTINS_FLOAT && ( \
81             MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D)
82     } else if (mp_obj_is_float(o_in)) {
83         return &mp_type_float;
84         #endif
85     #if MICROPY_OBJ_IMMEDIATE_OBJS
86     } else if (mp_obj_is_immediate_obj(o_in)) {
87         static const mp_obj_type_t *const types[2] = {&mp_type_NoneType, &mp_type_bool};
88         return types[MP_OBJ_IMMEDIATE_OBJ_VALUE(o_in) & 1];
89     #endif
90     } else {
91         const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in);
92         return o->type;
93     }
94 
95     #endif
96 }
97 
mp_obj_get_type_str(mp_const_obj_t o_in)98 const char *mp_obj_get_type_str(mp_const_obj_t o_in) {
99     return qstr_str(mp_obj_get_type(o_in)->name);
100 }
101 
mp_obj_print_helper(const mp_print_t * print,mp_obj_t o_in,mp_print_kind_t kind)102 void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
103     // There can be data structures nested too deep, or just recursive
104     MP_STACK_CHECK();
105     #ifndef NDEBUG
106     if (o_in == MP_OBJ_NULL) {
107         mp_print_str(print, "(nil)");
108         return;
109     }
110     #endif
111     const mp_obj_type_t *type = mp_obj_get_type(o_in);
112     if (type->print != NULL) {
113         type->print((mp_print_t *)print, o_in, kind);
114     } else {
115         mp_printf(print, "<%q>", type->name);
116     }
117 }
118 
mp_obj_print(mp_obj_t o_in,mp_print_kind_t kind)119 void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) {
120     mp_obj_print_helper(MP_PYTHON_PRINTER, o_in, kind);
121 }
122 
123 // helper function to print an exception with traceback
mp_obj_print_exception(const mp_print_t * print,mp_obj_t exc)124 void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc) {
125     if (mp_obj_is_exception_instance(exc)) {
126         size_t n, *values;
127         mp_obj_exception_get_traceback(exc, &n, &values);
128         if (n > 0) {
129             assert(n % 3 == 0);
130             mp_print_str(print, "Traceback (most recent call last):\n");
131             for (int i = n - 3; i >= 0; i -= 3) {
132                 #if MICROPY_ENABLE_SOURCE_LINE
133                 mp_printf(print, "  File \"%q\", line %d", values[i], (int)values[i + 1]);
134                 #else
135                 mp_printf(print, "  File \"%q\"", values[i]);
136                 #endif
137                 // the block name can be NULL if it's unknown
138                 qstr block = values[i + 2];
139                 if (block == MP_QSTRnull) {
140                     mp_print_str(print, "\n");
141                 } else {
142                     mp_printf(print, ", in %q\n", block);
143                 }
144             }
145         }
146     }
147     mp_obj_print_helper(print, exc, PRINT_EXC);
148     mp_print_str(print, "\n");
149 }
150 
mp_obj_is_true(mp_obj_t arg)151 bool mp_obj_is_true(mp_obj_t arg) {
152     if (arg == mp_const_false) {
153         return 0;
154     } else if (arg == mp_const_true) {
155         return 1;
156     } else if (arg == mp_const_none) {
157         return 0;
158     } else if (mp_obj_is_small_int(arg)) {
159         if (arg == MP_OBJ_NEW_SMALL_INT(0)) {
160             return 0;
161         } else {
162             return 1;
163         }
164     } else {
165         const mp_obj_type_t *type = mp_obj_get_type(arg);
166         if (type->unary_op != NULL) {
167             mp_obj_t result = type->unary_op(MP_UNARY_OP_BOOL, arg);
168             if (result != MP_OBJ_NULL) {
169                 return result == mp_const_true;
170             }
171         }
172 
173         mp_obj_t len = mp_obj_len_maybe(arg);
174         if (len != MP_OBJ_NULL) {
175             // obj has a length, truth determined if len != 0
176             return len != MP_OBJ_NEW_SMALL_INT(0);
177         } else {
178             // any other obj is true per Python semantics
179             return 1;
180         }
181     }
182 }
183 
mp_obj_is_callable(mp_obj_t o_in)184 bool mp_obj_is_callable(mp_obj_t o_in) {
185     const mp_call_fun_t call = mp_obj_get_type(o_in)->call;
186     if (call != mp_obj_instance_call) {
187         return call != NULL;
188     }
189     return mp_obj_instance_is_callable(o_in);
190 }
191 
192 // This function implements the '==' and '!=' operators.
193 //
194 // From the Python language reference:
195 // (https://docs.python.org/3/reference/expressions.html#not-in)
196 // "The objects need not have the same type. If both are numbers, they are converted
197 // to a common type. Otherwise, the == and != operators always consider objects of
198 // different types to be unequal."
199 //
200 // This means that False==0 and True==1 are true expressions.
201 //
202 // Furthermore, from the v3.4.2 code for object.c: "Practical amendments: If rich
203 // comparison returns NotImplemented, == and != are decided by comparing the object
204 // pointer."
mp_obj_equal_not_equal(mp_binary_op_t op,mp_obj_t o1,mp_obj_t o2)205 mp_obj_t mp_obj_equal_not_equal(mp_binary_op_t op, mp_obj_t o1, mp_obj_t o2) {
206     mp_obj_t local_true = (op == MP_BINARY_OP_NOT_EQUAL) ? mp_const_false : mp_const_true;
207     mp_obj_t local_false = (op == MP_BINARY_OP_NOT_EQUAL) ? mp_const_true : mp_const_false;
208     int pass_number = 0;
209 
210     // Shortcut for very common cases
211     if (o1 == o2 &&
212         (mp_obj_is_small_int(o1) || !(mp_obj_get_type(o1)->flags & MP_TYPE_FLAG_EQ_NOT_REFLEXIVE))) {
213         return local_true;
214     }
215 
216     // fast path for strings
217     if (mp_obj_is_str(o1)) {
218         if (mp_obj_is_str(o2)) {
219             // both strings, use special function
220             return mp_obj_str_equal(o1, o2) ? local_true : local_false;
221         #if MICROPY_PY_STR_BYTES_CMP_WARN
222         } else if (mp_obj_is_type(o2, &mp_type_bytes)) {
223         str_bytes_cmp:
224             mp_warning(MP_WARN_CAT(BytesWarning), "Comparison between bytes and str");
225             return local_false;
226         #endif
227         } else {
228             goto skip_one_pass;
229         }
230     #if MICROPY_PY_STR_BYTES_CMP_WARN
231     } else if (mp_obj_is_str(o2) && mp_obj_is_type(o1, &mp_type_bytes)) {
232         // o1 is not a string (else caught above), so the objects are not equal
233         goto str_bytes_cmp;
234     #endif
235     }
236 
237     // fast path for small ints
238     if (mp_obj_is_small_int(o1)) {
239         if (mp_obj_is_small_int(o2)) {
240             // both SMALL_INT, and not equal if we get here
241             return local_false;
242         } else {
243             goto skip_one_pass;
244         }
245     }
246 
247     // generic type, call binary_op(MP_BINARY_OP_EQUAL)
248     while (pass_number < 2) {
249         const mp_obj_type_t *type = mp_obj_get_type(o1);
250         // If a full equality test is not needed and the other object is a different
251         // type then we don't need to bother trying the comparison.
252         if (type->binary_op != NULL &&
253             ((type->flags & MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE) || mp_obj_get_type(o2) == type)) {
254             // CPython is asymmetric: it will try __eq__ if there's no __ne__ but not the
255             // other way around.  If the class doesn't need a full test we can skip __ne__.
256             if (op == MP_BINARY_OP_NOT_EQUAL && (type->flags & MP_TYPE_FLAG_EQ_HAS_NEQ_TEST)) {
257                 mp_obj_t r = type->binary_op(MP_BINARY_OP_NOT_EQUAL, o1, o2);
258                 if (r != MP_OBJ_NULL) {
259                     return r;
260                 }
261             }
262 
263             // Try calling __eq__.
264             mp_obj_t r = type->binary_op(MP_BINARY_OP_EQUAL, o1, o2);
265             if (r != MP_OBJ_NULL) {
266                 if (op == MP_BINARY_OP_EQUAL) {
267                     return r;
268                 } else {
269                     return mp_obj_is_true(r) ? local_true : local_false;
270                 }
271             }
272         }
273 
274     skip_one_pass:
275         // Try the other way around if none of the above worked
276         ++pass_number;
277         mp_obj_t temp = o1;
278         o1 = o2;
279         o2 = temp;
280     }
281 
282     // equality not implemented, so fall back to pointer conparison
283     return (o1 == o2) ? local_true : local_false;
284 }
285 
mp_obj_equal(mp_obj_t o1,mp_obj_t o2)286 bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
287     return mp_obj_is_true(mp_obj_equal_not_equal(MP_BINARY_OP_EQUAL, o1, o2));
288 }
289 
mp_obj_get_int(mp_const_obj_t arg)290 mp_int_t mp_obj_get_int(mp_const_obj_t arg) {
291     // This function essentially performs implicit type conversion to int
292     // Note that Python does NOT provide implicit type conversion from
293     // float to int in the core expression language, try some_list[1.0].
294     if (arg == mp_const_false) {
295         return 0;
296     } else if (arg == mp_const_true) {
297         return 1;
298     } else if (mp_obj_is_small_int(arg)) {
299         return MP_OBJ_SMALL_INT_VALUE(arg);
300     } else if (mp_obj_is_type(arg, &mp_type_int)) {
301         return mp_obj_int_get_checked(arg);
302     } else {
303         mp_obj_t res = mp_unary_op(MP_UNARY_OP_INT, (mp_obj_t)arg);
304         return mp_obj_int_get_checked(res);
305     }
306 }
307 
mp_obj_get_int_truncated(mp_const_obj_t arg)308 mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg) {
309     if (mp_obj_is_int(arg)) {
310         return mp_obj_int_get_truncated(arg);
311     } else {
312         return mp_obj_get_int(arg);
313     }
314 }
315 
316 // returns false if arg is not of integral type
317 // returns true and sets *value if it is of integral type
318 // can throw OverflowError if arg is of integral type, but doesn't fit in a mp_int_t
mp_obj_get_int_maybe(mp_const_obj_t arg,mp_int_t * value)319 bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value) {
320     if (arg == mp_const_false) {
321         *value = 0;
322     } else if (arg == mp_const_true) {
323         *value = 1;
324     } else if (mp_obj_is_small_int(arg)) {
325         *value = MP_OBJ_SMALL_INT_VALUE(arg);
326     } else if (mp_obj_is_type(arg, &mp_type_int)) {
327         *value = mp_obj_int_get_checked(arg);
328     } else {
329         return false;
330     }
331     return true;
332 }
333 
334 #if MICROPY_PY_BUILTINS_FLOAT
mp_obj_get_float_maybe(mp_obj_t arg,mp_float_t * value)335 bool mp_obj_get_float_maybe(mp_obj_t arg, mp_float_t *value) {
336     mp_float_t val;
337 
338     if (arg == mp_const_false) {
339         val = 0;
340     } else if (arg == mp_const_true) {
341         val = 1;
342     } else if (mp_obj_is_small_int(arg)) {
343         val = (mp_float_t)MP_OBJ_SMALL_INT_VALUE(arg);
344     #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
345     } else if (mp_obj_is_type(arg, &mp_type_int)) {
346         val = mp_obj_int_as_float_impl(arg);
347     #endif
348     } else if (mp_obj_is_float(arg)) {
349         val = mp_obj_float_get(arg);
350     } else {
351         return false;
352     }
353 
354     *value = val;
355     return true;
356 }
357 
mp_obj_get_float(mp_obj_t arg)358 mp_float_t mp_obj_get_float(mp_obj_t arg) {
359     mp_float_t val;
360 
361     if (!mp_obj_get_float_maybe(arg, &val)) {
362         #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
363         mp_raise_TypeError(MP_ERROR_TEXT("can't convert to float"));
364         #else
365         mp_raise_msg_varg(&mp_type_TypeError,
366             MP_ERROR_TEXT("can't convert %s to float"), mp_obj_get_type_str(arg));
367         #endif
368     }
369 
370     return val;
371 }
372 
373 #if MICROPY_PY_BUILTINS_COMPLEX
mp_obj_get_complex_maybe(mp_obj_t arg,mp_float_t * real,mp_float_t * imag)374 bool mp_obj_get_complex_maybe(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
375     if (arg == mp_const_false) {
376         *real = 0;
377         *imag = 0;
378     } else if (arg == mp_const_true) {
379         *real = 1;
380         *imag = 0;
381     } else if (mp_obj_is_small_int(arg)) {
382         *real = (mp_float_t)MP_OBJ_SMALL_INT_VALUE(arg);
383         *imag = 0;
384     #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
385     } else if (mp_obj_is_type(arg, &mp_type_int)) {
386         *real = mp_obj_int_as_float_impl(arg);
387         *imag = 0;
388     #endif
389     } else if (mp_obj_is_float(arg)) {
390         *real = mp_obj_float_get(arg);
391         *imag = 0;
392     } else if (mp_obj_is_type(arg, &mp_type_complex)) {
393         mp_obj_complex_get(arg, real, imag);
394     } else {
395         return false;
396     }
397     return true;
398 }
399 
mp_obj_get_complex(mp_obj_t arg,mp_float_t * real,mp_float_t * imag)400 void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
401     if (!mp_obj_get_complex_maybe(arg, real, imag)) {
402         #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
403         mp_raise_TypeError(MP_ERROR_TEXT("can't convert to complex"));
404         #else
405         mp_raise_msg_varg(&mp_type_TypeError,
406             MP_ERROR_TEXT("can't convert %s to complex"), mp_obj_get_type_str(arg));
407         #endif
408     }
409 }
410 #endif
411 #endif
412 
413 // note: returned value in *items may point to the interior of a GC block
mp_obj_get_array(mp_obj_t o,size_t * len,mp_obj_t ** items)414 void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items) {
415     if (mp_obj_is_type(o, &mp_type_tuple)) {
416         mp_obj_tuple_get(o, len, items);
417     } else if (mp_obj_is_type(o, &mp_type_list)) {
418         mp_obj_list_get(o, len, items);
419     } else {
420         #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
421         mp_raise_TypeError(MP_ERROR_TEXT("expected tuple/list"));
422         #else
423         mp_raise_msg_varg(&mp_type_TypeError,
424             MP_ERROR_TEXT("object '%s' isn't a tuple or list"), mp_obj_get_type_str(o));
425         #endif
426     }
427 }
428 
429 // note: returned value in *items may point to the interior of a GC block
mp_obj_get_array_fixed_n(mp_obj_t o,size_t len,mp_obj_t ** items)430 void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items) {
431     size_t seq_len;
432     mp_obj_get_array(o, &seq_len, items);
433     if (seq_len != len) {
434         #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
435         mp_raise_ValueError(MP_ERROR_TEXT("tuple/list has wrong length"));
436         #else
437         mp_raise_msg_varg(&mp_type_ValueError,
438             MP_ERROR_TEXT("requested length %d but object has length %d"), (int)len, (int)seq_len);
439         #endif
440     }
441 }
442 
443 // is_slice determines whether the index is a slice index
mp_get_index(const mp_obj_type_t * type,size_t len,mp_obj_t index,bool is_slice)444 size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool is_slice) {
445     mp_int_t i;
446     if (mp_obj_is_small_int(index)) {
447         i = MP_OBJ_SMALL_INT_VALUE(index);
448     } else if (!mp_obj_get_int_maybe(index, &i)) {
449         #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
450         mp_raise_TypeError(MP_ERROR_TEXT("indices must be integers"));
451         #else
452         mp_raise_msg_varg(&mp_type_TypeError,
453             MP_ERROR_TEXT("%q indices must be integers, not %s"),
454             type->name, mp_obj_get_type_str(index));
455         #endif
456     }
457 
458     if (i < 0) {
459         i += len;
460     }
461     if (is_slice) {
462         if (i < 0) {
463             i = 0;
464         } else if ((mp_uint_t)i > len) {
465             i = len;
466         }
467     } else {
468         if (i < 0 || (mp_uint_t)i >= len) {
469             #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
470             mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("index out of range"));
471             #else
472             mp_raise_msg_varg(&mp_type_IndexError, MP_ERROR_TEXT("%q index out of range"), type->name);
473             #endif
474         }
475     }
476 
477     // By this point 0 <= i <= len and so fits in a size_t
478     return (size_t)i;
479 }
480 
mp_obj_id(mp_obj_t o_in)481 mp_obj_t mp_obj_id(mp_obj_t o_in) {
482     mp_int_t id = (mp_int_t)o_in;
483     if (!mp_obj_is_obj(o_in)) {
484         return mp_obj_new_int(id);
485     } else if (id >= 0) {
486         // Many OSes and CPUs have affinity for putting "user" memories
487         // into low half of address space, and "system" into upper half.
488         // We're going to take advantage of that and return small int
489         // (signed) for such "user" addresses.
490         return MP_OBJ_NEW_SMALL_INT(id);
491     } else {
492         // If that didn't work, well, let's return long int, just as
493         // a (big) positive value, so it will never clash with the range
494         // of small int returned in previous case.
495         return mp_obj_new_int_from_uint((mp_uint_t)id);
496     }
497 }
498 
499 // will raise a TypeError if object has no length
mp_obj_len(mp_obj_t o_in)500 mp_obj_t mp_obj_len(mp_obj_t o_in) {
501     mp_obj_t len = mp_obj_len_maybe(o_in);
502     if (len == MP_OBJ_NULL) {
503         #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
504         mp_raise_TypeError(MP_ERROR_TEXT("object has no len"));
505         #else
506         mp_raise_msg_varg(&mp_type_TypeError,
507             MP_ERROR_TEXT("object of type '%s' has no len()"), mp_obj_get_type_str(o_in));
508         #endif
509     } else {
510         return len;
511     }
512 }
513 
514 // may return MP_OBJ_NULL
mp_obj_len_maybe(mp_obj_t o_in)515 mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) {
516     if (
517         #if !MICROPY_PY_BUILTINS_STR_UNICODE
518         // It's simple - unicode is slow, non-unicode is fast
519         mp_obj_is_str(o_in) ||
520         #endif
521         mp_obj_is_type(o_in, &mp_type_bytes)) {
522         GET_STR_LEN(o_in, l);
523         return MP_OBJ_NEW_SMALL_INT(l);
524     } else {
525         const mp_obj_type_t *type = mp_obj_get_type(o_in);
526         if (type->unary_op != NULL) {
527             return type->unary_op(MP_UNARY_OP_LEN, o_in);
528         } else {
529             return MP_OBJ_NULL;
530         }
531     }
532 }
533 
mp_obj_subscr(mp_obj_t base,mp_obj_t index,mp_obj_t value)534 mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {
535     const mp_obj_type_t *type = mp_obj_get_type(base);
536     if (type->subscr != NULL) {
537         mp_obj_t ret = type->subscr(base, index, value);
538         if (ret != MP_OBJ_NULL) {
539             return ret;
540         }
541         // TODO: call base classes here?
542     }
543     if (value == MP_OBJ_NULL) {
544         #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
545         mp_raise_TypeError(MP_ERROR_TEXT("object doesn't support item deletion"));
546         #else
547         mp_raise_msg_varg(&mp_type_TypeError,
548             MP_ERROR_TEXT("'%s' object doesn't support item deletion"), mp_obj_get_type_str(base));
549         #endif
550     } else if (value == MP_OBJ_SENTINEL) {
551         #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
552         mp_raise_TypeError(MP_ERROR_TEXT("object isn't subscriptable"));
553         #else
554         mp_raise_msg_varg(&mp_type_TypeError,
555             MP_ERROR_TEXT("'%s' object isn't subscriptable"), mp_obj_get_type_str(base));
556         #endif
557     } else {
558         #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
559         mp_raise_TypeError(MP_ERROR_TEXT("object doesn't support item assignment"));
560         #else
561         mp_raise_msg_varg(&mp_type_TypeError,
562             MP_ERROR_TEXT("'%s' object doesn't support item assignment"), mp_obj_get_type_str(base));
563         #endif
564     }
565 }
566 
567 // Return input argument. Useful as .getiter for objects which are
568 // their own iterators, etc.
mp_identity(mp_obj_t self)569 mp_obj_t mp_identity(mp_obj_t self) {
570     return self;
571 }
572 MP_DEFINE_CONST_FUN_OBJ_1(mp_identity_obj, mp_identity);
573 
mp_identity_getiter(mp_obj_t self,mp_obj_iter_buf_t * iter_buf)574 mp_obj_t mp_identity_getiter(mp_obj_t self, mp_obj_iter_buf_t *iter_buf) {
575     (void)iter_buf;
576     return self;
577 }
578 
mp_get_buffer(mp_obj_t obj,mp_buffer_info_t * bufinfo,mp_uint_t flags)579 bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
580     const mp_obj_type_t *type = mp_obj_get_type(obj);
581     if (type->buffer_p.get_buffer == NULL) {
582         return false;
583     }
584     int ret = type->buffer_p.get_buffer(obj, bufinfo, flags);
585     if (ret != 0) {
586         return false;
587     }
588     return true;
589 }
590 
mp_get_buffer_raise(mp_obj_t obj,mp_buffer_info_t * bufinfo,mp_uint_t flags)591 void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
592     if (!mp_get_buffer(obj, bufinfo, flags)) {
593         mp_raise_TypeError(MP_ERROR_TEXT("object with buffer protocol required"));
594     }
595 }
596 
mp_generic_unary_op(mp_unary_op_t op,mp_obj_t o_in)597 mp_obj_t mp_generic_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
598     switch (op) {
599         case MP_UNARY_OP_HASH:
600             return MP_OBJ_NEW_SMALL_INT((mp_uint_t)o_in);
601         default:
602             return MP_OBJ_NULL;      // op not supported
603     }
604 }
605