blob: 26dfe0b2e25dd5af80e82a078d40e5ccec1e5456 [file] [log] [blame]
Damien George04b91472014-05-03 23:27:38 +01001/*
2 * This file is part of the Micro Python project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2013, 2014 Damien P. George
Paul Sokolovskyda9f0922014-05-13 08:44:45 +03007 * Copyright (c) 2014 Paul Sokolovsky
Damien George04b91472014-05-03 23:27:38 +01008 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
xbeefe34222014-03-16 00:14:26 -070028#include <stdbool.h>
Damiend99b0522013-12-21 18:17:45 +000029#include <string.h>
30#include <assert.h>
stijn98e2ee02014-05-03 10:14:16 +020031#include <alloca.h>
Damiend99b0522013-12-21 18:17:45 +000032
Paul Sokolovskyf54bcbf2014-05-02 17:47:01 +030033#include "mpconfig.h"
Damiend99b0522013-12-21 18:17:45 +000034#include "nlr.h"
35#include "misc.h"
Damien George55baff42014-01-21 21:40:13 +000036#include "qstr.h"
Damiend99b0522013-12-21 18:17:45 +000037#include "obj.h"
Paul Sokolovsky90750022014-02-01 15:05:04 +020038#include "objtuple.h"
Paul Sokolovskyf26a3072014-04-17 05:44:51 +030039#include "objfun.h"
Damien George2e482cd2014-02-16 00:01:29 +000040#include "runtime0.h"
Damiend99b0522013-12-21 18:17:45 +000041#include "runtime.h"
42#include "bc.h"
43
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +020044#if 0 // print debugging info
45#define DEBUG_PRINT (1)
46#else // don't print debugging info
Damien George41eb6082014-02-26 22:40:35 +000047#define DEBUG_printf(...) (void)0
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +020048#endif
49
Damiend99b0522013-12-21 18:17:45 +000050/******************************************************************************/
51/* native functions */
52
53// mp_obj_fun_native_t defined in obj.h
54
Paul Sokolovsky586bfce2014-04-05 13:50:06 +030055STATIC mp_obj_t fun_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
56 switch (op) {
57 case MP_BINARY_OP_EQUAL:
58 // These objects can be equal only if it's the same underlying structure,
59 // we don't even need to check for 2nd arg type.
60 return MP_BOOL(lhs_in == rhs_in);
61 }
Damien George6ac5dce2014-05-21 19:42:43 +010062 return MP_OBJ_NULL; // op not supported
Paul Sokolovsky586bfce2014-04-05 13:50:06 +030063}
64
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +020065STATIC 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 +000066 assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_native));
Damiend99b0522013-12-21 18:17:45 +000067 mp_obj_fun_native_t *self = self_in;
Damien George20006db2014-01-18 14:10:48 +000068
John R. Lenton88cb1e62014-01-13 19:55:18 +000069 // check number of arguments
Damien Georgea3f94e02014-04-20 00:13:22 +010070 mp_arg_check_num(n_args, n_kw, self->n_args_min, self->n_args_max, self->is_kw);
Damien George20006db2014-01-18 14:10:48 +000071
John R. Lentonc06763a2014-01-07 17:29:16 +000072 if (self->is_kw) {
Damien George20006db2014-01-18 14:10:48 +000073 // function allows keywords
74
Damien George0a587b82014-02-08 18:53:41 +000075 // we create a map directly from the given args array
76 mp_map_t kw_args;
77 mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
Damien George20006db2014-01-18 14:10:48 +000078
Damien George0a587b82014-02-08 18:53:41 +000079 return ((mp_fun_kw_t)self->fun)(n_args, args, &kw_args);
Damien George20006db2014-01-18 14:10:48 +000080
Paul Sokolovsky9d95a2b2014-01-26 01:58:51 +020081 } else if (self->n_args_min <= 3 && self->n_args_min == self->n_args_max) {
Damiend99b0522013-12-21 18:17:45 +000082 // function requires a fixed number of arguments
83
Damiend99b0522013-12-21 18:17:45 +000084 // dispatch function call
85 switch (self->n_args_min) {
86 case 0:
87 return ((mp_fun_0_t)self->fun)();
88
89 case 1:
90 return ((mp_fun_1_t)self->fun)(args[0]);
91
92 case 2:
Damien George20006db2014-01-18 14:10:48 +000093 return ((mp_fun_2_t)self->fun)(args[0], args[1]);
Damiend99b0522013-12-21 18:17:45 +000094
John R. Lenton45a87442014-01-04 01:15:01 +000095 case 3:
Damien George20006db2014-01-18 14:10:48 +000096 return ((mp_fun_3_t)self->fun)(args[0], args[1], args[2]);
John R. Lenton45a87442014-01-04 01:15:01 +000097
Damiend99b0522013-12-21 18:17:45 +000098 default:
99 assert(0);
100 return mp_const_none;
101 }
102
103 } else {
Damien George20006db2014-01-18 14:10:48 +0000104 // function takes a variable number of arguments, but no keywords
Damiend99b0522013-12-21 18:17:45 +0000105
Damien George20006db2014-01-18 14:10:48 +0000106 return ((mp_fun_var_t)self->fun)(n_args, args);
Damiend99b0522013-12-21 18:17:45 +0000107 }
108}
109
Damien George3e1a5c12014-03-29 13:43:38 +0000110const mp_obj_type_t mp_type_fun_native = {
Damien Georgec5966122014-02-15 16:10:44 +0000111 { &mp_type_type },
Damien Georgea71c83a2014-02-15 11:34:50 +0000112 .name = MP_QSTR_function,
Damien George20006db2014-01-18 14:10:48 +0000113 .call = fun_native_call,
Paul Sokolovsky586bfce2014-04-05 13:50:06 +0300114 .binary_op = fun_binary_op,
Damiend99b0522013-12-21 18:17:45 +0000115};
116
Damien Georgef62d33a2014-01-13 19:50:05 +0000117// fun must have the correct signature for n_args fixed arguments
Damien Georged17926d2014-03-30 13:35:08 +0100118mp_obj_t mp_make_function_n(int n_args, void *fun) {
Damiend99b0522013-12-21 18:17:45 +0000119 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
Damien George3e1a5c12014-03-29 13:43:38 +0000120 o->base.type = &mp_type_fun_native;
Dave Hylands44332ec2014-01-13 08:42:43 -0800121 o->is_kw = false;
Damien Georgef62d33a2014-01-13 19:50:05 +0000122 o->n_args_min = n_args;
123 o->n_args_max = n_args;
John R. Lenton45a87442014-01-04 01:15:01 +0000124 o->fun = fun;
125 return o;
126}
127
Damien Georged17926d2014-03-30 13:35:08 +0100128mp_obj_t mp_make_function_var(int n_args_min, mp_fun_var_t fun) {
Damiend99b0522013-12-21 18:17:45 +0000129 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
Damien George3e1a5c12014-03-29 13:43:38 +0000130 o->base.type = &mp_type_fun_native;
Dave Hylands44332ec2014-01-13 08:42:43 -0800131 o->is_kw = false;
Damiend99b0522013-12-21 18:17:45 +0000132 o->n_args_min = n_args_min;
Damien Georged5e81822014-02-26 17:47:05 +0000133 o->n_args_max = MP_OBJ_FUN_ARGS_MAX;
Damiend99b0522013-12-21 18:17:45 +0000134 o->fun = fun;
135 return o;
136}
137
138// min and max are inclusive
Damien Georged17926d2014-03-30 13:35:08 +0100139mp_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 +0000140 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
Damien George3e1a5c12014-03-29 13:43:38 +0000141 o->base.type = &mp_type_fun_native;
Dave Hylands44332ec2014-01-13 08:42:43 -0800142 o->is_kw = false;
Damiend99b0522013-12-21 18:17:45 +0000143 o->n_args_min = n_args_min;
144 o->n_args_max = n_args_max;
145 o->fun = fun;
146 return o;
147}
148
149/******************************************************************************/
150/* byte code functions */
151
Paul Sokolovskyc3103b52014-05-01 22:20:07 +0300152const char *mp_obj_code_get_name(const byte *code_info) {
Paul Sokolovsky68551a82014-05-01 01:32:58 +0300153 qstr block_name = code_info[8] | (code_info[9] << 8) | (code_info[10] << 16) | (code_info[11] << 24);
154 return qstr_str(block_name);
155}
156
Paul Sokolovskyab7bf282014-05-17 11:08:33 +0300157const char *mp_obj_fun_get_name(mp_const_obj_t fun_in) {
158 const mp_obj_fun_bc_t *fun = fun_in;
Paul Sokolovsky418aca92014-05-03 14:10:34 +0300159 const byte *code_info = fun->bytecode;
Paul Sokolovskyc3103b52014-05-01 22:20:07 +0300160 return mp_obj_code_get_name(code_info);
161}
162
Paul Sokolovsky68551a82014-05-01 01:32:58 +0300163#if MICROPY_CPYTHON_COMPAT
164STATIC void fun_bc_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
165 mp_obj_fun_bc_t *o = o_in;
166 print(env, "<function %s at 0x%x>", mp_obj_fun_get_name(o), o);
167}
168#endif
169
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200170#if DEBUG_PRINT
Damien Georgef78b6df2014-03-31 15:59:25 +0100171STATIC void dump_args(const mp_obj_t *a, int sz) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200172 DEBUG_printf("%p: ", a);
173 for (int i = 0; i < sz; i++) {
174 DEBUG_printf("%p ", a[i]);
175 }
176 DEBUG_printf("\n");
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200177}
Damien Georgef78b6df2014-03-31 15:59:25 +0100178#else
179#define dump_args(...) (void)0
180#endif
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200181
Paul Sokolovsky22d05982014-04-30 05:37:28 +0300182STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, uint expected, uint given) {
Paul Sokolovsky1f85d622014-05-01 01:35:38 +0300183#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
184 // Generic message, to be reused for other argument issues
185 nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
186 "argument num/types mismatch"));
187#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL
Paul Sokolovsky22d05982014-04-30 05:37:28 +0300188 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
189 "function takes %d positional arguments but %d were given", expected, given));
Paul Sokolovsky1f85d622014-05-01 01:35:38 +0300190#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
191 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
192 "%s() takes %d positional arguments but %d were given",
193 mp_obj_fun_get_name(f), expected, given));
194#endif
Paul Sokolovsky22d05982014-04-30 05:37:28 +0300195}
196
Paul Sokolovsky7fafb282014-03-30 20:21:28 +0300197// If it's possible to call a function without allocating new argument array,
198// this function returns true, together with pointers to 2 subarrays to be used
199// as arguments. Otherwise, it returns false. It is expected that this fucntion
200// will be accompanied by another, mp_obj_fun_prepare_full_args(), which will
201// instead take pointer to full-length out-array, and will fill it in. Rationale
202// being that a caller can try this function and if it succeeds, the function call
203// can be made without allocating extra memory. Otherwise, caller can allocate memory
204// and try "full" function. These functions are expected to be refactoring of
205// code in fun_bc_call() and evenrually replace it.
206bool mp_obj_fun_prepare_simple_args(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args,
207 uint *out_args1_len, const mp_obj_t **out_args1, uint *out_args2_len, const mp_obj_t **out_args2) {
208 mp_obj_fun_bc_t *self = self_in;
Paul Sokolovsky7917b732014-05-01 23:00:12 +0300209 DEBUG_printf("mp_obj_fun_prepare_simple_args: given: %d pos, %d kw, expected: %d pos (%d default)\n",
210 n_args, n_kw, self->n_pos_args, self->n_def_args);
Paul Sokolovsky7fafb282014-03-30 20:21:28 +0300211
212 assert(n_kw == 0);
Damien George2827d622014-04-27 15:50:52 +0100213 assert(self->n_kwonly_args == 0);
Paul Sokolovsky7fafb282014-03-30 20:21:28 +0300214 assert(self->takes_var_args == 0);
215 assert(self->takes_kw_args == 0);
216
217 mp_obj_t *extra_args = self->extra_args + self->n_def_args;
218 uint n_extra_args = 0;
219
Damien George2827d622014-04-27 15:50:52 +0100220 if (n_args > self->n_pos_args) {
221 goto arg_error;
Paul Sokolovsky7fafb282014-03-30 20:21:28 +0300222 } else {
Paul Sokolovsky5ba58f42014-05-01 22:59:15 +0300223 if (n_args >= self->n_pos_args - self->n_def_args) {
224 extra_args -= self->n_pos_args - n_args;
225 n_extra_args += self->n_pos_args - n_args;
226 } else {
227 fun_pos_args_mismatch(self, self->n_pos_args - self->n_def_args, n_args);
228 }
Paul Sokolovsky7fafb282014-03-30 20:21:28 +0300229 }
230 *out_args1 = args;
231 *out_args1_len = n_args;
232 *out_args2 = extra_args;
233 *out_args2_len = n_extra_args;
234 return true;
235
236arg_error:
Paul Sokolovsky22d05982014-04-30 05:37:28 +0300237 fun_pos_args_mismatch(self, self->n_pos_args, n_args);
Paul Sokolovsky7fafb282014-03-30 20:21:28 +0300238}
239
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200240STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
Damien George2827d622014-04-27 15:50:52 +0100241 // This function is pretty complicated. It's main aim is to be efficient in speed and RAM
242 // usage for the common case of positional only args.
243 //
244 // extra_args layout: def_args, var_arg tuple, kwonly args, var_kw dict
245
Paul Sokolovsky41e2dea2014-04-10 05:37:58 +0300246 DEBUG_printf("Input n_args: %d, n_kw: %d\n", n_args, n_kw);
247 DEBUG_printf("Input pos args: ");
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200248 dump_args(args, n_args);
Paul Sokolovsky41e2dea2014-04-10 05:37:58 +0300249 DEBUG_printf("Input kw args: ");
250 dump_args(args + n_args, n_kw * 2);
Damiend99b0522013-12-21 18:17:45 +0000251 mp_obj_fun_bc_t *self = self_in;
Paul Sokolovsky41e2dea2014-04-10 05:37:58 +0300252 DEBUG_printf("Func n_def_args: %d\n", self->n_def_args);
Damiend99b0522013-12-21 18:17:45 +0000253
Damien Georgee5d371b2014-02-16 00:17:42 +0000254 const mp_obj_t *kwargs = args + n_args;
Damien George2e482cd2014-02-16 00:01:29 +0000255 mp_obj_t *extra_args = self->extra_args + self->n_def_args;
256 uint n_extra_args = 0;
257
Damien Georgee5d371b2014-02-16 00:17:42 +0000258 // check positional arguments
259
Damien George2827d622014-04-27 15:50:52 +0100260 if (n_args > self->n_pos_args) {
Damien George2e482cd2014-02-16 00:01:29 +0000261 // given more than enough arguments
262 if (!self->takes_var_args) {
Paul Sokolovsky22d05982014-04-30 05:37:28 +0300263 fun_pos_args_mismatch(self, self->n_pos_args, n_args);
Damien George2e482cd2014-02-16 00:01:29 +0000264 }
265 // put extra arguments in varargs tuple
Damien George2827d622014-04-27 15:50:52 +0100266 *extra_args = mp_obj_new_tuple(n_args - self->n_pos_args, args + self->n_pos_args);
Damien George2e482cd2014-02-16 00:01:29 +0000267 n_extra_args = 1;
Damien George2827d622014-04-27 15:50:52 +0100268 n_args = self->n_pos_args;
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200269 } else {
Damien George2e482cd2014-02-16 00:01:29 +0000270 if (self->takes_var_args) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200271 DEBUG_printf("passing empty tuple as *args\n");
Damien George2e482cd2014-02-16 00:01:29 +0000272 *extra_args = mp_const_empty_tuple;
273 n_extra_args = 1;
274 }
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200275 // Apply processing and check below only if we don't have kwargs,
276 // otherwise, kw handling code below has own extensive checks.
277 if (n_kw == 0) {
Damien George2827d622014-04-27 15:50:52 +0100278 if (n_args >= self->n_pos_args - self->n_def_args) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200279 // given enough arguments, but may need to use some default arguments
Damien George2827d622014-04-27 15:50:52 +0100280 extra_args -= self->n_pos_args - n_args;
281 n_extra_args += self->n_pos_args - n_args;
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200282 } else {
Paul Sokolovsky22d05982014-04-30 05:37:28 +0300283 fun_pos_args_mismatch(self, self->n_pos_args - self->n_def_args, n_args);
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200284 }
285 }
Damiend99b0522013-12-21 18:17:45 +0000286 }
Damien George2e482cd2014-02-16 00:01:29 +0000287
Damien Georgee5d371b2014-02-16 00:17:42 +0000288 // check keyword arguments
289
Damien George20006db2014-01-18 14:10:48 +0000290 if (n_kw != 0) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200291 // We cannot use dynamically-sized array here, because GCC indeed
292 // deallocates it on leaving defining scope (unlike most static stack allocs).
293 // So, we have 2 choices: allocate it unconditionally at the top of function
294 // (wastes stack), or use alloca which is guaranteed to dealloc on func exit.
295 //mp_obj_t flat_args[self->n_args];
Damien George2827d622014-04-27 15:50:52 +0100296 mp_obj_t *flat_args = alloca((self->n_pos_args + self->n_kwonly_args) * sizeof(mp_obj_t));
297 for (int i = self->n_pos_args + self->n_kwonly_args - 1; i >= 0; i--) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200298 flat_args[i] = MP_OBJ_NULL;
Damien Georgee5d371b2014-02-16 00:17:42 +0000299 }
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200300 memcpy(flat_args, args, sizeof(*args) * n_args);
301 DEBUG_printf("Initial args: ");
Damien George2827d622014-04-27 15:50:52 +0100302 dump_args(flat_args, self->n_pos_args + self->n_kwonly_args);
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200303
304 mp_obj_t dict = MP_OBJ_NULL;
305 if (self->takes_kw_args) {
306 dict = mp_obj_new_dict(n_kw); // TODO: better go conservative with 0?
307 }
Damien Georgee5d371b2014-02-16 00:17:42 +0000308 for (uint i = 0; i < n_kw; i++) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200309 qstr arg_name = MP_OBJ_QSTR_VALUE(kwargs[2 * i]);
Damien George2827d622014-04-27 15:50:52 +0100310 for (uint j = 0; j < self->n_pos_args + self->n_kwonly_args; j++) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200311 if (arg_name == self->args[j]) {
312 if (flat_args[j] != MP_OBJ_NULL) {
Damien Georgeea13f402014-04-05 18:32:08 +0100313 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200314 "function got multiple values for argument '%s'", qstr_str(arg_name)));
315 }
316 flat_args[j] = kwargs[2 * i + 1];
317 goto continue2;
318 }
319 }
320 // Didn't find name match with positional args
321 if (!self->takes_kw_args) {
Damien Georgeea13f402014-04-05 18:32:08 +0100322 nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments"));
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200323 }
Damien Georgee5d371b2014-02-16 00:17:42 +0000324 mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]);
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200325continue2:;
Damien Georgee5d371b2014-02-16 00:17:42 +0000326 }
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200327 DEBUG_printf("Args with kws flattened: ");
Damien George2827d622014-04-27 15:50:52 +0100328 dump_args(flat_args, self->n_pos_args + self->n_kwonly_args);
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200329
Damien George2827d622014-04-27 15:50:52 +0100330 // Now fill in defaults for positional args
331 mp_obj_t *d = &flat_args[self->n_pos_args - 1];
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200332 mp_obj_t *s = &self->extra_args[self->n_def_args - 1];
Paul Sokolovsky978607a2014-04-10 05:39:38 +0300333 for (int i = self->n_def_args; i > 0; i--, d--, s--) {
Damien George25f5a302014-03-03 23:25:08 +0000334 if (*d == MP_OBJ_NULL) {
Paul Sokolovsky978607a2014-04-10 05:39:38 +0300335 *d = *s;
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200336 }
337 }
338 DEBUG_printf("Args after filling defaults: ");
Damien George2827d622014-04-27 15:50:52 +0100339 dump_args(flat_args, self->n_pos_args + self->n_kwonly_args);
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200340
Damien George2827d622014-04-27 15:50:52 +0100341 // Check that all mandatory positional args are specified
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200342 while (d >= flat_args) {
343 if (*d-- == MP_OBJ_NULL) {
Damien Georgeea13f402014-04-05 18:32:08 +0100344 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200345 "function missing required positional argument #%d", d - flat_args));
346 }
347 }
348
Damien George2827d622014-04-27 15:50:52 +0100349 // Check that all mandatory keyword args are specified
350 for (int i = 0; i < self->n_kwonly_args; i++) {
351 if (flat_args[self->n_pos_args + i] == MP_OBJ_NULL) {
352 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
353 "function missing required keyword argument '%s'", qstr_str(self->args[self->n_pos_args + i])));
354 }
355 }
356
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200357 args = flat_args;
Damien George2827d622014-04-27 15:50:52 +0100358 n_args = self->n_pos_args + self->n_kwonly_args;
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200359
360 if (self->takes_kw_args) {
361 extra_args[n_extra_args] = dict;
362 n_extra_args += 1;
363 }
Damien Georgee5d371b2014-02-16 00:17:42 +0000364 } else {
365 // no keyword arguments given
Damien George2827d622014-04-27 15:50:52 +0100366 if (self->n_kwonly_args != 0) {
367 nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
368 "function missing keyword-only argument"));
369 }
Damien Georgee5d371b2014-02-16 00:17:42 +0000370 if (self->takes_kw_args) {
371 extra_args[n_extra_args] = mp_obj_new_dict(0);
372 n_extra_args += 1;
373 }
Damien George20006db2014-01-18 14:10:48 +0000374 }
Damiend99b0522013-12-21 18:17:45 +0000375
Damien George7efc5b32014-04-05 22:36:42 +0100376 mp_obj_dict_t *old_globals = mp_globals_get();
Damien Georged17926d2014-03-30 13:35:08 +0100377 mp_globals_set(self->globals);
Damien Georgec8f78bc2014-02-15 22:55:00 +0000378 mp_obj_t result;
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200379 DEBUG_printf("Calling: args=%p, n_args=%d, extra_args=%p, n_extra_args=%d\n", args, n_args, extra_args, n_extra_args);
380 dump_args(args, n_args);
381 dump_args(extra_args, n_extra_args);
Damien George3417bc22014-05-10 10:36:38 +0100382 mp_vm_return_kind_t vm_return_kind = mp_execute_bytecode(self->bytecode, args, n_args, extra_args, n_extra_args, &result);
Damien Georged17926d2014-03-30 13:35:08 +0100383 mp_globals_set(old_globals);
Damien Georgefb083ea2014-02-01 18:29:40 +0000384
Damien Georgec8f78bc2014-02-15 22:55:00 +0000385 if (vm_return_kind == MP_VM_RETURN_NORMAL) {
386 return result;
387 } else { // MP_VM_RETURN_EXCEPTION
Damien Georgeea13f402014-04-05 18:32:08 +0100388 nlr_raise(result);
Damien Georgec8f78bc2014-02-15 22:55:00 +0000389 }
Damiend99b0522013-12-21 18:17:45 +0000390}
391
Damien George3e1a5c12014-03-29 13:43:38 +0000392const mp_obj_type_t mp_type_fun_bc = {
Damien Georgec5966122014-02-15 16:10:44 +0000393 { &mp_type_type },
Damien Georgea71c83a2014-02-15 11:34:50 +0000394 .name = MP_QSTR_function,
Paul Sokolovsky68551a82014-05-01 01:32:58 +0300395#if MICROPY_CPYTHON_COMPAT
396 .print = fun_bc_print,
397#endif
Damien George20006db2014-01-18 14:10:48 +0000398 .call = fun_bc_call,
Paul Sokolovsky586bfce2014-04-05 13:50:06 +0300399 .binary_op = fun_binary_op,
Damiend99b0522013-12-21 18:17:45 +0000400};
401
Damien George2827d622014-04-27 15:50:52 +0100402mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n_kwonly_args, mp_obj_t def_args_in, const byte *code) {
Damien George2e482cd2014-02-16 00:01:29 +0000403 uint n_def_args = 0;
404 uint n_extra_args = 0;
Paul Sokolovsky90750022014-02-01 15:05:04 +0200405 mp_obj_tuple_t *def_args = def_args_in;
406 if (def_args != MP_OBJ_NULL) {
Damien George69b89d22014-04-11 13:38:30 +0000407 assert(MP_OBJ_IS_TYPE(def_args, &mp_type_tuple));
Paul Sokolovsky90750022014-02-01 15:05:04 +0200408 n_def_args = def_args->len;
Damien George2e482cd2014-02-16 00:01:29 +0000409 n_extra_args = def_args->len;
Paul Sokolovsky90750022014-02-01 15:05:04 +0200410 }
Damien George2e482cd2014-02-16 00:01:29 +0000411 if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
412 n_extra_args += 1;
413 }
Damien Georgee5d371b2014-02-16 00:17:42 +0000414 if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) {
415 n_extra_args += 1;
416 }
Damien George2e482cd2014-02-16 00:01:29 +0000417 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 +0000418 o->base.type = &mp_type_fun_bc;
Damien Georged17926d2014-03-30 13:35:08 +0100419 o->globals = mp_globals_get();
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200420 o->args = args;
Damien George2827d622014-04-27 15:50:52 +0100421 o->n_pos_args = n_pos_args;
422 o->n_kwonly_args = n_kwonly_args;
Paul Sokolovsky90750022014-02-01 15:05:04 +0200423 o->n_def_args = n_def_args;
Damien George2e482cd2014-02-16 00:01:29 +0000424 o->takes_var_args = (scope_flags & MP_SCOPE_FLAG_VARARGS) != 0;
425 o->takes_kw_args = (scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0;
Damien George66028ab2014-01-03 14:03:48 +0000426 o->bytecode = code;
Damien George2827d622014-04-27 15:50:52 +0100427 memset(o->extra_args, 0, n_extra_args * sizeof(mp_obj_t));
Paul Sokolovsky90750022014-02-01 15:05:04 +0200428 if (def_args != MP_OBJ_NULL) {
Damien George2e482cd2014-02-16 00:01:29 +0000429 memcpy(o->extra_args, def_args->items, n_def_args * sizeof(mp_obj_t));
Paul Sokolovsky90750022014-02-01 15:05:04 +0200430 }
Damien George2827d622014-04-27 15:50:52 +0100431 if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
432 o->extra_args[n_def_args] = MP_OBJ_NULL;
433 }
434 if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
435 o->extra_args[n_extra_args - 1] = MP_OBJ_NULL;
436 }
Damiend99b0522013-12-21 18:17:45 +0000437 return o;
438}
439
Damiend99b0522013-12-21 18:17:45 +0000440/******************************************************************************/
441/* inline assembler functions */
442
443typedef struct _mp_obj_fun_asm_t {
444 mp_obj_base_t base;
445 int n_args;
446 void *fun;
447} mp_obj_fun_asm_t;
448
449typedef machine_uint_t (*inline_asm_fun_0_t)();
450typedef machine_uint_t (*inline_asm_fun_1_t)(machine_uint_t);
451typedef machine_uint_t (*inline_asm_fun_2_t)(machine_uint_t, machine_uint_t);
452typedef machine_uint_t (*inline_asm_fun_3_t)(machine_uint_t, machine_uint_t, machine_uint_t);
453
454// convert a Micro Python object to a sensible value for inline asm
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200455STATIC machine_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
Damiend99b0522013-12-21 18:17:45 +0000456 // TODO for byte_array, pass pointer to the array
457 if (MP_OBJ_IS_SMALL_INT(obj)) {
458 return MP_OBJ_SMALL_INT_VALUE(obj);
459 } else if (obj == mp_const_none) {
460 return 0;
461 } else if (obj == mp_const_false) {
462 return 0;
463 } else if (obj == mp_const_true) {
464 return 1;
Damien George5fa93b62014-01-22 14:35:10 +0000465 } else if (MP_OBJ_IS_STR(obj)) {
Damiend99b0522013-12-21 18:17:45 +0000466 // pointer to the string (it's probably constant though!)
Damien George5fa93b62014-01-22 14:35:10 +0000467 uint l;
468 return (machine_uint_t)mp_obj_str_get_data(obj, &l);
Damiend99b0522013-12-21 18:17:45 +0000469 } else {
Damien George87210872014-04-13 00:30:32 +0100470 mp_obj_type_t *type = mp_obj_get_type(obj);
471 if (0) {
472#if MICROPY_ENABLE_FLOAT
473 } else if (type == &mp_type_float) {
474 // convert float to int (could also pass in float registers)
475 return (machine_int_t)mp_obj_float_get(obj);
476#endif
477 } else if (type == &mp_type_tuple) {
478 // pointer to start of tuple (could pass length, but then could use len(x) for that)
479 uint len;
480 mp_obj_t *items;
481 mp_obj_tuple_get(obj, &len, &items);
482 return (machine_uint_t)items;
483 } else if (type == &mp_type_list) {
484 // pointer to start of list (could pass length, but then could use len(x) for that)
485 uint len;
486 mp_obj_t *items;
487 mp_obj_list_get(obj, &len, &items);
488 return (machine_uint_t)items;
Damien George87210872014-04-13 00:30:32 +0100489 } else {
Damien George57a4b4f2014-04-18 22:29:21 +0100490 mp_buffer_info_t bufinfo;
Damien Georgeb11b85a2014-04-18 22:59:24 +0100491 if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_WRITE)) {
Damien George8a1cab92014-04-13 12:08:52 +0100492 // supports the buffer protocol, return a pointer to the data
493 return (machine_uint_t)bufinfo.buf;
494 } else {
495 // just pass along a pointer to the object
496 return (machine_uint_t)obj;
497 }
Damien George87210872014-04-13 00:30:32 +0100498 }
Damiend99b0522013-12-21 18:17:45 +0000499 }
500}
501
502// convert a return value from inline asm to a sensible Micro Python object
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200503STATIC mp_obj_t convert_val_from_inline_asm(machine_uint_t val) {
Damiend99b0522013-12-21 18:17:45 +0000504 return MP_OBJ_NEW_SMALL_INT(val);
505}
506
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200507STATIC 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 +0000508 mp_obj_fun_asm_t *self = self_in;
509
Damien Georgeccc85ea2014-05-10 13:40:46 +0100510 mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false);
Damiend99b0522013-12-21 18:17:45 +0000511
512 machine_uint_t ret;
513 if (n_args == 0) {
514 ret = ((inline_asm_fun_0_t)self->fun)();
515 } else if (n_args == 1) {
516 ret = ((inline_asm_fun_1_t)self->fun)(convert_obj_for_inline_asm(args[0]));
517 } else if (n_args == 2) {
Damien George20006db2014-01-18 14:10:48 +0000518 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 +0000519 } else if (n_args == 3) {
Damien George20006db2014-01-18 14:10:48 +0000520 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 +0000521 } else {
522 assert(0);
523 ret = 0;
524 }
525
526 return convert_val_from_inline_asm(ret);
527}
528
Damien George3e1a5c12014-03-29 13:43:38 +0000529STATIC const mp_obj_type_t mp_type_fun_asm = {
Damien Georgec5966122014-02-15 16:10:44 +0000530 { &mp_type_type },
Damien Georgea71c83a2014-02-15 11:34:50 +0000531 .name = MP_QSTR_function,
Damien George20006db2014-01-18 14:10:48 +0000532 .call = fun_asm_call,
Paul Sokolovsky586bfce2014-04-05 13:50:06 +0300533 .binary_op = fun_binary_op,
Damiend99b0522013-12-21 18:17:45 +0000534};
535
536mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun) {
537 mp_obj_fun_asm_t *o = m_new_obj(mp_obj_fun_asm_t);
Damien George3e1a5c12014-03-29 13:43:38 +0000538 o->base.type = &mp_type_fun_asm;
Damiend99b0522013-12-21 18:17:45 +0000539 o->n_args = n_args;
540 o->fun = fun;
541 return o;
542}