blob: 633f5d0cae9f4c3d2a82d106ac81485b7cfd5a07 [file] [log] [blame]
xbeefe34222014-03-16 00:14:26 -07001#include <stdbool.h>
Damiend99b0522013-12-21 18:17:45 +00002#include <stdlib.h>
Damiend99b0522013-12-21 18:17:45 +00003#include <string.h>
4#include <assert.h>
5
6#include "nlr.h"
7#include "misc.h"
8#include "mpconfig.h"
Damien George55baff42014-01-21 21:40:13 +00009#include "qstr.h"
Damiend99b0522013-12-21 18:17:45 +000010#include "obj.h"
Paul Sokolovsky90750022014-02-01 15:05:04 +020011#include "objtuple.h"
Paul Sokolovskyf26a3072014-04-17 05:44:51 +030012#include "objfun.h"
Damien George2e482cd2014-02-16 00:01:29 +000013#include "runtime0.h"
Damiend99b0522013-12-21 18:17:45 +000014#include "runtime.h"
15#include "bc.h"
16
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +020017#if 0 // print debugging info
18#define DEBUG_PRINT (1)
19#else // don't print debugging info
Damien George41eb6082014-02-26 22:40:35 +000020#define DEBUG_printf(...) (void)0
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +020021#endif
22
Damiend99b0522013-12-21 18:17:45 +000023/******************************************************************************/
24/* native functions */
25
26// mp_obj_fun_native_t defined in obj.h
27
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +020028STATIC void check_nargs(mp_obj_fun_native_t *self, int n_args, int n_kw) {
Damien Georged17926d2014-03-30 13:35:08 +010029 mp_check_nargs(n_args, self->n_args_min, self->n_args_max, n_kw, self->is_kw);
Dave Hylands51dabac2014-02-17 17:57:13 -080030}
31
Damien Georged17926d2014-03-30 13:35:08 +010032void mp_check_nargs(int n_args, machine_uint_t n_args_min, machine_uint_t n_args_max, int n_kw, bool is_kw) {
Damien George3fd2d7f2014-04-18 22:06:55 +010033 // TODO maybe take the function name as an argument so we can print nicer error messages
34
Dave Hylands51dabac2014-02-17 17:57:13 -080035 if (n_kw && !is_kw) {
Damien George3fd2d7f2014-04-18 22:06:55 +010036 nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments"));
John R. Lenton88cb1e62014-01-13 19:55:18 +000037 }
38
Dave Hylands51dabac2014-02-17 17:57:13 -080039 if (n_args_min == n_args_max) {
40 if (n_args != n_args_min) {
Damien Georgeea13f402014-04-05 18:32:08 +010041 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
Damien George3fd2d7f2014-04-18 22:06:55 +010042 "function takes %d positional arguments but %d were given",
43 n_args_min, n_args));
John R. Lenton88cb1e62014-01-13 19:55:18 +000044 }
45 } else {
Dave Hylands51dabac2014-02-17 17:57:13 -080046 if (n_args < n_args_min) {
Damien Georgeea13f402014-04-05 18:32:08 +010047 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
Damien George3fd2d7f2014-04-18 22:06:55 +010048 "function missing %d required positional arguments",
Dave Hylands51dabac2014-02-17 17:57:13 -080049 n_args_min - n_args));
50 } else if (n_args > n_args_max) {
Damien Georgeea13f402014-04-05 18:32:08 +010051 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
Damien George3fd2d7f2014-04-18 22:06:55 +010052 "function expected at most %d arguments, got %d",
53 n_args_max, n_args));
John R. Lenton88cb1e62014-01-13 19:55:18 +000054 }
55 }
56}
57
Paul Sokolovsky586bfce2014-04-05 13:50:06 +030058STATIC mp_obj_t fun_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
59 switch (op) {
60 case MP_BINARY_OP_EQUAL:
61 // These objects can be equal only if it's the same underlying structure,
62 // we don't even need to check for 2nd arg type.
63 return MP_BOOL(lhs_in == rhs_in);
64 }
65 return NULL;
66}
67
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +020068STATIC mp_obj_t fun_native_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
Damien George3e1a5c12014-03-29 13:43:38 +000069 assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_native));
Damiend99b0522013-12-21 18:17:45 +000070 mp_obj_fun_native_t *self = self_in;
Damien George20006db2014-01-18 14:10:48 +000071
John R. Lenton88cb1e62014-01-13 19:55:18 +000072 // check number of arguments
Damien George20006db2014-01-18 14:10:48 +000073 check_nargs(self, n_args, n_kw);
74
John R. Lentonc06763a2014-01-07 17:29:16 +000075 if (self->is_kw) {
Damien George20006db2014-01-18 14:10:48 +000076 // function allows keywords
77
Damien George0a587b82014-02-08 18:53:41 +000078 // we create a map directly from the given args array
79 mp_map_t kw_args;
80 mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
Damien George20006db2014-01-18 14:10:48 +000081
Damien George0a587b82014-02-08 18:53:41 +000082 return ((mp_fun_kw_t)self->fun)(n_args, args, &kw_args);
Damien George20006db2014-01-18 14:10:48 +000083
Paul Sokolovsky9d95a2b2014-01-26 01:58:51 +020084 } else if (self->n_args_min <= 3 && self->n_args_min == self->n_args_max) {
Damiend99b0522013-12-21 18:17:45 +000085 // function requires a fixed number of arguments
86
Damiend99b0522013-12-21 18:17:45 +000087 // dispatch function call
88 switch (self->n_args_min) {
89 case 0:
90 return ((mp_fun_0_t)self->fun)();
91
92 case 1:
93 return ((mp_fun_1_t)self->fun)(args[0]);
94
95 case 2:
Damien George20006db2014-01-18 14:10:48 +000096 return ((mp_fun_2_t)self->fun)(args[0], args[1]);
Damiend99b0522013-12-21 18:17:45 +000097
John R. Lenton45a87442014-01-04 01:15:01 +000098 case 3:
Damien George20006db2014-01-18 14:10:48 +000099 return ((mp_fun_3_t)self->fun)(args[0], args[1], args[2]);
John R. Lenton45a87442014-01-04 01:15:01 +0000100
Damiend99b0522013-12-21 18:17:45 +0000101 default:
102 assert(0);
103 return mp_const_none;
104 }
105
106 } else {
Damien George20006db2014-01-18 14:10:48 +0000107 // function takes a variable number of arguments, but no keywords
Damiend99b0522013-12-21 18:17:45 +0000108
Damien George20006db2014-01-18 14:10:48 +0000109 return ((mp_fun_var_t)self->fun)(n_args, args);
Damiend99b0522013-12-21 18:17:45 +0000110 }
111}
112
Damien George3e1a5c12014-03-29 13:43:38 +0000113const mp_obj_type_t mp_type_fun_native = {
Damien Georgec5966122014-02-15 16:10:44 +0000114 { &mp_type_type },
Damien Georgea71c83a2014-02-15 11:34:50 +0000115 .name = MP_QSTR_function,
Damien George20006db2014-01-18 14:10:48 +0000116 .call = fun_native_call,
Paul Sokolovsky586bfce2014-04-05 13:50:06 +0300117 .binary_op = fun_binary_op,
Damiend99b0522013-12-21 18:17:45 +0000118};
119
Damien Georgef62d33a2014-01-13 19:50:05 +0000120// fun must have the correct signature for n_args fixed arguments
Damien Georged17926d2014-03-30 13:35:08 +0100121mp_obj_t mp_make_function_n(int n_args, void *fun) {
Damiend99b0522013-12-21 18:17:45 +0000122 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
Damien George3e1a5c12014-03-29 13:43:38 +0000123 o->base.type = &mp_type_fun_native;
Dave Hylands44332ec2014-01-13 08:42:43 -0800124 o->is_kw = false;
Damien Georgef62d33a2014-01-13 19:50:05 +0000125 o->n_args_min = n_args;
126 o->n_args_max = n_args;
John R. Lenton45a87442014-01-04 01:15:01 +0000127 o->fun = fun;
128 return o;
129}
130
Damien Georged17926d2014-03-30 13:35:08 +0100131mp_obj_t mp_make_function_var(int n_args_min, mp_fun_var_t fun) {
Damiend99b0522013-12-21 18:17:45 +0000132 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
Damien George3e1a5c12014-03-29 13:43:38 +0000133 o->base.type = &mp_type_fun_native;
Dave Hylands44332ec2014-01-13 08:42:43 -0800134 o->is_kw = false;
Damiend99b0522013-12-21 18:17:45 +0000135 o->n_args_min = n_args_min;
Damien Georged5e81822014-02-26 17:47:05 +0000136 o->n_args_max = MP_OBJ_FUN_ARGS_MAX;
Damiend99b0522013-12-21 18:17:45 +0000137 o->fun = fun;
138 return o;
139}
140
141// min and max are inclusive
Damien Georged17926d2014-03-30 13:35:08 +0100142mp_obj_t mp_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var_t fun) {
Damiend99b0522013-12-21 18:17:45 +0000143 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
Damien George3e1a5c12014-03-29 13:43:38 +0000144 o->base.type = &mp_type_fun_native;
Dave Hylands44332ec2014-01-13 08:42:43 -0800145 o->is_kw = false;
Damiend99b0522013-12-21 18:17:45 +0000146 o->n_args_min = n_args_min;
147 o->n_args_max = n_args_max;
148 o->fun = fun;
149 return o;
150}
151
152/******************************************************************************/
153/* byte code functions */
154
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200155#if DEBUG_PRINT
Damien Georgef78b6df2014-03-31 15:59:25 +0100156STATIC void dump_args(const mp_obj_t *a, int sz) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200157 DEBUG_printf("%p: ", a);
158 for (int i = 0; i < sz; i++) {
159 DEBUG_printf("%p ", a[i]);
160 }
161 DEBUG_printf("\n");
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200162}
Damien Georgef78b6df2014-03-31 15:59:25 +0100163#else
164#define dump_args(...) (void)0
165#endif
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200166
Paul Sokolovsky7fafb282014-03-30 20:21:28 +0300167// If it's possible to call a function without allocating new argument array,
168// this function returns true, together with pointers to 2 subarrays to be used
169// as arguments. Otherwise, it returns false. It is expected that this fucntion
170// will be accompanied by another, mp_obj_fun_prepare_full_args(), which will
171// instead take pointer to full-length out-array, and will fill it in. Rationale
172// being that a caller can try this function and if it succeeds, the function call
173// can be made without allocating extra memory. Otherwise, caller can allocate memory
174// and try "full" function. These functions are expected to be refactoring of
175// code in fun_bc_call() and evenrually replace it.
176bool mp_obj_fun_prepare_simple_args(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args,
177 uint *out_args1_len, const mp_obj_t **out_args1, uint *out_args2_len, const mp_obj_t **out_args2) {
178 mp_obj_fun_bc_t *self = self_in;
179
180 assert(n_kw == 0);
181 assert(self->takes_var_args == 0);
182 assert(self->takes_kw_args == 0);
183
184 mp_obj_t *extra_args = self->extra_args + self->n_def_args;
185 uint n_extra_args = 0;
186
187 if (n_args > self->n_args) {
188 goto arg_error;
189 } else {
190 extra_args -= self->n_args - n_args;
191 n_extra_args += self->n_args - n_args;
192 }
193 *out_args1 = args;
194 *out_args1_len = n_args;
195 *out_args2 = extra_args;
196 *out_args2_len = n_extra_args;
197 return true;
198
199arg_error:
Damien Georgeea13f402014-04-05 18:32:08 +0100200 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", self->n_args, n_args));
Paul Sokolovsky7fafb282014-03-30 20:21:28 +0300201}
202
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200203STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
Paul Sokolovsky41e2dea2014-04-10 05:37:58 +0300204 DEBUG_printf("Input n_args: %d, n_kw: %d\n", n_args, n_kw);
205 DEBUG_printf("Input pos args: ");
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200206 dump_args(args, n_args);
Paul Sokolovsky41e2dea2014-04-10 05:37:58 +0300207 DEBUG_printf("Input kw args: ");
208 dump_args(args + n_args, n_kw * 2);
Damiend99b0522013-12-21 18:17:45 +0000209 mp_obj_fun_bc_t *self = self_in;
Paul Sokolovsky41e2dea2014-04-10 05:37:58 +0300210 DEBUG_printf("Func n_def_args: %d\n", self->n_def_args);
Damiend99b0522013-12-21 18:17:45 +0000211
Damien Georgee5d371b2014-02-16 00:17:42 +0000212 const mp_obj_t *kwargs = args + n_args;
Damien George2e482cd2014-02-16 00:01:29 +0000213 mp_obj_t *extra_args = self->extra_args + self->n_def_args;
214 uint n_extra_args = 0;
215
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200216
Damien Georgee5d371b2014-02-16 00:17:42 +0000217 // check positional arguments
218
Damien George2e482cd2014-02-16 00:01:29 +0000219 if (n_args > self->n_args) {
220 // given more than enough arguments
221 if (!self->takes_var_args) {
Paul Sokolovsky1a375882014-04-13 11:24:14 +0300222 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
223 "function takes %d positional arguments but %d were given", self->n_args, n_args));
Damien George2e482cd2014-02-16 00:01:29 +0000224 }
225 // put extra arguments in varargs tuple
226 *extra_args = mp_obj_new_tuple(n_args - self->n_args, args + self->n_args);
227 n_extra_args = 1;
228 n_args = self->n_args;
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200229 } else {
Damien George2e482cd2014-02-16 00:01:29 +0000230 if (self->takes_var_args) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200231 DEBUG_printf("passing empty tuple as *args\n");
Damien George2e482cd2014-02-16 00:01:29 +0000232 *extra_args = mp_const_empty_tuple;
233 n_extra_args = 1;
234 }
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200235 // Apply processing and check below only if we don't have kwargs,
236 // otherwise, kw handling code below has own extensive checks.
237 if (n_kw == 0) {
238 if (n_args >= self->n_args - self->n_def_args) {
239 // given enough arguments, but may need to use some default arguments
240 extra_args -= self->n_args - n_args;
241 n_extra_args += self->n_args - n_args;
242 } else {
Paul Sokolovsky1a375882014-04-13 11:24:14 +0300243 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
244 "function takes at least %d positional arguments but %d were given",
245 self->n_args - self->n_def_args, n_args));
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200246 }
247 }
Damiend99b0522013-12-21 18:17:45 +0000248 }
Damien George2e482cd2014-02-16 00:01:29 +0000249
Damien Georgee5d371b2014-02-16 00:17:42 +0000250 // check keyword arguments
251
Damien George20006db2014-01-18 14:10:48 +0000252 if (n_kw != 0) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200253 // We cannot use dynamically-sized array here, because GCC indeed
254 // deallocates it on leaving defining scope (unlike most static stack allocs).
255 // So, we have 2 choices: allocate it unconditionally at the top of function
256 // (wastes stack), or use alloca which is guaranteed to dealloc on func exit.
257 //mp_obj_t flat_args[self->n_args];
258 mp_obj_t *flat_args = alloca(self->n_args * sizeof(mp_obj_t));
259 for (int i = self->n_args - 1; i >= 0; i--) {
260 flat_args[i] = MP_OBJ_NULL;
Damien Georgee5d371b2014-02-16 00:17:42 +0000261 }
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200262 memcpy(flat_args, args, sizeof(*args) * n_args);
263 DEBUG_printf("Initial args: ");
264 dump_args(flat_args, self->n_args);
265
266 mp_obj_t dict = MP_OBJ_NULL;
267 if (self->takes_kw_args) {
268 dict = mp_obj_new_dict(n_kw); // TODO: better go conservative with 0?
269 }
Damien Georgee5d371b2014-02-16 00:17:42 +0000270 for (uint i = 0; i < n_kw; i++) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200271 qstr arg_name = MP_OBJ_QSTR_VALUE(kwargs[2 * i]);
272 for (uint j = 0; j < self->n_args; j++) {
273 if (arg_name == self->args[j]) {
274 if (flat_args[j] != MP_OBJ_NULL) {
Damien Georgeea13f402014-04-05 18:32:08 +0100275 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200276 "function got multiple values for argument '%s'", qstr_str(arg_name)));
277 }
278 flat_args[j] = kwargs[2 * i + 1];
279 goto continue2;
280 }
281 }
282 // Didn't find name match with positional args
283 if (!self->takes_kw_args) {
Damien Georgeea13f402014-04-05 18:32:08 +0100284 nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments"));
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200285 }
Damien Georgee5d371b2014-02-16 00:17:42 +0000286 mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]);
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200287continue2:;
Damien Georgee5d371b2014-02-16 00:17:42 +0000288 }
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200289 DEBUG_printf("Args with kws flattened: ");
290 dump_args(flat_args, self->n_args);
291
292 // Now fill in defaults
293 mp_obj_t *d = &flat_args[self->n_args - 1];
294 mp_obj_t *s = &self->extra_args[self->n_def_args - 1];
Paul Sokolovsky978607a2014-04-10 05:39:38 +0300295 for (int i = self->n_def_args; i > 0; i--, d--, s--) {
Damien George25f5a302014-03-03 23:25:08 +0000296 if (*d == MP_OBJ_NULL) {
Paul Sokolovsky978607a2014-04-10 05:39:38 +0300297 *d = *s;
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200298 }
299 }
300 DEBUG_printf("Args after filling defaults: ");
301 dump_args(flat_args, self->n_args);
302
303 // Now check that all mandatory args specified
304 while (d >= flat_args) {
305 if (*d-- == MP_OBJ_NULL) {
Damien Georgeea13f402014-04-05 18:32:08 +0100306 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200307 "function missing required positional argument #%d", d - flat_args));
308 }
309 }
310
311 args = flat_args;
312 n_args = self->n_args;
313
314 if (self->takes_kw_args) {
315 extra_args[n_extra_args] = dict;
316 n_extra_args += 1;
317 }
Damien Georgee5d371b2014-02-16 00:17:42 +0000318 } else {
319 // no keyword arguments given
320 if (self->takes_kw_args) {
321 extra_args[n_extra_args] = mp_obj_new_dict(0);
322 n_extra_args += 1;
323 }
Damien George20006db2014-01-18 14:10:48 +0000324 }
Damiend99b0522013-12-21 18:17:45 +0000325
Damien George7efc5b32014-04-05 22:36:42 +0100326 mp_obj_dict_t *old_globals = mp_globals_get();
Damien Georged17926d2014-03-30 13:35:08 +0100327 mp_globals_set(self->globals);
Damien Georgec8f78bc2014-02-15 22:55:00 +0000328 mp_obj_t result;
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200329 DEBUG_printf("Calling: args=%p, n_args=%d, extra_args=%p, n_extra_args=%d\n", args, n_args, extra_args, n_extra_args);
330 dump_args(args, n_args);
331 dump_args(extra_args, n_extra_args);
Damien Georgebee17b02014-03-27 11:07:04 +0000332 mp_vm_return_kind_t vm_return_kind = mp_execute_byte_code(self->bytecode, args, n_args, extra_args, n_extra_args, &result);
Damien Georged17926d2014-03-30 13:35:08 +0100333 mp_globals_set(old_globals);
Damien Georgefb083ea2014-02-01 18:29:40 +0000334
Damien Georgec8f78bc2014-02-15 22:55:00 +0000335 if (vm_return_kind == MP_VM_RETURN_NORMAL) {
336 return result;
337 } else { // MP_VM_RETURN_EXCEPTION
Damien Georgeea13f402014-04-05 18:32:08 +0100338 nlr_raise(result);
Damien Georgec8f78bc2014-02-15 22:55:00 +0000339 }
Damiend99b0522013-12-21 18:17:45 +0000340}
341
Damien George3e1a5c12014-03-29 13:43:38 +0000342const mp_obj_type_t mp_type_fun_bc = {
Damien Georgec5966122014-02-15 16:10:44 +0000343 { &mp_type_type },
Damien Georgea71c83a2014-02-15 11:34:50 +0000344 .name = MP_QSTR_function,
Damien George20006db2014-01-18 14:10:48 +0000345 .call = fun_bc_call,
Paul Sokolovsky586bfce2014-04-05 13:50:06 +0300346 .binary_op = fun_binary_op,
Damiend99b0522013-12-21 18:17:45 +0000347};
348
Damien Georgebee17b02014-03-27 11:07:04 +0000349mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_args, mp_obj_t def_args_in, const byte *code) {
Damien George2e482cd2014-02-16 00:01:29 +0000350 uint n_def_args = 0;
351 uint n_extra_args = 0;
Paul Sokolovsky90750022014-02-01 15:05:04 +0200352 mp_obj_tuple_t *def_args = def_args_in;
353 if (def_args != MP_OBJ_NULL) {
Damien George69b89d22014-04-11 13:38:30 +0000354 assert(MP_OBJ_IS_TYPE(def_args, &mp_type_tuple));
Paul Sokolovsky90750022014-02-01 15:05:04 +0200355 n_def_args = def_args->len;
Damien George2e482cd2014-02-16 00:01:29 +0000356 n_extra_args = def_args->len;
Paul Sokolovsky90750022014-02-01 15:05:04 +0200357 }
Damien George2e482cd2014-02-16 00:01:29 +0000358 if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
359 n_extra_args += 1;
360 }
Damien Georgee5d371b2014-02-16 00:17:42 +0000361 if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) {
362 n_extra_args += 1;
363 }
Damien George2e482cd2014-02-16 00:01:29 +0000364 mp_obj_fun_bc_t *o = m_new_obj_var(mp_obj_fun_bc_t, mp_obj_t, n_extra_args);
Damien George3e1a5c12014-03-29 13:43:38 +0000365 o->base.type = &mp_type_fun_bc;
Damien Georged17926d2014-03-30 13:35:08 +0100366 o->globals = mp_globals_get();
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200367 o->args = args;
Damiend99b0522013-12-21 18:17:45 +0000368 o->n_args = n_args;
Paul Sokolovsky90750022014-02-01 15:05:04 +0200369 o->n_def_args = n_def_args;
Damien George2e482cd2014-02-16 00:01:29 +0000370 o->takes_var_args = (scope_flags & MP_SCOPE_FLAG_VARARGS) != 0;
371 o->takes_kw_args = (scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0;
Damien George66028ab2014-01-03 14:03:48 +0000372 o->bytecode = code;
Paul Sokolovsky90750022014-02-01 15:05:04 +0200373 if (def_args != MP_OBJ_NULL) {
Damien George2e482cd2014-02-16 00:01:29 +0000374 memcpy(o->extra_args, def_args->items, n_def_args * sizeof(mp_obj_t));
Paul Sokolovsky90750022014-02-01 15:05:04 +0200375 }
Damiend99b0522013-12-21 18:17:45 +0000376 return o;
377}
378
Damiend99b0522013-12-21 18:17:45 +0000379/******************************************************************************/
380/* inline assembler functions */
381
382typedef struct _mp_obj_fun_asm_t {
383 mp_obj_base_t base;
384 int n_args;
385 void *fun;
386} mp_obj_fun_asm_t;
387
388typedef machine_uint_t (*inline_asm_fun_0_t)();
389typedef machine_uint_t (*inline_asm_fun_1_t)(machine_uint_t);
390typedef machine_uint_t (*inline_asm_fun_2_t)(machine_uint_t, machine_uint_t);
391typedef machine_uint_t (*inline_asm_fun_3_t)(machine_uint_t, machine_uint_t, machine_uint_t);
392
393// convert a Micro Python object to a sensible value for inline asm
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200394STATIC machine_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
Damiend99b0522013-12-21 18:17:45 +0000395 // TODO for byte_array, pass pointer to the array
396 if (MP_OBJ_IS_SMALL_INT(obj)) {
397 return MP_OBJ_SMALL_INT_VALUE(obj);
398 } else if (obj == mp_const_none) {
399 return 0;
400 } else if (obj == mp_const_false) {
401 return 0;
402 } else if (obj == mp_const_true) {
403 return 1;
Damien George5fa93b62014-01-22 14:35:10 +0000404 } else if (MP_OBJ_IS_STR(obj)) {
Damiend99b0522013-12-21 18:17:45 +0000405 // pointer to the string (it's probably constant though!)
Damien George5fa93b62014-01-22 14:35:10 +0000406 uint l;
407 return (machine_uint_t)mp_obj_str_get_data(obj, &l);
Damiend99b0522013-12-21 18:17:45 +0000408 } else {
Damien George87210872014-04-13 00:30:32 +0100409 mp_obj_type_t *type = mp_obj_get_type(obj);
410 if (0) {
411#if MICROPY_ENABLE_FLOAT
412 } else if (type == &mp_type_float) {
413 // convert float to int (could also pass in float registers)
414 return (machine_int_t)mp_obj_float_get(obj);
415#endif
416 } else if (type == &mp_type_tuple) {
417 // pointer to start of tuple (could pass length, but then could use len(x) for that)
418 uint len;
419 mp_obj_t *items;
420 mp_obj_tuple_get(obj, &len, &items);
421 return (machine_uint_t)items;
422 } else if (type == &mp_type_list) {
423 // pointer to start of list (could pass length, but then could use len(x) for that)
424 uint len;
425 mp_obj_t *items;
426 mp_obj_list_get(obj, &len, &items);
427 return (machine_uint_t)items;
Damien George87210872014-04-13 00:30:32 +0100428 } else {
Damien George57a4b4f2014-04-18 22:29:21 +0100429 mp_buffer_info_t bufinfo;
Damien George8a1cab92014-04-13 12:08:52 +0100430 if (mp_get_buffer(obj, &bufinfo)) {
431 // supports the buffer protocol, return a pointer to the data
432 return (machine_uint_t)bufinfo.buf;
433 } else {
434 // just pass along a pointer to the object
435 return (machine_uint_t)obj;
436 }
Damien George87210872014-04-13 00:30:32 +0100437 }
Damiend99b0522013-12-21 18:17:45 +0000438 }
439}
440
441// convert a return value from inline asm to a sensible Micro Python object
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200442STATIC mp_obj_t convert_val_from_inline_asm(machine_uint_t val) {
Damiend99b0522013-12-21 18:17:45 +0000443 return MP_OBJ_NEW_SMALL_INT(val);
444}
445
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200446STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
Damiend99b0522013-12-21 18:17:45 +0000447 mp_obj_fun_asm_t *self = self_in;
448
449 if (n_args != self->n_args) {
Damien Georgeea13f402014-04-05 18:32:08 +0100450 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", self->n_args, n_args));
Damiend99b0522013-12-21 18:17:45 +0000451 }
Damien George20006db2014-01-18 14:10:48 +0000452 if (n_kw != 0) {
Damien Georgeea13f402014-04-05 18:32:08 +0100453 nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments"));
Damien George20006db2014-01-18 14:10:48 +0000454 }
Damiend99b0522013-12-21 18:17:45 +0000455
456 machine_uint_t ret;
457 if (n_args == 0) {
458 ret = ((inline_asm_fun_0_t)self->fun)();
459 } else if (n_args == 1) {
460 ret = ((inline_asm_fun_1_t)self->fun)(convert_obj_for_inline_asm(args[0]));
461 } else if (n_args == 2) {
Damien George20006db2014-01-18 14:10:48 +0000462 ret = ((inline_asm_fun_2_t)self->fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]));
Damiend99b0522013-12-21 18:17:45 +0000463 } else if (n_args == 3) {
Damien George20006db2014-01-18 14:10:48 +0000464 ret = ((inline_asm_fun_3_t)self->fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]), convert_obj_for_inline_asm(args[2]));
Damiend99b0522013-12-21 18:17:45 +0000465 } else {
466 assert(0);
467 ret = 0;
468 }
469
470 return convert_val_from_inline_asm(ret);
471}
472
Damien George3e1a5c12014-03-29 13:43:38 +0000473STATIC const mp_obj_type_t mp_type_fun_asm = {
Damien Georgec5966122014-02-15 16:10:44 +0000474 { &mp_type_type },
Damien Georgea71c83a2014-02-15 11:34:50 +0000475 .name = MP_QSTR_function,
Damien George20006db2014-01-18 14:10:48 +0000476 .call = fun_asm_call,
Paul Sokolovsky586bfce2014-04-05 13:50:06 +0300477 .binary_op = fun_binary_op,
Damiend99b0522013-12-21 18:17:45 +0000478};
479
480mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun) {
481 mp_obj_fun_asm_t *o = m_new_obj(mp_obj_fun_asm_t);
Damien George3e1a5c12014-03-29 13:43:38 +0000482 o->base.type = &mp_type_fun_asm;
Damiend99b0522013-12-21 18:17:45 +0000483 o->n_args = n_args;
484 o->fun = fun;
485 return o;
486}