blob: 3b48b570fdd4bc59bb958563aa6f5adfaa0d12b8 [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"
Damien George2e482cd2014-02-16 00:01:29 +000012#include "runtime0.h"
Damiend99b0522013-12-21 18:17:45 +000013#include "runtime.h"
14#include "bc.h"
15
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +020016#if 0 // print debugging info
17#define DEBUG_PRINT (1)
18#else // don't print debugging info
Damien George41eb6082014-02-26 22:40:35 +000019#define DEBUG_printf(...) (void)0
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +020020#endif
21
Damiend99b0522013-12-21 18:17:45 +000022/******************************************************************************/
23/* native functions */
24
25// mp_obj_fun_native_t defined in obj.h
26
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +020027STATIC void check_nargs(mp_obj_fun_native_t *self, int n_args, int n_kw) {
Damien Georged17926d2014-03-30 13:35:08 +010028 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 -080029}
30
Damien Georged17926d2014-03-30 13:35:08 +010031void mp_check_nargs(int n_args, machine_uint_t n_args_min, machine_uint_t n_args_max, int n_kw, bool is_kw) {
Dave Hylands51dabac2014-02-17 17:57:13 -080032 if (n_kw && !is_kw) {
Damien Georgec5966122014-02-15 16:10:44 +000033 nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError,
John R. Lenton88cb1e62014-01-13 19:55:18 +000034 "function does not take keyword arguments"));
35 }
36
Dave Hylands51dabac2014-02-17 17:57:13 -080037 if (n_args_min == n_args_max) {
38 if (n_args != n_args_min) {
Damien Georgec5966122014-02-15 16:10:44 +000039 nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
John R. Lenton88cb1e62014-01-13 19:55:18 +000040 "function takes %d positional arguments but %d were given",
Dave Hylands51dabac2014-02-17 17:57:13 -080041 n_args_min, n_args));
John R. Lenton88cb1e62014-01-13 19:55:18 +000042 }
43 } else {
Dave Hylands51dabac2014-02-17 17:57:13 -080044 if (n_args < n_args_min) {
Damien Georgec5966122014-02-15 16:10:44 +000045 nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
John R. Lenton88cb1e62014-01-13 19:55:18 +000046 "<fun name>() missing %d required positional arguments: <list of names of params>",
Dave Hylands51dabac2014-02-17 17:57:13 -080047 n_args_min - n_args));
48 } else if (n_args > n_args_max) {
Damien Georgec5966122014-02-15 16:10:44 +000049 nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
John R. Lenton88cb1e62014-01-13 19:55:18 +000050 "<fun name> expected at most %d arguments, got %d",
Dave Hylands51dabac2014-02-17 17:57:13 -080051 n_args_max, n_args));
John R. Lenton88cb1e62014-01-13 19:55:18 +000052 }
53 }
54}
55
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +020056STATIC 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 +000057 assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_native));
Damiend99b0522013-12-21 18:17:45 +000058 mp_obj_fun_native_t *self = self_in;
Damien George20006db2014-01-18 14:10:48 +000059
John R. Lenton88cb1e62014-01-13 19:55:18 +000060 // check number of arguments
Damien George20006db2014-01-18 14:10:48 +000061 check_nargs(self, n_args, n_kw);
62
John R. Lentonc06763a2014-01-07 17:29:16 +000063 if (self->is_kw) {
Damien George20006db2014-01-18 14:10:48 +000064 // function allows keywords
65
Damien George0a587b82014-02-08 18:53:41 +000066 // we create a map directly from the given args array
67 mp_map_t kw_args;
68 mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
Damien George20006db2014-01-18 14:10:48 +000069
Damien George0a587b82014-02-08 18:53:41 +000070 return ((mp_fun_kw_t)self->fun)(n_args, args, &kw_args);
Damien George20006db2014-01-18 14:10:48 +000071
Paul Sokolovsky9d95a2b2014-01-26 01:58:51 +020072 } else if (self->n_args_min <= 3 && self->n_args_min == self->n_args_max) {
Damiend99b0522013-12-21 18:17:45 +000073 // function requires a fixed number of arguments
74
Damiend99b0522013-12-21 18:17:45 +000075 // dispatch function call
76 switch (self->n_args_min) {
77 case 0:
78 return ((mp_fun_0_t)self->fun)();
79
80 case 1:
81 return ((mp_fun_1_t)self->fun)(args[0]);
82
83 case 2:
Damien George20006db2014-01-18 14:10:48 +000084 return ((mp_fun_2_t)self->fun)(args[0], args[1]);
Damiend99b0522013-12-21 18:17:45 +000085
John R. Lenton45a87442014-01-04 01:15:01 +000086 case 3:
Damien George20006db2014-01-18 14:10:48 +000087 return ((mp_fun_3_t)self->fun)(args[0], args[1], args[2]);
John R. Lenton45a87442014-01-04 01:15:01 +000088
Damiend99b0522013-12-21 18:17:45 +000089 default:
90 assert(0);
91 return mp_const_none;
92 }
93
94 } else {
Damien George20006db2014-01-18 14:10:48 +000095 // function takes a variable number of arguments, but no keywords
Damiend99b0522013-12-21 18:17:45 +000096
Damien George20006db2014-01-18 14:10:48 +000097 return ((mp_fun_var_t)self->fun)(n_args, args);
Damiend99b0522013-12-21 18:17:45 +000098 }
99}
100
Damien George3e1a5c12014-03-29 13:43:38 +0000101const mp_obj_type_t mp_type_fun_native = {
Damien Georgec5966122014-02-15 16:10:44 +0000102 { &mp_type_type },
Damien Georgea71c83a2014-02-15 11:34:50 +0000103 .name = MP_QSTR_function,
Damien George20006db2014-01-18 14:10:48 +0000104 .call = fun_native_call,
Damiend99b0522013-12-21 18:17:45 +0000105};
106
Damien Georgef62d33a2014-01-13 19:50:05 +0000107// fun must have the correct signature for n_args fixed arguments
Damien Georged17926d2014-03-30 13:35:08 +0100108mp_obj_t mp_make_function_n(int n_args, void *fun) {
Damiend99b0522013-12-21 18:17:45 +0000109 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
Damien George3e1a5c12014-03-29 13:43:38 +0000110 o->base.type = &mp_type_fun_native;
Dave Hylands44332ec2014-01-13 08:42:43 -0800111 o->is_kw = false;
Damien Georgef62d33a2014-01-13 19:50:05 +0000112 o->n_args_min = n_args;
113 o->n_args_max = n_args;
John R. Lenton45a87442014-01-04 01:15:01 +0000114 o->fun = fun;
115 return o;
116}
117
Damien Georged17926d2014-03-30 13:35:08 +0100118mp_obj_t mp_make_function_var(int n_args_min, mp_fun_var_t 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;
Damiend99b0522013-12-21 18:17:45 +0000122 o->n_args_min = n_args_min;
Damien Georged5e81822014-02-26 17:47:05 +0000123 o->n_args_max = MP_OBJ_FUN_ARGS_MAX;
Damiend99b0522013-12-21 18:17:45 +0000124 o->fun = fun;
125 return o;
126}
127
128// min and max are inclusive
Damien Georged17926d2014-03-30 13:35:08 +0100129mp_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 +0000130 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
Damien George3e1a5c12014-03-29 13:43:38 +0000131 o->base.type = &mp_type_fun_native;
Dave Hylands44332ec2014-01-13 08:42:43 -0800132 o->is_kw = false;
Damiend99b0522013-12-21 18:17:45 +0000133 o->n_args_min = n_args_min;
134 o->n_args_max = n_args_max;
135 o->fun = fun;
136 return o;
137}
138
139/******************************************************************************/
140/* byte code functions */
141
142typedef struct _mp_obj_fun_bc_t {
143 mp_obj_base_t base;
Damien George66028ab2014-01-03 14:03:48 +0000144 mp_map_t *globals; // the context within which this function was defined
Damien George51047752014-02-26 17:40:52 +0000145 machine_uint_t n_args : 15; // number of arguments this function takes
146 machine_uint_t n_def_args : 15; // number of default arguments
147 machine_uint_t takes_var_args : 1; // set if this function takes variable args
148 machine_uint_t takes_kw_args : 1; // set if this function takes keyword args
Damien George66028ab2014-01-03 14:03:48 +0000149 const byte *bytecode; // bytecode for the function
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200150 qstr *args; // argument names (needed to resolve positional args passed as keywords)
Damien Georgee5d371b2014-02-16 00:17:42 +0000151 mp_obj_t extra_args[]; // values of default args (if any), plus a slot at the end for var args and/or kw args (if it takes them)
Damiend99b0522013-12-21 18:17:45 +0000152} mp_obj_fun_bc_t;
153
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200154#if DEBUG_PRINT
Damien Georgef78b6df2014-03-31 15:59:25 +0100155STATIC void dump_args(const mp_obj_t *a, int sz) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200156 DEBUG_printf("%p: ", a);
157 for (int i = 0; i < sz; i++) {
158 DEBUG_printf("%p ", a[i]);
159 }
160 DEBUG_printf("\n");
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200161}
Damien Georgef78b6df2014-03-31 15:59:25 +0100162#else
163#define dump_args(...) (void)0
164#endif
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200165
Paul Sokolovsky7fafb282014-03-30 20:21:28 +0300166// If it's possible to call a function without allocating new argument array,
167// this function returns true, together with pointers to 2 subarrays to be used
168// as arguments. Otherwise, it returns false. It is expected that this fucntion
169// will be accompanied by another, mp_obj_fun_prepare_full_args(), which will
170// instead take pointer to full-length out-array, and will fill it in. Rationale
171// being that a caller can try this function and if it succeeds, the function call
172// can be made without allocating extra memory. Otherwise, caller can allocate memory
173// and try "full" function. These functions are expected to be refactoring of
174// code in fun_bc_call() and evenrually replace it.
175bool mp_obj_fun_prepare_simple_args(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args,
176 uint *out_args1_len, const mp_obj_t **out_args1, uint *out_args2_len, const mp_obj_t **out_args2) {
177 mp_obj_fun_bc_t *self = self_in;
178
179 assert(n_kw == 0);
180 assert(self->takes_var_args == 0);
181 assert(self->takes_kw_args == 0);
182
183 mp_obj_t *extra_args = self->extra_args + self->n_def_args;
184 uint n_extra_args = 0;
185
186 if (n_args > self->n_args) {
187 goto arg_error;
188 } else {
189 extra_args -= self->n_args - n_args;
190 n_extra_args += self->n_args - n_args;
191 }
192 *out_args1 = args;
193 *out_args1_len = n_args;
194 *out_args2 = extra_args;
195 *out_args2_len = n_extra_args;
196 return true;
197
198arg_error:
199 nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", self->n_args, n_args));
200}
201
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200202STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200203 DEBUG_printf("Input: ");
204 dump_args(args, n_args);
Damiend99b0522013-12-21 18:17:45 +0000205 mp_obj_fun_bc_t *self = self_in;
206
Damien Georgee5d371b2014-02-16 00:17:42 +0000207 const mp_obj_t *kwargs = args + n_args;
Damien George2e482cd2014-02-16 00:01:29 +0000208 mp_obj_t *extra_args = self->extra_args + self->n_def_args;
209 uint n_extra_args = 0;
210
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200211
Damien Georgee5d371b2014-02-16 00:17:42 +0000212 // check positional arguments
213
Damien George2e482cd2014-02-16 00:01:29 +0000214 if (n_args > self->n_args) {
215 // given more than enough arguments
216 if (!self->takes_var_args) {
217 goto arg_error;
218 }
219 // put extra arguments in varargs tuple
220 *extra_args = mp_obj_new_tuple(n_args - self->n_args, args + self->n_args);
221 n_extra_args = 1;
222 n_args = self->n_args;
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200223 } else {
Damien George2e482cd2014-02-16 00:01:29 +0000224 if (self->takes_var_args) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200225 DEBUG_printf("passing empty tuple as *args\n");
Damien George2e482cd2014-02-16 00:01:29 +0000226 *extra_args = mp_const_empty_tuple;
227 n_extra_args = 1;
228 }
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200229 // Apply processing and check below only if we don't have kwargs,
230 // otherwise, kw handling code below has own extensive checks.
231 if (n_kw == 0) {
232 if (n_args >= self->n_args - self->n_def_args) {
233 // given enough arguments, but may need to use some default arguments
234 extra_args -= self->n_args - n_args;
235 n_extra_args += self->n_args - n_args;
236 } else {
237 goto arg_error;
238 }
239 }
Damiend99b0522013-12-21 18:17:45 +0000240 }
Damien George2e482cd2014-02-16 00:01:29 +0000241
Damien Georgee5d371b2014-02-16 00:17:42 +0000242 // check keyword arguments
243
Damien George20006db2014-01-18 14:10:48 +0000244 if (n_kw != 0) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200245 // We cannot use dynamically-sized array here, because GCC indeed
246 // deallocates it on leaving defining scope (unlike most static stack allocs).
247 // So, we have 2 choices: allocate it unconditionally at the top of function
248 // (wastes stack), or use alloca which is guaranteed to dealloc on func exit.
249 //mp_obj_t flat_args[self->n_args];
250 mp_obj_t *flat_args = alloca(self->n_args * sizeof(mp_obj_t));
251 for (int i = self->n_args - 1; i >= 0; i--) {
252 flat_args[i] = MP_OBJ_NULL;
Damien Georgee5d371b2014-02-16 00:17:42 +0000253 }
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200254 memcpy(flat_args, args, sizeof(*args) * n_args);
255 DEBUG_printf("Initial args: ");
256 dump_args(flat_args, self->n_args);
257
258 mp_obj_t dict = MP_OBJ_NULL;
259 if (self->takes_kw_args) {
260 dict = mp_obj_new_dict(n_kw); // TODO: better go conservative with 0?
261 }
Damien Georgee5d371b2014-02-16 00:17:42 +0000262 for (uint i = 0; i < n_kw; i++) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200263 qstr arg_name = MP_OBJ_QSTR_VALUE(kwargs[2 * i]);
264 for (uint j = 0; j < self->n_args; j++) {
265 if (arg_name == self->args[j]) {
266 if (flat_args[j] != MP_OBJ_NULL) {
267 nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
268 "function got multiple values for argument '%s'", qstr_str(arg_name)));
269 }
270 flat_args[j] = kwargs[2 * i + 1];
271 goto continue2;
272 }
273 }
274 // Didn't find name match with positional args
275 if (!self->takes_kw_args) {
276 nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments"));
277 }
Damien Georgee5d371b2014-02-16 00:17:42 +0000278 mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]);
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200279continue2:;
Damien Georgee5d371b2014-02-16 00:17:42 +0000280 }
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200281 DEBUG_printf("Args with kws flattened: ");
282 dump_args(flat_args, self->n_args);
283
284 // Now fill in defaults
285 mp_obj_t *d = &flat_args[self->n_args - 1];
286 mp_obj_t *s = &self->extra_args[self->n_def_args - 1];
287 for (int i = self->n_def_args; i > 0; i--) {
Damien George25f5a302014-03-03 23:25:08 +0000288 if (*d == MP_OBJ_NULL) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200289 *d-- = *s--;
290 }
291 }
292 DEBUG_printf("Args after filling defaults: ");
293 dump_args(flat_args, self->n_args);
294
295 // Now check that all mandatory args specified
296 while (d >= flat_args) {
297 if (*d-- == MP_OBJ_NULL) {
298 nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
299 "function missing required positional argument #%d", d - flat_args));
300 }
301 }
302
303 args = flat_args;
304 n_args = self->n_args;
305
306 if (self->takes_kw_args) {
307 extra_args[n_extra_args] = dict;
308 n_extra_args += 1;
309 }
Damien Georgee5d371b2014-02-16 00:17:42 +0000310 } else {
311 // no keyword arguments given
312 if (self->takes_kw_args) {
313 extra_args[n_extra_args] = mp_obj_new_dict(0);
314 n_extra_args += 1;
315 }
Damien George20006db2014-01-18 14:10:48 +0000316 }
Damiend99b0522013-12-21 18:17:45 +0000317
Damien Georged17926d2014-03-30 13:35:08 +0100318 mp_map_t *old_globals = mp_globals_get();
319 mp_globals_set(self->globals);
Damien Georgec8f78bc2014-02-15 22:55:00 +0000320 mp_obj_t result;
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200321 DEBUG_printf("Calling: args=%p, n_args=%d, extra_args=%p, n_extra_args=%d\n", args, n_args, extra_args, n_extra_args);
322 dump_args(args, n_args);
323 dump_args(extra_args, n_extra_args);
Damien Georgebee17b02014-03-27 11:07:04 +0000324 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 +0100325 mp_globals_set(old_globals);
Damien Georgefb083ea2014-02-01 18:29:40 +0000326
Damien Georgec8f78bc2014-02-15 22:55:00 +0000327 if (vm_return_kind == MP_VM_RETURN_NORMAL) {
328 return result;
329 } else { // MP_VM_RETURN_EXCEPTION
330 nlr_jump(result);
331 }
Damien George2e482cd2014-02-16 00:01:29 +0000332
333arg_error:
334 nlr_jump(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 +0000335}
336
Damien George3e1a5c12014-03-29 13:43:38 +0000337const mp_obj_type_t mp_type_fun_bc = {
Damien Georgec5966122014-02-15 16:10:44 +0000338 { &mp_type_type },
Damien Georgea71c83a2014-02-15 11:34:50 +0000339 .name = MP_QSTR_function,
Damien George20006db2014-01-18 14:10:48 +0000340 .call = fun_bc_call,
Damiend99b0522013-12-21 18:17:45 +0000341};
342
Damien Georgebee17b02014-03-27 11:07:04 +0000343mp_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 +0000344 uint n_def_args = 0;
345 uint n_extra_args = 0;
Paul Sokolovsky90750022014-02-01 15:05:04 +0200346 mp_obj_tuple_t *def_args = def_args_in;
347 if (def_args != MP_OBJ_NULL) {
348 n_def_args = def_args->len;
Damien George2e482cd2014-02-16 00:01:29 +0000349 n_extra_args = def_args->len;
Paul Sokolovsky90750022014-02-01 15:05:04 +0200350 }
Damien George2e482cd2014-02-16 00:01:29 +0000351 if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
352 n_extra_args += 1;
353 }
Damien Georgee5d371b2014-02-16 00:17:42 +0000354 if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) {
355 n_extra_args += 1;
356 }
Damien George2e482cd2014-02-16 00:01:29 +0000357 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 +0000358 o->base.type = &mp_type_fun_bc;
Damien Georged17926d2014-03-30 13:35:08 +0100359 o->globals = mp_globals_get();
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200360 o->args = args;
Damiend99b0522013-12-21 18:17:45 +0000361 o->n_args = n_args;
Paul Sokolovsky90750022014-02-01 15:05:04 +0200362 o->n_def_args = n_def_args;
Damien George2e482cd2014-02-16 00:01:29 +0000363 o->takes_var_args = (scope_flags & MP_SCOPE_FLAG_VARARGS) != 0;
364 o->takes_kw_args = (scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0;
Damien George66028ab2014-01-03 14:03:48 +0000365 o->bytecode = code;
Paul Sokolovsky90750022014-02-01 15:05:04 +0200366 if (def_args != MP_OBJ_NULL) {
Damien George2e482cd2014-02-16 00:01:29 +0000367 memcpy(o->extra_args, def_args->items, n_def_args * sizeof(mp_obj_t));
Paul Sokolovsky90750022014-02-01 15:05:04 +0200368 }
Damiend99b0522013-12-21 18:17:45 +0000369 return o;
370}
371
Damien Georgebee17b02014-03-27 11:07:04 +0000372void mp_obj_fun_bc_get(mp_obj_t self_in, int *n_args, const byte **code) {
Damien George3e1a5c12014-03-29 13:43:38 +0000373 assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_bc));
Damien George66028ab2014-01-03 14:03:48 +0000374 mp_obj_fun_bc_t *self = self_in;
375 *n_args = self->n_args;
Damien George66028ab2014-01-03 14:03:48 +0000376 *code = self->bytecode;
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#if MICROPY_ENABLE_FLOAT
Damien George0c36da02014-03-08 15:24:39 +0000409 } else if (MP_OBJ_IS_TYPE(obj, &mp_type_float)) {
Damiend99b0522013-12-21 18:17:45 +0000410 // convert float to int (could also pass in float registers)
411 return (machine_int_t)mp_obj_float_get(obj);
412#endif
Damien George07ddab52014-03-29 13:15:08 +0000413 } else if (MP_OBJ_IS_TYPE(obj, &mp_type_tuple)) {
Damiend99b0522013-12-21 18:17:45 +0000414 // pointer to start of tuple (could pass length, but then could use len(x) for that)
415 uint len;
416 mp_obj_t *items;
417 mp_obj_tuple_get(obj, &len, &items);
418 return (machine_uint_t)items;
Damien George3e1a5c12014-03-29 13:43:38 +0000419 } else if (MP_OBJ_IS_TYPE(obj, &mp_type_list)) {
Damiend99b0522013-12-21 18:17:45 +0000420 // pointer to start of list (could pass length, but then could use len(x) for that)
421 uint len;
422 mp_obj_t *items;
423 mp_obj_list_get(obj, &len, &items);
424 return (machine_uint_t)items;
425 } else {
426 // just pass along a pointer to the object
427 return (machine_uint_t)obj;
428 }
429}
430
431// convert a return value from inline asm to a sensible Micro Python object
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200432STATIC mp_obj_t convert_val_from_inline_asm(machine_uint_t val) {
Damiend99b0522013-12-21 18:17:45 +0000433 return MP_OBJ_NEW_SMALL_INT(val);
434}
435
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200436STATIC 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 +0000437 mp_obj_fun_asm_t *self = self_in;
438
439 if (n_args != self->n_args) {
Damien Georgec5966122014-02-15 16:10:44 +0000440 nlr_jump(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 +0000441 }
Damien George20006db2014-01-18 14:10:48 +0000442 if (n_kw != 0) {
Damien Georgec5966122014-02-15 16:10:44 +0000443 nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments"));
Damien George20006db2014-01-18 14:10:48 +0000444 }
Damiend99b0522013-12-21 18:17:45 +0000445
446 machine_uint_t ret;
447 if (n_args == 0) {
448 ret = ((inline_asm_fun_0_t)self->fun)();
449 } else if (n_args == 1) {
450 ret = ((inline_asm_fun_1_t)self->fun)(convert_obj_for_inline_asm(args[0]));
451 } else if (n_args == 2) {
Damien George20006db2014-01-18 14:10:48 +0000452 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 +0000453 } else if (n_args == 3) {
Damien George20006db2014-01-18 14:10:48 +0000454 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 +0000455 } else {
456 assert(0);
457 ret = 0;
458 }
459
460 return convert_val_from_inline_asm(ret);
461}
462
Damien George3e1a5c12014-03-29 13:43:38 +0000463STATIC const mp_obj_type_t mp_type_fun_asm = {
Damien Georgec5966122014-02-15 16:10:44 +0000464 { &mp_type_type },
Damien Georgea71c83a2014-02-15 11:34:50 +0000465 .name = MP_QSTR_function,
Damien George20006db2014-01-18 14:10:48 +0000466 .call = fun_asm_call,
Damiend99b0522013-12-21 18:17:45 +0000467};
468
469mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun) {
470 mp_obj_fun_asm_t *o = m_new_obj(mp_obj_fun_asm_t);
Damien George3e1a5c12014-03-29 13:43:38 +0000471 o->base.type = &mp_type_fun_asm;
Damiend99b0522013-12-21 18:17:45 +0000472 o->n_args = n_args;
473 o->fun = fun;
474 return o;
475}