obj.c 10.7 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
121
122
123
124
        return mp_obj_tuple_hash(o_in);

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

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

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

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

181
182
183
184
bool mp_obj_less(mp_obj_t o1, mp_obj_t o2) {
    if (MP_OBJ_IS_SMALL_INT(o1) && MP_OBJ_IS_SMALL_INT(o2)) {
        mp_small_int_t i1 = MP_OBJ_SMALL_INT_VALUE(o1);
        mp_small_int_t i2 = MP_OBJ_SMALL_INT_VALUE(o2);
185
186
187
188
189
190
191
        return i1 < i2;
    } else {
        assert(0);
        return false;
    }
}

192
193
machine_int_t mp_obj_get_int(mp_obj_t arg) {
    if (arg == mp_const_false) {
194
        return 0;
195
    } else if (arg == mp_const_true) {
196
        return 1;
197
198
    } else if (MP_OBJ_IS_SMALL_INT(arg)) {
        return MP_OBJ_SMALL_INT_VALUE(arg);
199
    } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) {
200
        return mp_obj_int_get_checked(arg);
Dave Hylands's avatar
Dave Hylands committed
201
202
203
204
#if MICROPY_ENABLE_FLOAT
    } else if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) {
        return mp_obj_float_get(arg);
#endif
205
    } else {
206
        nlr_jump(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
    }
}

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

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

251
void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items) {
252
    if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) {
253
        mp_obj_tuple_get(o, len, items);
254
    } else if (MP_OBJ_IS_TYPE(o, &mp_type_list)) {
255
256
257
258
259
260
261
        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) {
262
    if (MP_OBJ_IS_TYPE(o, &mp_type_tuple) || MP_OBJ_IS_TYPE(o, &mp_type_list)) {
263
        uint seq_len;
264
        if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) {
265
            mp_obj_tuple_get(o, &seq_len, items);
266
        } else {
267
            mp_obj_list_get(o, &seq_len, items);
268
        }
269
270
        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));
271
272
        }
    } else {
273
        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)));
274
275
276
    }
}

277
278
279
// 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;
280
    if (MP_OBJ_IS_SMALL_INT(index)) {
281
        i = MP_OBJ_SMALL_INT_VALUE(index);
282
    } else if (MP_OBJ_IS_TYPE(index, &mp_type_bool)) {
xbe's avatar
xbe committed
283
        i = (index == mp_const_true ? 1 : 0);
284
    } else {
285
        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)));
286
    }
287
288

    if (i < 0) {
xbe's avatar
xbe committed
289
        i += len;
290
291
    }
    if (is_slice) {
xbe's avatar
xbe committed
292
293
294
295
296
        if (i < 0) {
            i = 0;
        } else if (i > len) {
            i = len;
        }
297
    } else {
xbe's avatar
xbe committed
298
299
300
        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)));
        }
301
302
    }
    return i;
303
}
304

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

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