builtin.c 10.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <assert.h>

#include "nlr.h"
#include "misc.h"
10
#include "mpconfig.h"
11
#include "mpqstr.h"
12
13
#include "obj.h"
#include "runtime0.h"
14
15
16
17
#include "runtime.h"
#include "map.h"
#include "builtin.h"

Damien George's avatar
Damien George committed
18
19
20
21
22
23
// args[0] is function from class body
// args[1] is class name
// args[2:] are base objects
mp_obj_t mp_builtin___build_class__(int n_args, const mp_obj_t *args) {
    assert(2 <= n_args);

24
    // we differ from CPython: we set the new __locals__ object here
25
    mp_map_t *old_locals = rt_locals_get();
26
    mp_map_t *class_locals = mp_map_new(MP_MAP_QSTR, 0);
27
    rt_locals_set(class_locals);
28
29

    // call the class code
Damien George's avatar
Damien George committed
30
    mp_obj_t cell = rt_call_function_1(args[0], (mp_obj_t)0xdeadbeef);
31
32

    // restore old __locals__ object
33
    rt_locals_set(old_locals);
34

Damien George's avatar
Damien George committed
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
    /*
    // get the class type (meta object) from the base objects
    mp_obj_t meta;
    if (n_args == 2) {
        // no explicit bases, so use 'type'
        meta = (mp_obj_t)&mp_const_type;
    } else {
        // use type of first base object
        meta = mp_obj_get_type(args[2]);
    }
    */

    // TODO do proper metaclass resolution for multiple base objects

    /*
    // create the new class using a call to the meta object
    // (arguments must be backwards in the array)
    mp_obj_t meta_args[3];
    meta_args[2] = args[1]; // class name
    meta_args[1] = mp_obj_new_tuple(n_args - 2, args + 2); // tuple of bases
    meta_args[0] = class_locals; // dict of members TODO, currently is a map
    mp_obj_t new_class = rt_call_function_n(meta, 3, meta_args);
    */
    // create the new class
    mp_obj_t new_class = mp_obj_new_class(class_locals);

    // store into cell if neede
    if (cell != mp_const_none) {
        mp_obj_cell_set(cell, new_class);
    }

    return new_class;
67
68
}

Damien George's avatar
Damien George committed
69
70
MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin___build_class___obj, 2, mp_builtin___build_class__);

71
72
73
mp_obj_t mp_builtin___repl_print__(mp_obj_t o) {
    if (o != mp_const_none) {
        mp_obj_print(o);
74
75
        printf("\n");
    }
76
    return mp_const_none;
77
78
}

79
80
81
mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
    if (MP_OBJ_IS_SMALL_INT(o_in)) {
        mp_small_int_t val = MP_OBJ_SMALL_INT_VALUE(o_in);
82
83
        if (val < 0) {
            val = -val;
84
        }
85
        return MP_OBJ_NEW_SMALL_INT(val);
86
#if MICROPY_ENABLE_FLOAT
87
88
    } else if (MP_OBJ_IS_TYPE(o_in, &float_type)) {
        mp_float_t value = mp_obj_float_get(o_in);
89
        // TODO check for NaN etc
90
91
        if (value < 0) {
            return mp_obj_new_float(-value);
92
        } else {
93
            return o_in;
94
        }
95
96
97
98
    } else if (MP_OBJ_IS_TYPE(o_in, &complex_type)) {
        mp_float_t real, imag;
        mp_obj_complex_get(o_in, &real, &imag);
        return mp_obj_new_float(machine_sqrt(real*real + imag*imag));
99
100
101
#endif
    } else {
        assert(0);
102
        return mp_const_none;
103
104
105
    }
}

106
107
108
109
mp_obj_t mp_builtin_all(mp_obj_t o_in) {
    mp_obj_t iterable = rt_getiter(o_in);
    mp_obj_t item;
    while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
110
        if (!rt_is_true(item)) {
111
            return mp_const_false;
112
113
        }
    }
114
    return mp_const_true;
115
116
}

117
118
119
120
mp_obj_t mp_builtin_any(mp_obj_t o_in) {
    mp_obj_t iterable = rt_getiter(o_in);
    mp_obj_t item;
    while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
121
        if (rt_is_true(item)) {
122
            return mp_const_true;
123
124
        }
    }
125
    return mp_const_false;
126
127
}

128
129
130
mp_obj_t mp_builtin_callable(mp_obj_t o_in) {
    if (mp_obj_is_callable(o_in)) {
        return mp_const_true;
131
    } else {
132
        return mp_const_false;
133
134
135
    }
}

136
137
mp_obj_t mp_builtin_chr(mp_obj_t o_in) {
    int ord = mp_obj_get_int(o_in);
138
139
140
141
    if (0 <= ord && ord <= 0x10ffff) {
        char *str = m_new(char, 2);
        str[0] = ord;
        str[1] = '\0';
142
        return mp_obj_new_str(qstr_from_str_take(str, 2));
143
    } else {
144
        nlr_jump(mp_obj_new_exception_msg(MP_QSTR_ValueError, "chr() arg not in range(0x110000)"));
145
    }
146
147
}

148
149
150
151
152
153
154
mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
    if (MP_OBJ_IS_SMALL_INT(o1_in) && MP_OBJ_IS_SMALL_INT(o2_in)) {
        mp_small_int_t i1 = MP_OBJ_SMALL_INT_VALUE(o1_in);
        mp_small_int_t i2 = MP_OBJ_SMALL_INT_VALUE(o2_in);
        mp_obj_t revs_args[2];
        revs_args[1] = MP_OBJ_NEW_SMALL_INT(i1 / i2);
        revs_args[0] = MP_OBJ_NEW_SMALL_INT(i1 % i2);
155
156
        return rt_build_tuple(2, revs_args);
    } else {
157
        nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError, "unsupported operand type(s) for divmod(): '%s' and '%s'", mp_obj_get_type_str(o1_in), mp_obj_get_type_str(o2_in)));
158
159
160
    }
}

161
static mp_obj_t mp_builtin_hash(mp_obj_t o_in) {
162
    // TODO hash will generally overflow small integer; can we safely truncate it?
163
    return mp_obj_new_int(mp_obj_hash(o_in));
164
165
}

166
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_hash_obj, mp_builtin_hash);
167

168
169
static mp_obj_t mp_builtin_iter(mp_obj_t o_in) {
    return rt_getiter(o_in);
170
171
}

172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_iter_obj, mp_builtin_iter);

mp_obj_t mp_builtin_len(mp_obj_t o_in) {
    mp_small_int_t len = 0;
    if (MP_OBJ_IS_TYPE(o_in, &str_type)) {
        len = strlen(qstr_str(mp_obj_str_get(o_in)));
    } else if (MP_OBJ_IS_TYPE(o_in, &tuple_type)) {
        uint seq_len;
        mp_obj_t *seq_items;
        mp_obj_tuple_get(o_in, &seq_len, &seq_items);
        len = seq_len;
    } else if (MP_OBJ_IS_TYPE(o_in, &list_type)) {
        uint seq_len;
        mp_obj_t *seq_items;
        mp_obj_list_get(o_in, &seq_len, &seq_items);
        len = seq_len;
    } else if (MP_OBJ_IS_TYPE(o_in, &dict_type)) {
189
        len = mp_obj_dict_len(o_in);
190
    } else {
191
        nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in)));
192
    }
193
    return MP_OBJ_NEW_SMALL_INT(len);
194
195
}

196
mp_obj_t mp_builtin_max(int n_args, const mp_obj_t *args) {
197
198
    if (n_args == 1) {
        // given an iterable
199
200
201
202
203
        mp_obj_t iterable = rt_getiter(args[0]);
        mp_obj_t max_obj = NULL;
        mp_obj_t item;
        while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
            if (max_obj == NULL || mp_obj_less(max_obj, item)) {
204
205
                max_obj = item;
            }
206
        }
207
        if (max_obj == NULL) {
208
            nlr_jump(mp_obj_new_exception_msg(MP_QSTR_ValueError, "max() arg is an empty sequence"));
209
210
        }
        return max_obj;
211
    } else {
212
        // given many args
213
        mp_obj_t max_obj = args[0];
214
        for (int i = 1; i < n_args; i++) {
215
            if (mp_obj_less(max_obj, args[i])) {
216
217
218
219
                max_obj = args[i];
            }
        }
        return max_obj;
220
221
222
    }
}

223
mp_obj_t mp_builtin_min(int n_args, const mp_obj_t *args) {
224
225
    if (n_args == 1) {
        // given an iterable
226
227
228
229
230
        mp_obj_t iterable = rt_getiter(args[0]);
        mp_obj_t min_obj = NULL;
        mp_obj_t item;
        while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
            if (min_obj == NULL || mp_obj_less(item, min_obj)) {
231
232
233
234
                min_obj = item;
            }
        }
        if (min_obj == NULL) {
235
            nlr_jump(mp_obj_new_exception_msg(MP_QSTR_ValueError, "min() arg is an empty sequence"));
236
237
238
239
        }
        return min_obj;
    } else {
        // given many args
240
        mp_obj_t min_obj = args[0];
241
        for (int i = 1; i < n_args; i++) {
242
            if (mp_obj_less(args[i], min_obj)) {
243
244
245
246
247
248
                min_obj = args[i];
            }
        }
        return min_obj;
    }
}
249

250
251
252
static mp_obj_t mp_builtin_next(mp_obj_t o) {
    mp_obj_t ret = rt_iternext(o);
    if (ret == mp_const_stop_iteration) {
253
        nlr_jump(mp_obj_new_exception(MP_QSTR_StopIteration));
254
255
256
    } else {
        return ret;
    }
257
258
259
260
261
262
}

MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_next_obj, mp_builtin_next);

mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
    const char *str = qstr_str(mp_obj_get_qstr(o_in));
263
    if (strlen(str) == 1) {
264
        return mp_obj_new_int(str[0]);
265
    } else {
266
        nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "ord() expected a character, but string of length %d found", (void*)(machine_int_t)strlen(str)));
267
268
    }
}
269

270
mp_obj_t mp_builtin_pow(int n_args, const mp_obj_t *args) {
271
272
273
    switch (n_args) {
        case 2: return rt_binary_op(RT_BINARY_OP_POWER, args[0], args[1]);
        case 3: return rt_binary_op(RT_BINARY_OP_MODULO, rt_binary_op(RT_BINARY_OP_POWER, args[0], args[1]), args[2]); // TODO optimise...
274
        default: nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "pow expected at most 3 arguments, got %d", (void*)(machine_int_t)n_args));
275
276
    }
}
277

278
mp_obj_t mp_builtin_print(int n_args, const mp_obj_t *args) {
279
280
281
282
    for (int i = 0; i < n_args; i++) {
        if (i > 0) {
            printf(" ");
        }
283
        if (MP_OBJ_IS_TYPE(args[i], &str_type)) {
284
            // special case, print string raw
285
            printf("%s", qstr_str(mp_obj_str_get(args[i])));
286
287
        } else {
            // print the object Python style
288
            mp_obj_print(args[i]);
289
290
291
        }
    }
    printf("\n");
292
    return mp_const_none;
293
294
}

295
mp_obj_t mp_builtin_range(int n_args, const mp_obj_t *args) {
296
    switch (n_args) {
297
298
299
        case 1: return mp_obj_new_range(0, mp_obj_get_int(args[0]), 1);
        case 2: return mp_obj_new_range(mp_obj_get_int(args[0]), mp_obj_get_int(args[1]), 1);
        case 3: return mp_obj_new_range(mp_obj_get_int(args[0]), mp_obj_get_int(args[1]), mp_obj_get_int(args[2]));
300
        default: nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "range expected at most 3 arguments, got %d", (void*)(machine_int_t)n_args));
301
302
303
304
305
    }
}

mp_obj_t mp_builtin_sum(int n_args, const mp_obj_t *args) {
    mp_obj_t value;
306
    switch (n_args) {
307
        case 1: value = mp_obj_new_int(0); break;
308
        case 2: value = args[1]; break;
309
        default: nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "sum expected at most 2 arguments, got %d", (void*)(machine_int_t)n_args));
310
    }
311
312
313
    mp_obj_t iterable = rt_getiter(args[0]);
    mp_obj_t item;
    while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
314
315
316
317
        value = rt_binary_op(RT_BINARY_OP_ADD, value, item);
    }
    return value;
}
318
319
320

static mp_obj_t mp_builtin_type(mp_obj_t o_in) {
    // TODO implement the 3 argument version of type()
Damien George's avatar
Damien George committed
321
    return mp_obj_get_type(o_in);
322
323
324
}

MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_type_obj, mp_builtin_type);