obj.c 11.9 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
103
104
105
106
// returns true if o_in is bool, small int, or long int
bool mp_obj_is_integer(mp_obj_t o_in) {
    return MP_OBJ_IS_INT(o_in) || MP_OBJ_IS_TYPE(o_in, &mp_type_bool);
}

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

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

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

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

// 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
143
bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
144
145
    if (o1 == o2) {
        return true;
146
147
    } else if (o1 == mp_const_none || o2 == mp_const_none) {
        return false;
148
149
    } else if (MP_OBJ_IS_SMALL_INT(o1) || MP_OBJ_IS_SMALL_INT(o2)) {
        if (MP_OBJ_IS_SMALL_INT(o1) && MP_OBJ_IS_SMALL_INT(o2)) {
150
151
            return false;
        } else {
152
153
            if (MP_OBJ_IS_SMALL_INT(o2)) {
                mp_obj_t temp = o1; o1 = o2; o2 = temp;
154
155
            }
            // o1 is the SMALL_INT, o2 is not
156
157
            mp_small_int_t val = MP_OBJ_SMALL_INT_VALUE(o1);
            if (o2 == mp_const_false) {
158
                return val == 0;
159
            } else if (o2 == mp_const_true) {
160
                return val == 1;
161
            } else if (MP_OBJ_IS_TYPE(o2, &mp_type_int)) {
162
163
164
                // If o2 is long int, dispatch to its virtual methods
                mp_obj_base_t *o = o2;
                if (o->type->binary_op != NULL) {
Damien George's avatar
Damien George committed
165
                    mp_obj_t r = o->type->binary_op(MP_BINARY_OP_EQUAL, o2, o1);
166
167
                    return r == mp_const_true ? true : false;
                }
168
            }
169
            return false;
170
        }
171
172
    } else if (MP_OBJ_IS_STR(o1) && MP_OBJ_IS_STR(o2)) {
        return mp_obj_str_equal(o1, o2);
173
    } else {
174
175
        mp_obj_base_t *o = o1;
        if (o->type->binary_op != NULL) {
Damien George's avatar
Damien George committed
176
            mp_obj_t r = o->type->binary_op(MP_BINARY_OP_EQUAL, o1, o2);
177
178
179
180
            if (r != MP_OBJ_NULL) {
                return r == mp_const_true ? true : false;
            }
        }
181

182
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_NotImplementedError,
183
            "Equality for '%s' and '%s' types not yet implemented", mp_obj_get_type_str(o1), mp_obj_get_type_str(o2)));
184
185
186
187
        return false;
    }
}

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

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

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

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

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

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

290
291
292
// 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) {
    int i;
293
294
    if (MP_OBJ_IS_INT(index)) {
        i = mp_obj_int_get_checked(index);
295
    } else if (MP_OBJ_IS_TYPE(index, &mp_type_bool)) {
xbe's avatar
xbe committed
296
        i = (index == mp_const_true ? 1 : 0);
297
    } else {
298
        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)));
299
    }
300
301

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

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

// 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;
}
337
MP_DEFINE_CONST_FUN_OBJ_1(mp_identity_obj, mp_identity);
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355

bool mp_get_buffer(mp_obj_t obj, buffer_info_t *bufinfo) {
    mp_obj_base_t *o = (mp_obj_base_t *)obj;
    if (o->type->buffer_p.get_buffer == NULL) {
        return false;
    }
    o->type->buffer_p.get_buffer(o, bufinfo, BUFFER_READ);
    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"));
    }
}