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

177
        nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_NotImplementedError,
178
            "Equality for '%s' and '%s' types not yet implemented", mp_obj_get_type_str(o1), mp_obj_get_type_str(o2)));
179
180
181
182
        return false;
    }
}

183
184
machine_int_t mp_obj_get_int(mp_obj_t arg) {
    if (arg == mp_const_false) {
185
        return 0;
186
    } else if (arg == mp_const_true) {
187
        return 1;
188
189
    } else if (MP_OBJ_IS_SMALL_INT(arg)) {
        return MP_OBJ_SMALL_INT_VALUE(arg);
190
    } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) {
191
        return mp_obj_int_get_checked(arg);
192
    } else {
193
        nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg)));
194
195
196
    }
}

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
// 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;
}

215
#if MICROPY_ENABLE_FLOAT
216
mp_float_t mp_obj_get_float(mp_obj_t arg) {
217
    if (arg == mp_const_false) {
218
        return 0;
219
    } else if (arg == mp_const_true) {
220
        return 1;
221
222
    } else if (MP_OBJ_IS_SMALL_INT(arg)) {
        return MP_OBJ_SMALL_INT_VALUE(arg);
223
    } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) {
224
        return mp_obj_int_as_float(arg);
225
    } else if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) {
226
        return mp_obj_float_get(arg);
227
    } else {
228
        nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to float", mp_obj_get_type_str(arg)));
229
230
231
    }
}

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

256
void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items) {
257
    if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) {
258
        mp_obj_tuple_get(o, len, items);
259
    } else if (MP_OBJ_IS_TYPE(o, &mp_type_list)) {
260
261
262
263
264
265
266
        mp_obj_list_get(o, len, items);
    } else {
        nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o)));
    }
}

void mp_obj_get_array_fixed_n(mp_obj_t o, uint len, mp_obj_t **items) {
267
    if (MP_OBJ_IS_TYPE(o, &mp_type_tuple) || MP_OBJ_IS_TYPE(o, &mp_type_list)) {
268
        uint seq_len;
269
        if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) {
270
            mp_obj_tuple_get(o, &seq_len, items);
271
        } else {
272
            mp_obj_list_get(o, &seq_len, items);
273
        }
274
275
        if (seq_len != len) {
            nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "requested length %d but object has length %d", len, seq_len));
276
277
        }
    } else {
278
        nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o)));
279
280
281
    }
}

282
283
284
// 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;
285
    if (MP_OBJ_IS_SMALL_INT(index)) {
286
        i = MP_OBJ_SMALL_INT_VALUE(index);
287
    } else if (MP_OBJ_IS_TYPE(index, &mp_type_bool)) {
xbe's avatar
xbe committed
288
        i = (index == mp_const_true ? 1 : 0);
289
    } else {
290
        nlr_jump(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)));
291
    }
292
293

    if (i < 0) {
xbe's avatar
xbe committed
294
        i += len;
295
296
    }
    if (is_slice) {
xbe's avatar
xbe committed
297
298
299
300
301
        if (i < 0) {
            i = 0;
        } else if (i > len) {
            i = len;
        }
302
    } else {
xbe's avatar
xbe committed
303
304
305
        if (i < 0 || i >= len) {
            nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "%s index out of range", qstr_str(type->name)));
        }
306
307
    }
    return i;
308
}
309

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

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