builtin.c 10.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <assert.h>

#include "nlr.h"
#include "misc.h"
#include "mpyconfig.h"
#include "runtime.h"
#include "bc.h"

#include "map.h"
#include "obj.h"
#include "objprivate.h"
#include "builtin.h"

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
py_obj_t py_builtin___build_class__(py_obj_t o_class_fun, py_obj_t o_class_name) {
    // we differ from CPython: we set the new __locals__ object here
    py_map_t *old_locals = rt_get_map_locals();
    py_map_t *class_locals = py_map_new(MAP_QSTR, 0);
    rt_set_map_locals(class_locals);

    // call the class code
    rt_call_function_1(o_class_fun, (py_obj_t)0xdeadbeef);

    // restore old __locals__ object
    rt_set_map_locals(old_locals);

    // create and return the new class
    py_obj_base_t *o = m_new(py_obj_base_t, 1);
    o->kind = O_CLASS;
    o->u_class.locals = class_locals;
    return o;
}

py_obj_t py_builtin___import__(int n, py_obj_t *args) {
    printf("import:\n");
    for (int i = 0; i < n; i++) {
    printf("  ");
    py_obj_print(args[i]);
    printf("\n");
    }
    return py_const_none;
}

48
49
50
51
52
53
54
55
py_obj_t py_builtin___repl_print__(py_obj_t o) {
    if (o != py_const_none) {
        py_obj_print(o);
        printf("\n");
    }
    return py_const_none;
}

56
57
58
59
60
py_obj_t py_builtin_abs(py_obj_t o_in) {
    if (IS_SMALL_INT(o_in)) {
        py_small_int_t val = FROM_SMALL_INT(o_in);
        if (val < 0) {
            val = -val;
61
        }
62
63
64
65
66
67
68
        return TO_SMALL_INT(val);
#if MICROPY_ENABLE_FLOAT
    } else if (IS_O(o_in, O_FLOAT)) {
        py_obj_base_t *o = o_in;
        // TODO check for NaN etc
        if (o->u_float < 0) {
            return py_obj_new_float(-o->u_float);
69
        } else {
70
            return o_in;
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
    } else if (IS_O(o_in, O_COMPLEX)) {
        py_obj_base_t *o = o_in;
        return py_obj_new_float(machine_sqrt(o->u_complex.real*o->u_complex.real + o->u_complex.imag*o->u_complex.imag));
#endif
    } else {
        assert(0);
        return py_const_none;
    }
}

py_obj_t py_builtin_all(py_obj_t o_in) {
    py_obj_t iterable = rt_getiter(o_in);
    py_obj_t item;
    while ((item = rt_iternext(iterable)) != py_const_stop_iteration) {
        if (!rt_is_true(item)) {
            return py_const_false;
        }
    }
    return py_const_true;
}

py_obj_t py_builtin_any(py_obj_t o_in) {
    py_obj_t iterable = rt_getiter(o_in);
    py_obj_t item;
    while ((item = rt_iternext(iterable)) != py_const_stop_iteration) {
        if (rt_is_true(item)) {
            return py_const_true;
        }
    }
    return py_const_false;
}

py_obj_t py_builtin_bool(int n_args, const py_obj_t *args) {
    switch (n_args) {
        case 0: return py_const_false;
        case 1: if (rt_is_true(args[0])) { return py_const_true; } else { return py_const_false; }
        default: nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "bool() takes at most 1 argument (%d given)", (void*)(machine_int_t)n_args, NULL));
    }
}

py_obj_t py_builtin_callable(py_obj_t o_in) {
    if (py_obj_is_callable(o_in)) {
        return py_const_true;
    } else {
        return py_const_false;
    }
}

#if MICROPY_ENABLE_FLOAT
py_obj_t py_builtin_complex(int n_args, const py_obj_t *args) {
    switch (n_args) {
        case 0:
            return py_obj_new_complex(0, 0);

        case 1:
            // TODO allow string as first arg
            if (IS_O(args[0], O_COMPLEX)) {
                return args[0];
            } else {
                return py_obj_new_complex(py_obj_get_float(args[0]), 0);
            }

        case 2:
        {
            py_float_t real, imag;
            if (IS_O(args[0], O_COMPLEX)) {
                py_obj_get_complex(args[0], &real, &imag);
            } else {
                real = py_obj_get_float(args[0]);
                imag = 0;
            }
            if (IS_O(args[1], O_COMPLEX)) {
                py_float_t real2, imag2;
                py_obj_get_complex(args[1], &real2, &imag2);
                real -= imag2;
                imag += real2;
            } else {
                imag += py_obj_get_float(args[1]);
            }
            return py_obj_new_complex(real, imag);
        }

        default: nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "comlpex() takes at most 2 arguments (%d given)", (void*)(machine_int_t)n_args, NULL));
    }
}
#endif

py_obj_t py_builtin_chr(py_obj_t o_in) {
    int ord = py_obj_get_int(o_in);
    if (0 <= ord && ord <= 0x10ffff) {
        char *str = m_new(char, 2);
        str[0] = ord;
        str[1] = '\0';
        return py_obj_new_str(qstr_from_str_take(str));
    } else {
        nlr_jump(py_obj_new_exception_2(rt_q_ValueError, "chr() arg not in range(0x110000)", NULL, NULL));
168
    }
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
}

py_obj_t py_builtin_dict(void) {
    // TODO create from an iterable!
    return rt_build_map(0);
}

py_obj_t py_builtin_divmod(py_obj_t o1_in, py_obj_t o2_in) {
    if (IS_SMALL_INT(o1_in) && IS_SMALL_INT(o2_in)) {
        py_small_int_t i1 = FROM_SMALL_INT(o1_in);
        py_small_int_t i2 = FROM_SMALL_INT(o2_in);
        py_obj_t revs_args[2];
        revs_args[1] = TO_SMALL_INT(i1 / i2);
        revs_args[0] = TO_SMALL_INT(i1 % i2);
        return rt_build_tuple(2, revs_args);
    } else {
        nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "unsupported operand type(s) for divmod(): '%s' and '%s'", py_obj_get_type_str(o1_in), py_obj_get_type_str(o2_in)));
    }
}

py_obj_t py_builtin_hash(py_obj_t o_in) {
    // TODO hash will generally overflow small integer; can we safely truncate it?
    return py_obj_new_int(py_obj_hash(o_in));
}

py_obj_t py_builtin_iter(py_obj_t o_in) {
    return rt_getiter(o_in);
}

py_obj_t py_builtin_next(py_obj_t o_in) {
    return rt_gen_instance_next(o_in);
200
201
202
203
204
205
206
207
208
209
210
211
212
213
}

py_obj_t py_builtin_len(py_obj_t o_in) {
    py_small_int_t len = 0;
    if (IS_O(o_in, O_STR)) {
        py_obj_base_t *o = o_in;
        len = strlen(qstr_str(o->u_str));
    } else if (IS_O(o_in, O_TUPLE) || IS_O(o_in, O_LIST)) {
        py_obj_base_t *o = o_in;
        len = o->u_tuple_list.len;
    } else if (IS_O(o_in, O_MAP)) {
        py_obj_base_t *o = o_in;
        len = o->u_map.used;
    } else {
214
        nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "object of type '%s' has no len()", py_obj_get_type_str(o_in), NULL));
215
216
217
218
    }
    return TO_SMALL_INT(len);
}

219
220
221
222
223
224
225
226
227
228
229
230
231
py_obj_t py_builtin_list(int n_args, const py_obj_t *args) {
    switch (n_args) {
        case 0: return rt_build_list(0, NULL);
        case 1:
        {
            // make list from iterable
            py_obj_t iterable = rt_getiter(args[0]);
            py_obj_t list = rt_build_list(0, NULL);
            py_obj_t item;
            while ((item = rt_iternext(iterable)) != py_const_stop_iteration) {
                rt_list_append(list, item);
            }
            return list;
232
        }
233
234
235
236
237
238
239
240
241
242
243
244
245
246
        default: nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "list() takes at most 1 argument (%d given)", (void*)(machine_int_t)n_args, NULL));
    }
}

py_obj_t py_builtin_max(int n_args, const py_obj_t *args) {
    if (n_args == 1) {
        // given an iterable
        py_obj_t iterable = rt_getiter(args[0]);
        py_obj_t max_obj = NULL;
        py_obj_t item;
        while ((item = rt_iternext(iterable)) != py_const_stop_iteration) {
            if (max_obj == NULL || py_obj_less(max_obj, item)) {
                max_obj = item;
            }
247
        }
248
249
250
251
        if (max_obj == NULL) {
            nlr_jump(py_obj_new_exception_2(rt_q_ValueError, "max() arg is an empty sequence", NULL, NULL));
        }
        return max_obj;
252
    } else {
253
254
255
256
257
258
259
260
        // given many args
        py_obj_t max_obj = args[0];
        for (int i = 1; i < n_args; i++) {
            if (py_obj_less(max_obj, args[i])) {
                max_obj = args[i];
            }
        }
        return max_obj;
261
262
263
    }
}

264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
py_obj_t py_builtin_min(int n_args, const py_obj_t *args) {
    if (n_args == 1) {
        // given an iterable
        py_obj_t iterable = rt_getiter(args[0]);
        py_obj_t min_obj = NULL;
        py_obj_t item;
        while ((item = rt_iternext(iterable)) != py_const_stop_iteration) {
            if (min_obj == NULL || py_obj_less(item, min_obj)) {
                min_obj = item;
            }
        }
        if (min_obj == NULL) {
            nlr_jump(py_obj_new_exception_2(rt_q_ValueError, "min() arg is an empty sequence", NULL, NULL));
        }
        return min_obj;
    } else {
        // given many args
        py_obj_t min_obj = args[0];
        for (int i = 1; i < n_args; i++) {
            if (py_obj_less(args[i], min_obj)) {
                min_obj = args[i];
            }
        }
        return min_obj;
    }
}
290

291
292
293
294
295
296
297
298
py_obj_t py_builtin_ord(py_obj_t o_in) {
    const char *str = qstr_str(py_obj_get_qstr(o_in));
    if (strlen(str) == 1) {
        return py_obj_new_int(str[0]);
    } else {
        nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "ord() expected a character, but string of length %d found", (void*)(machine_int_t)strlen(str), NULL));
    }
}
299

300
301
302
303
304
305
306
py_obj_t py_builtin_pow(int n_args, const py_obj_t *args) {
    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...
        default: nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "pow expected at most 3 arguments, got %d", (void*)(machine_int_t)n_args, NULL));
    }
}
307

308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
py_obj_t py_builtin_print(int n_args, const py_obj_t *args) {
    for (int i = 0; i < n_args; i++) {
        if (i > 0) {
            printf(" ");
        }
        if (IS_O(args[i], O_STR)) {
            // special case, print string raw
            printf("%s", qstr_str(((py_obj_base_t*)args[i])->u_str));
        } else {
            // print the object Python style
            py_obj_print(args[i]);
        }
    }
    printf("\n");
    return py_const_none;
323
324
}

325
py_obj_t py_builtin_range(int n_args, const py_obj_t *args) {
326
327
328
329
330
331
332
    switch (n_args) {
        case 1: return py_obj_new_range(0, py_obj_get_int(args[0]), 1);
        case 2: return py_obj_new_range(py_obj_get_int(args[0]), py_obj_get_int(args[1]), 1);
        case 3: return py_obj_new_range(py_obj_get_int(args[0]), py_obj_get_int(args[1]), py_obj_get_int(args[2]));
        default: nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "range expected at most 3 arguments, got %d", (void*)(machine_int_t)n_args, NULL));
    }
}
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347

py_obj_t py_builtin_sum(int n_args, const py_obj_t *args) {
    py_obj_t value;
    switch (n_args) {
        case 1: value = py_obj_new_int(0); break;
        case 2: value = args[1]; break;
        default: nlr_jump(py_obj_new_exception_2(rt_q_TypeError, "sum expected at most 2 arguments, got %d", (void*)(machine_int_t)n_args, NULL));
    }
    py_obj_t iterable = rt_getiter(args[0]);
    py_obj_t item;
    while ((item = rt_iternext(iterable)) != py_const_stop_iteration) {
        value = rt_binary_op(RT_BINARY_OP_ADD, value, item);
    }
    return value;
}