obj.c 12.6 KB
Newer Older
1
2
3
4
5
6
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>

#include "nlr.h"
#include "misc.h"
7
#include "mpconfig.h"
8
#include "qstr.h"
9
10
#include "obj.h"
#include "runtime0.h"
11
12
#include "runtime.h"

13
mp_obj_type_t *mp_obj_get_type(mp_obj_t o_in) {
Damien George's avatar
Damien George committed
14
    if (MP_OBJ_IS_SMALL_INT(o_in)) {
15
        return (mp_obj_t)&mp_type_int;
16
    } else if (MP_OBJ_IS_QSTR(o_in)) {
17
        return (mp_obj_t)&mp_type_str;
Damien George's avatar
Damien George committed
18
19
20
21
22
23
    } else {
        mp_obj_base_t *o = o_in;
        return (mp_obj_t)o->type;
    }
}

24
const char *mp_obj_get_type_str(mp_obj_t o_in) {
25
    return qstr_str(mp_obj_get_type(o_in)->name);
26
27
28
29
30
31
32
33
34
}

void printf_wrapper(void *env, const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    vprintf(fmt, args);
    va_end(args);
}

35
void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
36
37
38
    mp_obj_type_t *type = mp_obj_get_type(o_in);
    if (type->print != NULL) {
        type->print(print, env, o_in, kind);
39
    } else {
40
        print(env, "<%s>", qstr_str(type->name));
41
42
43
    }
}

44
45
void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) {
    mp_obj_print_helper(printf_wrapper, NULL, o_in, kind);
46
47
}

48
49
// helper function to print an exception with traceback
void mp_obj_print_exception(mp_obj_t exc) {
50
    if (mp_obj_is_exception_instance(exc)) {
51
52
53
        machine_uint_t n, *values;
        mp_obj_exception_get_traceback(exc, &n, &values);
        if (n > 0) {
54
            assert(n % 3 == 0);
55
56
            printf("Traceback (most recent call last):\n");
            for (int i = n - 3; i >= 0; i -= 3) {
57
#if MICROPY_ENABLE_SOURCE_LINE
58
                printf("  File \"%s\", line %d", qstr_str(values[i]), (int)values[i + 1]);
59
#else
60
                printf("  File \"%s\"", qstr_str(values[i]));
61
#endif
62
63
64
65
66
67
68
                // the block name can be NULL if it's unknown
                qstr block = values[i + 2];
                if (block == MP_QSTR_NULL) {
                    printf("\n");
                } else {
                    printf(", in %s\n", qstr_str(block));
                }
69
70
71
            }
        }
    }
72
    mp_obj_print(exc, PRINT_EXC);
73
74
75
    printf("\n");
}

Damien George's avatar
Damien George committed
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
int mp_obj_is_true(mp_obj_t arg) {
    if (arg == mp_const_false) {
        return 0;
    } else if (arg == mp_const_true) {
        return 1;
    } else if (arg == mp_const_none) {
        return 0;
    } else if (MP_OBJ_IS_SMALL_INT(arg)) {
        if (MP_OBJ_SMALL_INT_VALUE(arg) == 0) {
            return 0;
        } else {
            return 1;
        }
    } else {
        mp_obj_type_t *type = mp_obj_get_type(arg);
        if (type->unary_op != NULL) {
            mp_obj_t result = type->unary_op(MP_UNARY_OP_BOOL, arg);
            if (result != MP_OBJ_NULL) {
                return result == mp_const_true;
            }
        }

        mp_obj_t len = mp_obj_len_maybe(arg);
        if (len != MP_OBJ_NULL) {
            // obj has a length, truth determined if len != 0
            return len != MP_OBJ_NEW_SMALL_INT(0);
        } else {
            // any other obj is true per Python semantics
            return 1;
        }
    }
}

109
bool mp_obj_is_callable(mp_obj_t o_in) {
110
    return mp_obj_get_type(o_in)->call != NULL;
111
112
}

113
114
machine_int_t mp_obj_hash(mp_obj_t o_in) {
    if (o_in == mp_const_false) {
115
        return 0; // needs to hash to same as the integer 0, since False==0
116
    } else if (o_in == mp_const_true) {
117
        return 1; // needs to hash to same as the integer 1, since True==1
118
119
    } else if (MP_OBJ_IS_SMALL_INT(o_in)) {
        return MP_OBJ_SMALL_INT_VALUE(o_in);
120
    } else if (MP_OBJ_IS_STR(o_in) || MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) {
121
        return mp_obj_str_get_hash(o_in);
122
    } else if (MP_OBJ_IS_TYPE(o_in, &mp_type_NoneType)) {
123
        return (machine_int_t)o_in;
124
    } else if (MP_OBJ_IS_TYPE(o_in, &mp_type_fun_native) || MP_OBJ_IS_TYPE(o_in, &mp_type_fun_bc)) {
125
        return (machine_int_t)o_in;
126
    } else if (MP_OBJ_IS_TYPE(o_in, &mp_type_tuple)) {
127
        return mp_obj_tuple_hash(o_in);
128
129
    } else if (MP_OBJ_IS_TYPE(o_in, &mp_type_type)) {
        return (machine_int_t)o_in;
130
131
132
133

    // TODO hash class and instances
    // TODO delegate to __hash__ method if it exists

134
    } else {
135
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unhashable type: '%s'", mp_obj_get_type_str(o_in)));
136
137
138
139
140
141
142
143
144
    }
}

// this function implements the '==' operator (and so the inverse of '!=')
// from the python language reference:
// "The objects need not have the same type. If both are numbers, they are converted
// to a common type. Otherwise, the == and != operators always consider objects of
// different types to be unequal."
// note also that False==0 and True==1 are true expressions
145
bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
146
147
    if (o1 == o2) {
        return true;
148
149
    }
    if (o1 == mp_const_none || o2 == mp_const_none) {
150
        return false;
151
152
153
154
155
156
    }

    // fast path for small ints
    if (MP_OBJ_IS_SMALL_INT(o1)) {
        if (MP_OBJ_IS_SMALL_INT(o2)) {
            // both SMALL_INT, and not equal if we get here
157
158
            return false;
        } else {
159
160
            mp_obj_t temp = o2; o2 = o1; o1 = temp;
            // o2 is now the SMALL_INT, o1 is not
161
            // fall through to generic op
162
        }
163
164
165
166
167
168
169
170
171
172
173
174
175
176
    }

    // fast path for strings
    if (MP_OBJ_IS_STR(o1)) {
        if (MP_OBJ_IS_STR(o2)) {
            // both strings, use special function
            return mp_obj_str_equal(o1, o2);
        } else {
            // a string is never equal to anything else
            return false;
        }
    } else if (MP_OBJ_IS_STR(o2)) {
        // o1 is not a string (else caught above), so the objects are not equal
        return false;
177
    }
178

179
180
181
182
183
184
185
    // generic type, call binary_op(MP_BINARY_OP_EQUAL)
    mp_obj_type_t *type = mp_obj_get_type(o1);
    if (type->binary_op != NULL) {
        mp_obj_t r = type->binary_op(MP_BINARY_OP_EQUAL, o1, o2);
        if (r != MP_OBJ_NULL) {
            return r == mp_const_true ? true : false;
        }
186
    }
187
188
189
190

    nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_NotImplementedError,
        "Equality for '%s' and '%s' types not yet implemented", mp_obj_get_type_str(o1), mp_obj_get_type_str(o2)));
    return false;
191
192
}

193
machine_int_t mp_obj_get_int(mp_obj_t arg) {
194
195
196
    // This function essentially performs implicit type conversion to int
    // Note that Python does NOT provide implicit type conversion from
    // float to int in the core expression language, try some_list[1.0].
197
    if (arg == mp_const_false) {
198
        return 0;
199
    } else if (arg == mp_const_true) {
200
        return 1;
201
202
    } else if (MP_OBJ_IS_SMALL_INT(arg)) {
        return MP_OBJ_SMALL_INT_VALUE(arg);
203
    } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) {
204
        return mp_obj_int_get_checked(arg);
205
    } else {
206
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg)));
207
208
209
    }
}

210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
// returns false if arg is not of integral type
// returns true and sets *value if it is of integral type
// can throw OverflowError if arg is of integral type, but doesn't fit in a machine_int_t
bool mp_obj_get_int_maybe(mp_obj_t arg, machine_int_t *value) {
    if (arg == mp_const_false) {
        *value = 0;
    } else if (arg == mp_const_true) {
        *value = 1;
    } else if (MP_OBJ_IS_SMALL_INT(arg)) {
        *value = MP_OBJ_SMALL_INT_VALUE(arg);
    } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) {
        *value = mp_obj_int_get_checked(arg);
    } else {
        return false;
    }
    return true;
}

228
#if MICROPY_ENABLE_FLOAT
229
mp_float_t mp_obj_get_float(mp_obj_t arg) {
230
    if (arg == mp_const_false) {
231
        return 0;
232
    } else if (arg == mp_const_true) {
233
        return 1;
234
235
    } else if (MP_OBJ_IS_SMALL_INT(arg)) {
        return MP_OBJ_SMALL_INT_VALUE(arg);
236
    } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) {
237
        return mp_obj_int_as_float(arg);
238
    } else if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) {
239
        return mp_obj_float_get(arg);
240
    } else {
241
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to float", mp_obj_get_type_str(arg)));
242
243
244
    }
}

245
246
void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
    if (arg == mp_const_false) {
247
248
        *real = 0;
        *imag = 0;
249
    } else if (arg == mp_const_true) {
250
251
        *real = 1;
        *imag = 0;
252
253
    } else if (MP_OBJ_IS_SMALL_INT(arg)) {
        *real = MP_OBJ_SMALL_INT_VALUE(arg);
254
        *imag = 0;
255
256
257
    } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) {
        *real = mp_obj_int_as_float(arg);
        *imag = 0;
258
    } else if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) {
259
        *real = mp_obj_float_get(arg);
260
        *imag = 0;
261
    } else if (MP_OBJ_IS_TYPE(arg, &mp_type_complex)) {
262
        mp_obj_complex_get(arg, real, imag);
263
    } else {
264
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to complex", mp_obj_get_type_str(arg)));
265
266
267
268
    }
}
#endif

269
void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items) {
270
    if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) {
271
        mp_obj_tuple_get(o, len, items);
272
    } else if (MP_OBJ_IS_TYPE(o, &mp_type_list)) {
273
274
        mp_obj_list_get(o, len, items);
    } else {
275
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o)));
276
277
278
279
    }
}

void mp_obj_get_array_fixed_n(mp_obj_t o, uint len, mp_obj_t **items) {
280
    if (MP_OBJ_IS_TYPE(o, &mp_type_tuple) || MP_OBJ_IS_TYPE(o, &mp_type_list)) {
281
        uint seq_len;
282
        if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) {
283
            mp_obj_tuple_get(o, &seq_len, items);
284
        } else {
285
            mp_obj_list_get(o, &seq_len, items);
286
        }
287
        if (seq_len != len) {
288
            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "requested length %d but object has length %d", len, seq_len));
289
290
        }
    } else {
291
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o)));
292
293
294
    }
}

295
296
// is_slice determines whether the index is a slice index
uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index, bool is_slice) {
297
298
299
300
    machine_int_t i;
    if (MP_OBJ_IS_SMALL_INT(index)) {
        i = MP_OBJ_SMALL_INT_VALUE(index);
    } else if (!mp_obj_get_int_maybe(index, &i)) {
301
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%s indices must be integers, not %s", qstr_str(type->name), mp_obj_get_type_str(index)));
302
    }
303
304

    if (i < 0) {
xbe's avatar
xbe committed
305
        i += len;
306
307
    }
    if (is_slice) {
xbe's avatar
xbe committed
308
309
310
311
312
        if (i < 0) {
            i = 0;
        } else if (i > len) {
            i = len;
        }
313
    } else {
xbe's avatar
xbe committed
314
        if (i < 0 || i >= len) {
315
            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "%s index out of range", qstr_str(type->name)));
xbe's avatar
xbe committed
316
        }
317
318
    }
    return i;
319
}
320

321
// may return MP_OBJ_NULL
322
mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) {
Damien George's avatar
Damien George committed
323
    if (MP_OBJ_IS_STR(o_in) || MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) {
324
        return MP_OBJ_NEW_SMALL_INT((machine_int_t)mp_obj_str_get_len(o_in));
325
    } else {
326
327
        mp_obj_type_t *type = mp_obj_get_type(o_in);
        if (type->unary_op != NULL) {
Damien George's avatar
Damien George committed
328
            return type->unary_op(MP_UNARY_OP_LEN, o_in);
329
330
        } else {
            return MP_OBJ_NULL;
331
        }
332
333
    }
}
334

335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {
    mp_obj_type_t *type = mp_obj_get_type(base);
    if (type->subscr != NULL) {
        mp_obj_t ret = type->subscr(base, index, value);
        if (ret != MP_OBJ_NOT_SUPPORTED) {
            return ret;
        }
        // TODO: call base classes here?
    }
    if (value == MP_OBJ_NULL) {
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object does not support item deletion", mp_obj_get_type_str(base)));
    } else if (value == MP_OBJ_SENTINEL) {
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not subscriptable", mp_obj_get_type_str(base)));
    } else {
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object does not support item assignment", mp_obj_get_type_str(base)));
    }
}

353
354
355
356
357
// Return input argument. Useful as .getiter for objects which are
// their own iterators, etc.
mp_obj_t mp_identity(mp_obj_t self) {
    return self;
}
358
MP_DEFINE_CONST_FUN_OBJ_1(mp_identity_obj, mp_identity);
359
360

bool mp_get_buffer(mp_obj_t obj, buffer_info_t *bufinfo) {
361
362
    mp_obj_type_t *type = mp_obj_get_type(obj);
    if (type->buffer_p.get_buffer == NULL) {
363
364
        return false;
    }
365
    type->buffer_p.get_buffer(obj, bufinfo, BUFFER_READ);
366
367
368
369
370
371
372
373
374
375
376
    if (bufinfo->buf == NULL) {
        return false;
    }
    return true;
}

void mp_get_buffer_raise(mp_obj_t obj, buffer_info_t *bufinfo) {
    if (!mp_get_buffer(obj, bufinfo)) {
        nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "Object with buffer protocol required"));
    }
}