obj.c 11.5 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, in %s\n", qstr_str(values[i]), (int)values[i + 1], qstr_str(values[i + 2]));
59
60
61
#else
                printf("  File \"%s\", in %s\n", qstr_str(values[i]), qstr_str(values[i + 2]));
#endif
62
63
64
            }
        }
    }
65
    mp_obj_print(exc, PRINT_EXC);
66
67
68
    printf("\n");
}

Damien George's avatar
Damien George committed
69
70
71
72
73
74
75
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
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;
        }
    }
}

102
bool mp_obj_is_callable(mp_obj_t o_in) {
103
    return mp_obj_get_type(o_in)->call != NULL;
104
105
}

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

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

127
    } else {
128
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unhashable type: '%s'", mp_obj_get_type_str(o_in)));
129
130
131
132
133
134
135
136
137
    }
}

// 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
138
bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
139
140
    if (o1 == o2) {
        return true;
141
142
    }
    if (o1 == mp_const_none || o2 == mp_const_none) {
143
        return false;
144
145
146
147
148
149
    }

    // 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
150
151
            return false;
        } else {
152
153
            mp_obj_t temp = o2; o2 = o1; o1 = temp;
            // o2 is now the SMALL_INT, o1 is not
154
            // fall through to generic op
155
        }
156
157
158
159
160
161
162
163
164
165
166
167
168
169
    }

    // 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;
170
    }
171

172
173
174
175
176
177
178
    // 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;
        }
179
    }
180
181
182
183

    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;
184
185
}

186
machine_int_t mp_obj_get_int(mp_obj_t arg) {
187
188
189
    // 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].
190
    if (arg == mp_const_false) {
191
        return 0;
192
    } else if (arg == mp_const_true) {
193
        return 1;
194
195
    } else if (MP_OBJ_IS_SMALL_INT(arg)) {
        return MP_OBJ_SMALL_INT_VALUE(arg);
196
    } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) {
197
        return mp_obj_int_get_checked(arg);
198
    } else {
199
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg)));
200
201
202
    }
}

203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
// 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;
}

221
#if MICROPY_ENABLE_FLOAT
222
mp_float_t mp_obj_get_float(mp_obj_t arg) {
223
    if (arg == mp_const_false) {
224
        return 0;
225
    } else if (arg == mp_const_true) {
226
        return 1;
227
228
    } else if (MP_OBJ_IS_SMALL_INT(arg)) {
        return MP_OBJ_SMALL_INT_VALUE(arg);
229
    } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) {
230
        return mp_obj_int_as_float(arg);
231
    } else if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) {
232
        return mp_obj_float_get(arg);
233
    } else {
234
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to float", mp_obj_get_type_str(arg)));
235
236
237
    }
}

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

262
void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items) {
263
    if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) {
264
        mp_obj_tuple_get(o, len, items);
265
    } else if (MP_OBJ_IS_TYPE(o, &mp_type_list)) {
266
267
        mp_obj_list_get(o, len, items);
    } else {
268
        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)));
269
270
271
272
    }
}

void mp_obj_get_array_fixed_n(mp_obj_t o, uint len, mp_obj_t **items) {
273
    if (MP_OBJ_IS_TYPE(o, &mp_type_tuple) || MP_OBJ_IS_TYPE(o, &mp_type_list)) {
274
        uint seq_len;
275
        if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) {
276
            mp_obj_tuple_get(o, &seq_len, items);
277
        } else {
278
            mp_obj_list_get(o, &seq_len, items);
279
        }
280
        if (seq_len != len) {
281
            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "requested length %d but object has length %d", len, seq_len));
282
283
        }
    } else {
284
        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)));
285
286
287
    }
}

288
289
// 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) {
290
291
292
293
    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)) {
294
        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)));
295
    }
296
297

    if (i < 0) {
xbe's avatar
xbe committed
298
        i += len;
299
300
    }
    if (is_slice) {
xbe's avatar
xbe committed
301
302
303
304
305
        if (i < 0) {
            i = 0;
        } else if (i > len) {
            i = len;
        }
306
    } else {
xbe's avatar
xbe committed
307
        if (i < 0 || i >= len) {
308
            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
309
        }
310
311
    }
    return i;
312
}
313

314
// may return MP_OBJ_NULL
315
mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) {
316
    if (MP_OBJ_IS_STR(o_in)) {
317
        return MP_OBJ_NEW_SMALL_INT((machine_int_t)mp_obj_str_get_len(o_in));
318
    } else {
319
320
        mp_obj_type_t *type = mp_obj_get_type(o_in);
        if (type->unary_op != NULL) {
Damien George's avatar
Damien George committed
321
            return type->unary_op(MP_UNARY_OP_LEN, o_in);
322
323
        } else {
            return MP_OBJ_NULL;
324
        }
325
326
    }
}
327
328
329
330
331
332

// 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;
}
333
MP_DEFINE_CONST_FUN_OBJ_1(mp_identity_obj, mp_identity);
334
335

bool mp_get_buffer(mp_obj_t obj, buffer_info_t *bufinfo) {
336
337
    mp_obj_type_t *type = mp_obj_get_type(obj);
    if (type->buffer_p.get_buffer == NULL) {
338
339
        return false;
    }
340
    type->buffer_p.get_buffer(obj, bufinfo, BUFFER_READ);
341
342
343
344
345
346
347
348
349
350
351
    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"));
    }
}