blob: fa6a734d046bcd2190930b6a48bdd0cb0f333e67 [file] [log] [blame]
Damiend99b0522013-12-21 18:17:45 +00001#include <stdlib.h>
2#include <stdint.h>
3#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 George66028ab2014-01-03 14:03:48 +000012#include "map.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
20#define DEBUG_printf(args...) (void)0
21#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) {
Dave Hylands51dabac2014-02-17 17:57:13 -080029 rt_check_nargs(n_args, self->n_args_min, self->n_args_max, n_kw, self->is_kw);
30}
31
32void rt_check_nargs(int n_args, machine_uint_t n_args_min, machine_uint_t n_args_max, int n_kw, bool is_kw) {
33 if (n_kw && !is_kw) {
Damien Georgec5966122014-02-15 16:10:44 +000034 nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError,
John R. Lenton88cb1e62014-01-13 19:55:18 +000035 "function does not take keyword arguments"));
36 }
37
Dave Hylands51dabac2014-02-17 17:57:13 -080038 if (n_args_min == n_args_max) {
39 if (n_args != n_args_min) {
Damien Georgec5966122014-02-15 16:10:44 +000040 nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
John R. Lenton88cb1e62014-01-13 19:55:18 +000041 "function takes %d positional arguments but %d were given",
Dave Hylands51dabac2014-02-17 17:57:13 -080042 n_args_min, n_args));
John R. Lenton88cb1e62014-01-13 19:55:18 +000043 }
44 } else {
Dave Hylands51dabac2014-02-17 17:57:13 -080045 if (n_args < n_args_min) {
Damien Georgec5966122014-02-15 16:10:44 +000046 nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
John R. Lenton88cb1e62014-01-13 19:55:18 +000047 "<fun name>() missing %d required positional arguments: <list of names of params>",
Dave Hylands51dabac2014-02-17 17:57:13 -080048 n_args_min - n_args));
49 } else if (n_args > n_args_max) {
Damien Georgec5966122014-02-15 16:10:44 +000050 nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
John R. Lenton88cb1e62014-01-13 19:55:18 +000051 "<fun name> expected at most %d arguments, got %d",
Dave Hylands51dabac2014-02-17 17:57:13 -080052 n_args_max, n_args));
John R. Lenton88cb1e62014-01-13 19:55:18 +000053 }
54 }
55}
56
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +020057STATIC mp_obj_t fun_native_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
Damien George20006db2014-01-18 14:10:48 +000058 assert(MP_OBJ_IS_TYPE(self_in, &fun_native_type));
Damiend99b0522013-12-21 18:17:45 +000059 mp_obj_fun_native_t *self = self_in;
Damien George20006db2014-01-18 14:10:48 +000060
John R. Lenton88cb1e62014-01-13 19:55:18 +000061 // check number of arguments
Damien George20006db2014-01-18 14:10:48 +000062 check_nargs(self, n_args, n_kw);
63
John R. Lentonc06763a2014-01-07 17:29:16 +000064 if (self->is_kw) {
Damien George20006db2014-01-18 14:10:48 +000065 // function allows keywords
66
Damien George0a587b82014-02-08 18:53:41 +000067 // we create a map directly from the given args array
68 mp_map_t kw_args;
69 mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
Damien George20006db2014-01-18 14:10:48 +000070
Damien George0a587b82014-02-08 18:53:41 +000071 return ((mp_fun_kw_t)self->fun)(n_args, args, &kw_args);
Damien George20006db2014-01-18 14:10:48 +000072
Paul Sokolovsky9d95a2b2014-01-26 01:58:51 +020073 } else if (self->n_args_min <= 3 && self->n_args_min == self->n_args_max) {
Damiend99b0522013-12-21 18:17:45 +000074 // function requires a fixed number of arguments
75
Damiend99b0522013-12-21 18:17:45 +000076 // dispatch function call
77 switch (self->n_args_min) {
78 case 0:
79 return ((mp_fun_0_t)self->fun)();
80
81 case 1:
82 return ((mp_fun_1_t)self->fun)(args[0]);
83
84 case 2:
Damien George20006db2014-01-18 14:10:48 +000085 return ((mp_fun_2_t)self->fun)(args[0], args[1]);
Damiend99b0522013-12-21 18:17:45 +000086
John R. Lenton45a87442014-01-04 01:15:01 +000087 case 3:
Damien George20006db2014-01-18 14:10:48 +000088 return ((mp_fun_3_t)self->fun)(args[0], args[1], args[2]);
John R. Lenton45a87442014-01-04 01:15:01 +000089
Damiend99b0522013-12-21 18:17:45 +000090 default:
91 assert(0);
92 return mp_const_none;
93 }
94
95 } else {
Damien George20006db2014-01-18 14:10:48 +000096 // function takes a variable number of arguments, but no keywords
Damiend99b0522013-12-21 18:17:45 +000097
Damien George20006db2014-01-18 14:10:48 +000098 return ((mp_fun_var_t)self->fun)(n_args, args);
Damiend99b0522013-12-21 18:17:45 +000099 }
100}
101
102const mp_obj_type_t fun_native_type = {
Damien Georgec5966122014-02-15 16:10:44 +0000103 { &mp_type_type },
Damien Georgea71c83a2014-02-15 11:34:50 +0000104 .name = MP_QSTR_function,
Damien George20006db2014-01-18 14:10:48 +0000105 .call = fun_native_call,
Damiend99b0522013-12-21 18:17:45 +0000106};
107
Damien Georgef62d33a2014-01-13 19:50:05 +0000108// fun must have the correct signature for n_args fixed arguments
109mp_obj_t rt_make_function_n(int n_args, void *fun) {
Damiend99b0522013-12-21 18:17:45 +0000110 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
111 o->base.type = &fun_native_type;
Dave Hylands44332ec2014-01-13 08:42:43 -0800112 o->is_kw = false;
Damien Georgef62d33a2014-01-13 19:50:05 +0000113 o->n_args_min = n_args;
114 o->n_args_max = n_args;
John R. Lenton45a87442014-01-04 01:15:01 +0000115 o->fun = fun;
116 return o;
117}
118
Damiend99b0522013-12-21 18:17:45 +0000119mp_obj_t rt_make_function_var(int n_args_min, mp_fun_var_t fun) {
120 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
121 o->base.type = &fun_native_type;
Dave Hylands44332ec2014-01-13 08:42:43 -0800122 o->is_kw = false;
Damiend99b0522013-12-21 18:17:45 +0000123 o->n_args_min = n_args_min;
Damien Georged5e81822014-02-26 17:47:05 +0000124 o->n_args_max = MP_OBJ_FUN_ARGS_MAX;
Damiend99b0522013-12-21 18:17:45 +0000125 o->fun = fun;
126 return o;
127}
128
129// min and max are inclusive
130mp_obj_t rt_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var_t fun) {
131 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
132 o->base.type = &fun_native_type;
Dave Hylands44332ec2014-01-13 08:42:43 -0800133 o->is_kw = false;
Damiend99b0522013-12-21 18:17:45 +0000134 o->n_args_min = n_args_min;
135 o->n_args_max = n_args_max;
136 o->fun = fun;
137 return o;
138}
139
140/******************************************************************************/
141/* byte code functions */
142
143typedef struct _mp_obj_fun_bc_t {
144 mp_obj_base_t base;
Damien George66028ab2014-01-03 14:03:48 +0000145 mp_map_t *globals; // the context within which this function was defined
Damien George51047752014-02-26 17:40:52 +0000146 machine_uint_t n_args : 15; // number of arguments this function takes
147 machine_uint_t n_def_args : 15; // number of default arguments
148 machine_uint_t takes_var_args : 1; // set if this function takes variable args
149 machine_uint_t takes_kw_args : 1; // set if this function takes keyword args
Damien George66028ab2014-01-03 14:03:48 +0000150 uint n_state; // total state size for the executing function (incl args, locals, stack)
151 const byte *bytecode; // bytecode for the function
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200152 qstr *args; // argument names (needed to resolve positional args passed as keywords)
Damien Georgee5d371b2014-02-16 00:17:42 +0000153 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 +0000154} mp_obj_fun_bc_t;
155
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200156void dump_args(const mp_obj_t *a, int sz) {
157#if DEBUG_PRINT
158 DEBUG_printf("%p: ", a);
159 for (int i = 0; i < sz; i++) {
160 DEBUG_printf("%p ", a[i]);
161 }
162 DEBUG_printf("\n");
163#endif
164}
165
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200166STATIC 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 +0200167 DEBUG_printf("Input: ");
168 dump_args(args, n_args);
Damiend99b0522013-12-21 18:17:45 +0000169 mp_obj_fun_bc_t *self = self_in;
170
Damien Georgee5d371b2014-02-16 00:17:42 +0000171 const mp_obj_t *kwargs = args + n_args;
Damien George2e482cd2014-02-16 00:01:29 +0000172 mp_obj_t *extra_args = self->extra_args + self->n_def_args;
173 uint n_extra_args = 0;
174
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200175
Damien Georgee5d371b2014-02-16 00:17:42 +0000176 // check positional arguments
177
Damien George2e482cd2014-02-16 00:01:29 +0000178 if (n_args > self->n_args) {
179 // given more than enough arguments
180 if (!self->takes_var_args) {
181 goto arg_error;
182 }
183 // put extra arguments in varargs tuple
184 *extra_args = mp_obj_new_tuple(n_args - self->n_args, args + self->n_args);
185 n_extra_args = 1;
186 n_args = self->n_args;
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200187 } else {
Damien George2e482cd2014-02-16 00:01:29 +0000188 if (self->takes_var_args) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200189 DEBUG_printf("passing empty tuple as *args\n");
Damien George2e482cd2014-02-16 00:01:29 +0000190 *extra_args = mp_const_empty_tuple;
191 n_extra_args = 1;
192 }
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200193 // Apply processing and check below only if we don't have kwargs,
194 // otherwise, kw handling code below has own extensive checks.
195 if (n_kw == 0) {
196 if (n_args >= self->n_args - self->n_def_args) {
197 // given enough arguments, but may need to use some default arguments
198 extra_args -= self->n_args - n_args;
199 n_extra_args += self->n_args - n_args;
200 } else {
201 goto arg_error;
202 }
203 }
Damiend99b0522013-12-21 18:17:45 +0000204 }
Damien George2e482cd2014-02-16 00:01:29 +0000205
Damien Georgee5d371b2014-02-16 00:17:42 +0000206 // check keyword arguments
207
Damien George20006db2014-01-18 14:10:48 +0000208 if (n_kw != 0) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200209 // We cannot use dynamically-sized array here, because GCC indeed
210 // deallocates it on leaving defining scope (unlike most static stack allocs).
211 // So, we have 2 choices: allocate it unconditionally at the top of function
212 // (wastes stack), or use alloca which is guaranteed to dealloc on func exit.
213 //mp_obj_t flat_args[self->n_args];
214 mp_obj_t *flat_args = alloca(self->n_args * sizeof(mp_obj_t));
215 for (int i = self->n_args - 1; i >= 0; i--) {
216 flat_args[i] = MP_OBJ_NULL;
Damien Georgee5d371b2014-02-16 00:17:42 +0000217 }
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200218 memcpy(flat_args, args, sizeof(*args) * n_args);
219 DEBUG_printf("Initial args: ");
220 dump_args(flat_args, self->n_args);
221
222 mp_obj_t dict = MP_OBJ_NULL;
223 if (self->takes_kw_args) {
224 dict = mp_obj_new_dict(n_kw); // TODO: better go conservative with 0?
225 }
Damien Georgee5d371b2014-02-16 00:17:42 +0000226 for (uint i = 0; i < n_kw; i++) {
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200227 qstr arg_name = MP_OBJ_QSTR_VALUE(kwargs[2 * i]);
228 for (uint j = 0; j < self->n_args; j++) {
229 if (arg_name == self->args[j]) {
230 if (flat_args[j] != MP_OBJ_NULL) {
231 nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
232 "function got multiple values for argument '%s'", qstr_str(arg_name)));
233 }
234 flat_args[j] = kwargs[2 * i + 1];
235 goto continue2;
236 }
237 }
238 // Didn't find name match with positional args
239 if (!self->takes_kw_args) {
240 nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments"));
241 }
Damien Georgee5d371b2014-02-16 00:17:42 +0000242 mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]);
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200243continue2:;
Damien Georgee5d371b2014-02-16 00:17:42 +0000244 }
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200245 DEBUG_printf("Args with kws flattened: ");
246 dump_args(flat_args, self->n_args);
247
248 // Now fill in defaults
249 mp_obj_t *d = &flat_args[self->n_args - 1];
250 mp_obj_t *s = &self->extra_args[self->n_def_args - 1];
251 for (int i = self->n_def_args; i > 0; i--) {
252 if (*d != MP_OBJ_NULL) {
253 *d-- = *s--;
254 }
255 }
256 DEBUG_printf("Args after filling defaults: ");
257 dump_args(flat_args, self->n_args);
258
259 // Now check that all mandatory args specified
260 while (d >= flat_args) {
261 if (*d-- == MP_OBJ_NULL) {
262 nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
263 "function missing required positional argument #%d", d - flat_args));
264 }
265 }
266
267 args = flat_args;
268 n_args = self->n_args;
269
270 if (self->takes_kw_args) {
271 extra_args[n_extra_args] = dict;
272 n_extra_args += 1;
273 }
Damien Georgee5d371b2014-02-16 00:17:42 +0000274 } else {
275 // no keyword arguments given
276 if (self->takes_kw_args) {
277 extra_args[n_extra_args] = mp_obj_new_dict(0);
278 n_extra_args += 1;
279 }
Damien George20006db2014-01-18 14:10:48 +0000280 }
Damiend99b0522013-12-21 18:17:45 +0000281
Damien George66028ab2014-01-03 14:03:48 +0000282 mp_map_t *old_globals = rt_globals_get();
Damien Georgefb083ea2014-02-01 18:29:40 +0000283 rt_globals_set(self->globals);
Damien Georgec8f78bc2014-02-15 22:55:00 +0000284 mp_obj_t result;
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200285 DEBUG_printf("Calling: args=%p, n_args=%d, extra_args=%p, n_extra_args=%d\n", args, n_args, extra_args, n_extra_args);
286 dump_args(args, n_args);
287 dump_args(extra_args, n_extra_args);
Damien George2e482cd2014-02-16 00:01:29 +0000288 mp_vm_return_kind_t vm_return_kind = mp_execute_byte_code(self->bytecode, args, n_args, extra_args, n_extra_args, self->n_state, &result);
Damien Georgefb083ea2014-02-01 18:29:40 +0000289 rt_globals_set(old_globals);
290
Damien Georgec8f78bc2014-02-15 22:55:00 +0000291 if (vm_return_kind == MP_VM_RETURN_NORMAL) {
292 return result;
293 } else { // MP_VM_RETURN_EXCEPTION
294 nlr_jump(result);
295 }
Damien George2e482cd2014-02-16 00:01:29 +0000296
297arg_error:
298 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 +0000299}
300
301const mp_obj_type_t fun_bc_type = {
Damien Georgec5966122014-02-15 16:10:44 +0000302 { &mp_type_type },
Damien Georgea71c83a2014-02-15 11:34:50 +0000303 .name = MP_QSTR_function,
Damien George20006db2014-01-18 14:10:48 +0000304 .call = fun_bc_call,
Damiend99b0522013-12-21 18:17:45 +0000305};
306
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200307mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_args, mp_obj_t def_args_in, uint n_state, const byte *code) {
Damien George2e482cd2014-02-16 00:01:29 +0000308 uint n_def_args = 0;
309 uint n_extra_args = 0;
Paul Sokolovsky90750022014-02-01 15:05:04 +0200310 mp_obj_tuple_t *def_args = def_args_in;
311 if (def_args != MP_OBJ_NULL) {
312 n_def_args = def_args->len;
Damien George2e482cd2014-02-16 00:01:29 +0000313 n_extra_args = def_args->len;
Paul Sokolovsky90750022014-02-01 15:05:04 +0200314 }
Damien George2e482cd2014-02-16 00:01:29 +0000315 if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
316 n_extra_args += 1;
317 }
Damien Georgee5d371b2014-02-16 00:17:42 +0000318 if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) {
319 n_extra_args += 1;
320 }
Damien George2e482cd2014-02-16 00:01:29 +0000321 mp_obj_fun_bc_t *o = m_new_obj_var(mp_obj_fun_bc_t, mp_obj_t, n_extra_args);
Damiend99b0522013-12-21 18:17:45 +0000322 o->base.type = &fun_bc_type;
Damien George66028ab2014-01-03 14:03:48 +0000323 o->globals = rt_globals_get();
Paul Sokolovskyac2e28c2014-02-16 18:30:49 +0200324 o->args = args;
Damiend99b0522013-12-21 18:17:45 +0000325 o->n_args = n_args;
Paul Sokolovsky90750022014-02-01 15:05:04 +0200326 o->n_def_args = n_def_args;
Damien George2e482cd2014-02-16 00:01:29 +0000327 o->takes_var_args = (scope_flags & MP_SCOPE_FLAG_VARARGS) != 0;
328 o->takes_kw_args = (scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0;
Damiend99b0522013-12-21 18:17:45 +0000329 o->n_state = n_state;
Damien George66028ab2014-01-03 14:03:48 +0000330 o->bytecode = code;
Paul Sokolovsky90750022014-02-01 15:05:04 +0200331 if (def_args != MP_OBJ_NULL) {
Damien George2e482cd2014-02-16 00:01:29 +0000332 memcpy(o->extra_args, def_args->items, n_def_args * sizeof(mp_obj_t));
Paul Sokolovsky90750022014-02-01 15:05:04 +0200333 }
Damiend99b0522013-12-21 18:17:45 +0000334 return o;
335}
336
Damien George66028ab2014-01-03 14:03:48 +0000337void mp_obj_fun_bc_get(mp_obj_t self_in, int *n_args, uint *n_state, const byte **code) {
338 assert(MP_OBJ_IS_TYPE(self_in, &fun_bc_type));
339 mp_obj_fun_bc_t *self = self_in;
340 *n_args = self->n_args;
341 *n_state = self->n_state;
342 *code = self->bytecode;
343}
344
Damiend99b0522013-12-21 18:17:45 +0000345/******************************************************************************/
346/* inline assembler functions */
347
348typedef struct _mp_obj_fun_asm_t {
349 mp_obj_base_t base;
350 int n_args;
351 void *fun;
352} mp_obj_fun_asm_t;
353
354typedef machine_uint_t (*inline_asm_fun_0_t)();
355typedef machine_uint_t (*inline_asm_fun_1_t)(machine_uint_t);
356typedef machine_uint_t (*inline_asm_fun_2_t)(machine_uint_t, machine_uint_t);
357typedef machine_uint_t (*inline_asm_fun_3_t)(machine_uint_t, machine_uint_t, machine_uint_t);
358
359// convert a Micro Python object to a sensible value for inline asm
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200360STATIC machine_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
Damiend99b0522013-12-21 18:17:45 +0000361 // TODO for byte_array, pass pointer to the array
362 if (MP_OBJ_IS_SMALL_INT(obj)) {
363 return MP_OBJ_SMALL_INT_VALUE(obj);
364 } else if (obj == mp_const_none) {
365 return 0;
366 } else if (obj == mp_const_false) {
367 return 0;
368 } else if (obj == mp_const_true) {
369 return 1;
Damien George5fa93b62014-01-22 14:35:10 +0000370 } else if (MP_OBJ_IS_STR(obj)) {
Damiend99b0522013-12-21 18:17:45 +0000371 // pointer to the string (it's probably constant though!)
Damien George5fa93b62014-01-22 14:35:10 +0000372 uint l;
373 return (machine_uint_t)mp_obj_str_get_data(obj, &l);
Damiend99b0522013-12-21 18:17:45 +0000374#if MICROPY_ENABLE_FLOAT
375 } else if (MP_OBJ_IS_TYPE(obj, &float_type)) {
376 // convert float to int (could also pass in float registers)
377 return (machine_int_t)mp_obj_float_get(obj);
378#endif
379 } else if (MP_OBJ_IS_TYPE(obj, &tuple_type)) {
380 // pointer to start of tuple (could pass length, but then could use len(x) for that)
381 uint len;
382 mp_obj_t *items;
383 mp_obj_tuple_get(obj, &len, &items);
384 return (machine_uint_t)items;
385 } else if (MP_OBJ_IS_TYPE(obj, &list_type)) {
386 // pointer to start of list (could pass length, but then could use len(x) for that)
387 uint len;
388 mp_obj_t *items;
389 mp_obj_list_get(obj, &len, &items);
390 return (machine_uint_t)items;
391 } else {
392 // just pass along a pointer to the object
393 return (machine_uint_t)obj;
394 }
395}
396
397// convert a return value from inline asm to a sensible Micro Python object
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200398STATIC mp_obj_t convert_val_from_inline_asm(machine_uint_t val) {
Damiend99b0522013-12-21 18:17:45 +0000399 return MP_OBJ_NEW_SMALL_INT(val);
400}
401
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200402STATIC 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 +0000403 mp_obj_fun_asm_t *self = self_in;
404
405 if (n_args != self->n_args) {
Damien Georgec5966122014-02-15 16:10:44 +0000406 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 +0000407 }
Damien George20006db2014-01-18 14:10:48 +0000408 if (n_kw != 0) {
Damien Georgec5966122014-02-15 16:10:44 +0000409 nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments"));
Damien George20006db2014-01-18 14:10:48 +0000410 }
Damiend99b0522013-12-21 18:17:45 +0000411
412 machine_uint_t ret;
413 if (n_args == 0) {
414 ret = ((inline_asm_fun_0_t)self->fun)();
415 } else if (n_args == 1) {
416 ret = ((inline_asm_fun_1_t)self->fun)(convert_obj_for_inline_asm(args[0]));
417 } else if (n_args == 2) {
Damien George20006db2014-01-18 14:10:48 +0000418 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 +0000419 } else if (n_args == 3) {
Damien George20006db2014-01-18 14:10:48 +0000420 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 +0000421 } else {
422 assert(0);
423 ret = 0;
424 }
425
426 return convert_val_from_inline_asm(ret);
427}
428
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200429STATIC const mp_obj_type_t fun_asm_type = {
Damien Georgec5966122014-02-15 16:10:44 +0000430 { &mp_type_type },
Damien Georgea71c83a2014-02-15 11:34:50 +0000431 .name = MP_QSTR_function,
Damien George20006db2014-01-18 14:10:48 +0000432 .call = fun_asm_call,
Damiend99b0522013-12-21 18:17:45 +0000433};
434
435mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun) {
436 mp_obj_fun_asm_t *o = m_new_obj(mp_obj_fun_asm_t);
437 o->base.type = &fun_asm_type;
438 o->n_args = n_args;
439 o->fun = fun;
440 return o;
441}