blob: fbc0cab118cd0efadaa103d105598add0ba6f96b [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"
Damiend99b0522013-12-21 18:17:45 +000013#include "runtime.h"
14#include "bc.h"
15
16/******************************************************************************/
17/* native functions */
18
19// mp_obj_fun_native_t defined in obj.h
20
John R. Lenton88cb1e62014-01-13 19:55:18 +000021void check_nargs(mp_obj_fun_native_t *self, int n_args, int n_kw) {
22 if (n_kw && !self->is_kw) {
23 nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError,
24 "function does not take keyword arguments"));
25 }
26
27 if (self->n_args_min == self->n_args_max) {
28 if (n_args != self->n_args_min) {
29 nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError,
30 "function takes %d positional arguments but %d were given",
31 (const char*)(machine_int_t)self->n_args_min,
32 (const char*)(machine_int_t)n_args));
33 }
34 } else {
35 if (n_args < self->n_args_min) {
36 nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError,
37 "<fun name>() missing %d required positional arguments: <list of names of params>",
38 (const char*)(machine_int_t)(self->n_args_min - n_args)));
39 } else if (n_args > self->n_args_max) {
40 nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError,
41 "<fun name> expected at most %d arguments, got %d",
42 (void*)(machine_int_t)self->n_args_max, (void*)(machine_int_t)n_args));
43 }
44 }
45}
46
Damien George20006db2014-01-18 14:10:48 +000047mp_obj_t fun_native_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
48 assert(MP_OBJ_IS_TYPE(self_in, &fun_native_type));
Damiend99b0522013-12-21 18:17:45 +000049 mp_obj_fun_native_t *self = self_in;
Damien George20006db2014-01-18 14:10:48 +000050
John R. Lenton88cb1e62014-01-13 19:55:18 +000051 // check number of arguments
Damien George20006db2014-01-18 14:10:48 +000052 check_nargs(self, n_args, n_kw);
53
John R. Lentonc06763a2014-01-07 17:29:16 +000054 if (self->is_kw) {
Damien George20006db2014-01-18 14:10:48 +000055 // function allows keywords
56
57 // TODO if n_kw==0 then don't allocate any memory for map (either pass NULL or allocate it on the heap)
58 mp_map_t *kw_args = mp_map_new(n_kw);
59 for (int i = 0; i < 2 * n_kw; i += 2) {
Damien George5fa93b62014-01-22 14:35:10 +000060 mp_map_lookup(kw_args, args[n_args + i], MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = args[n_args + i + 1];
Damien George20006db2014-01-18 14:10:48 +000061 }
62 mp_obj_t res = ((mp_fun_kw_t)self->fun)(n_args, args, kw_args);
63 // TODO clean up kw_args
64
65 return res;
66
Paul Sokolovsky9d95a2b2014-01-26 01:58:51 +020067 } else if (self->n_args_min <= 3 && self->n_args_min == self->n_args_max) {
Damiend99b0522013-12-21 18:17:45 +000068 // function requires a fixed number of arguments
69
Damiend99b0522013-12-21 18:17:45 +000070 // dispatch function call
71 switch (self->n_args_min) {
72 case 0:
73 return ((mp_fun_0_t)self->fun)();
74
75 case 1:
76 return ((mp_fun_1_t)self->fun)(args[0]);
77
78 case 2:
Damien George20006db2014-01-18 14:10:48 +000079 return ((mp_fun_2_t)self->fun)(args[0], args[1]);
Damiend99b0522013-12-21 18:17:45 +000080
John R. Lenton45a87442014-01-04 01:15:01 +000081 case 3:
Damien George20006db2014-01-18 14:10:48 +000082 return ((mp_fun_3_t)self->fun)(args[0], args[1], args[2]);
John R. Lenton45a87442014-01-04 01:15:01 +000083
Damiend99b0522013-12-21 18:17:45 +000084 default:
85 assert(0);
86 return mp_const_none;
87 }
88
89 } else {
Damien George20006db2014-01-18 14:10:48 +000090 // function takes a variable number of arguments, but no keywords
Damiend99b0522013-12-21 18:17:45 +000091
Damien George20006db2014-01-18 14:10:48 +000092 return ((mp_fun_var_t)self->fun)(n_args, args);
Damiend99b0522013-12-21 18:17:45 +000093 }
94}
95
96const mp_obj_type_t fun_native_type = {
97 { &mp_const_type },
98 "function",
Damien George20006db2014-01-18 14:10:48 +000099 .call = fun_native_call,
Damiend99b0522013-12-21 18:17:45 +0000100};
101
Damien Georgef62d33a2014-01-13 19:50:05 +0000102// fun must have the correct signature for n_args fixed arguments
103mp_obj_t rt_make_function_n(int n_args, void *fun) {
Damiend99b0522013-12-21 18:17:45 +0000104 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
105 o->base.type = &fun_native_type;
Dave Hylands44332ec2014-01-13 08:42:43 -0800106 o->is_kw = false;
Damien Georgef62d33a2014-01-13 19:50:05 +0000107 o->n_args_min = n_args;
108 o->n_args_max = n_args;
John R. Lenton45a87442014-01-04 01:15:01 +0000109 o->fun = fun;
110 return o;
111}
112
Damiend99b0522013-12-21 18:17:45 +0000113mp_obj_t rt_make_function_var(int n_args_min, mp_fun_var_t fun) {
114 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
115 o->base.type = &fun_native_type;
Dave Hylands44332ec2014-01-13 08:42:43 -0800116 o->is_kw = false;
Damiend99b0522013-12-21 18:17:45 +0000117 o->n_args_min = n_args_min;
118 o->n_args_max = ~((machine_uint_t)0);
119 o->fun = fun;
120 return o;
121}
122
123// min and max are inclusive
124mp_obj_t rt_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var_t fun) {
125 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
126 o->base.type = &fun_native_type;
Dave Hylands44332ec2014-01-13 08:42:43 -0800127 o->is_kw = false;
Damiend99b0522013-12-21 18:17:45 +0000128 o->n_args_min = n_args_min;
129 o->n_args_max = n_args_max;
130 o->fun = fun;
131 return o;
132}
133
134/******************************************************************************/
135/* byte code functions */
136
137typedef struct _mp_obj_fun_bc_t {
138 mp_obj_base_t base;
Damien George66028ab2014-01-03 14:03:48 +0000139 mp_map_t *globals; // the context within which this function was defined
Paul Sokolovsky90750022014-02-01 15:05:04 +0200140 short n_args; // number of arguments this function takes
141 short n_def_args; // number of default arguments
Damien George66028ab2014-01-03 14:03:48 +0000142 uint n_state; // total state size for the executing function (incl args, locals, stack)
143 const byte *bytecode; // bytecode for the function
Paul Sokolovsky90750022014-02-01 15:05:04 +0200144 mp_obj_t def_args[]; // values of default args, if any
Damiend99b0522013-12-21 18:17:45 +0000145} mp_obj_fun_bc_t;
146
Damien George20006db2014-01-18 14:10:48 +0000147mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
Damiend99b0522013-12-21 18:17:45 +0000148 mp_obj_fun_bc_t *self = self_in;
149
Paul Sokolovsky90750022014-02-01 15:05:04 +0200150 if (n_args < self->n_args - self->n_def_args || n_args > self->n_args) {
Damien Georgeeb7bfcb2014-01-04 15:57:35 +0000151 nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError, "function takes %d positional arguments but %d were given", (const char*)(machine_int_t)self->n_args, (const char*)(machine_int_t)n_args));
Damiend99b0522013-12-21 18:17:45 +0000152 }
Damien George20006db2014-01-18 14:10:48 +0000153 if (n_kw != 0) {
154 nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "function does not take keyword arguments"));
155 }
Damiend99b0522013-12-21 18:17:45 +0000156
Damien Georgefb083ea2014-02-01 18:29:40 +0000157 uint use_def_args = self->n_args - n_args;
Damien George66028ab2014-01-03 14:03:48 +0000158 mp_map_t *old_globals = rt_globals_get();
Damien Georgefb083ea2014-02-01 18:29:40 +0000159 rt_globals_set(self->globals);
160 mp_obj_t result = mp_execute_byte_code(self->bytecode, args, n_args, self->def_args + self->n_def_args - use_def_args, use_def_args, self->n_state);
161 rt_globals_set(old_globals);
162
163 return result;
Damiend99b0522013-12-21 18:17:45 +0000164}
165
166const mp_obj_type_t fun_bc_type = {
167 { &mp_const_type },
168 "function",
Damien George20006db2014-01-18 14:10:48 +0000169 .call = fun_bc_call,
Damiend99b0522013-12-21 18:17:45 +0000170};
171
Paul Sokolovsky90750022014-02-01 15:05:04 +0200172mp_obj_t mp_obj_new_fun_bc(int n_args, mp_obj_t def_args_in, uint n_state, const byte *code) {
173 int n_def_args = 0;
174 mp_obj_tuple_t *def_args = def_args_in;
175 if (def_args != MP_OBJ_NULL) {
176 n_def_args = def_args->len;
177 }
178 mp_obj_fun_bc_t *o = m_new_obj_var(mp_obj_fun_bc_t, mp_obj_t, n_def_args);
Damiend99b0522013-12-21 18:17:45 +0000179 o->base.type = &fun_bc_type;
Damien George66028ab2014-01-03 14:03:48 +0000180 o->globals = rt_globals_get();
Damiend99b0522013-12-21 18:17:45 +0000181 o->n_args = n_args;
Paul Sokolovsky90750022014-02-01 15:05:04 +0200182 o->n_def_args = n_def_args;
Damiend99b0522013-12-21 18:17:45 +0000183 o->n_state = n_state;
Damien George66028ab2014-01-03 14:03:48 +0000184 o->bytecode = code;
Paul Sokolovsky90750022014-02-01 15:05:04 +0200185 if (def_args != MP_OBJ_NULL) {
186 memcpy(o->def_args, def_args->items, n_def_args * sizeof(*o->def_args));
187 }
Damiend99b0522013-12-21 18:17:45 +0000188 return o;
189}
190
Damien George66028ab2014-01-03 14:03:48 +0000191void mp_obj_fun_bc_get(mp_obj_t self_in, int *n_args, uint *n_state, const byte **code) {
192 assert(MP_OBJ_IS_TYPE(self_in, &fun_bc_type));
193 mp_obj_fun_bc_t *self = self_in;
194 *n_args = self->n_args;
195 *n_state = self->n_state;
196 *code = self->bytecode;
197}
198
Damiend99b0522013-12-21 18:17:45 +0000199/******************************************************************************/
200/* inline assembler functions */
201
202typedef struct _mp_obj_fun_asm_t {
203 mp_obj_base_t base;
204 int n_args;
205 void *fun;
206} mp_obj_fun_asm_t;
207
208typedef machine_uint_t (*inline_asm_fun_0_t)();
209typedef machine_uint_t (*inline_asm_fun_1_t)(machine_uint_t);
210typedef machine_uint_t (*inline_asm_fun_2_t)(machine_uint_t, machine_uint_t);
211typedef machine_uint_t (*inline_asm_fun_3_t)(machine_uint_t, machine_uint_t, machine_uint_t);
212
213// convert a Micro Python object to a sensible value for inline asm
214machine_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
215 // TODO for byte_array, pass pointer to the array
216 if (MP_OBJ_IS_SMALL_INT(obj)) {
217 return MP_OBJ_SMALL_INT_VALUE(obj);
218 } else if (obj == mp_const_none) {
219 return 0;
220 } else if (obj == mp_const_false) {
221 return 0;
222 } else if (obj == mp_const_true) {
223 return 1;
Damien George5fa93b62014-01-22 14:35:10 +0000224 } else if (MP_OBJ_IS_STR(obj)) {
Damiend99b0522013-12-21 18:17:45 +0000225 // pointer to the string (it's probably constant though!)
Damien George5fa93b62014-01-22 14:35:10 +0000226 uint l;
227 return (machine_uint_t)mp_obj_str_get_data(obj, &l);
Damiend99b0522013-12-21 18:17:45 +0000228#if MICROPY_ENABLE_FLOAT
229 } else if (MP_OBJ_IS_TYPE(obj, &float_type)) {
230 // convert float to int (could also pass in float registers)
231 return (machine_int_t)mp_obj_float_get(obj);
232#endif
233 } else if (MP_OBJ_IS_TYPE(obj, &tuple_type)) {
234 // pointer to start of tuple (could pass length, but then could use len(x) for that)
235 uint len;
236 mp_obj_t *items;
237 mp_obj_tuple_get(obj, &len, &items);
238 return (machine_uint_t)items;
239 } else if (MP_OBJ_IS_TYPE(obj, &list_type)) {
240 // pointer to start of list (could pass length, but then could use len(x) for that)
241 uint len;
242 mp_obj_t *items;
243 mp_obj_list_get(obj, &len, &items);
244 return (machine_uint_t)items;
245 } else {
246 // just pass along a pointer to the object
247 return (machine_uint_t)obj;
248 }
249}
250
251// convert a return value from inline asm to a sensible Micro Python object
252mp_obj_t convert_val_from_inline_asm(machine_uint_t val) {
253 return MP_OBJ_NEW_SMALL_INT(val);
254}
255
Damien George20006db2014-01-18 14:10:48 +0000256mp_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 +0000257 mp_obj_fun_asm_t *self = self_in;
258
259 if (n_args != self->n_args) {
Damien Georgeeb7bfcb2014-01-04 15:57:35 +0000260 nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError, "function takes %d positional arguments but %d were given", (const char*)(machine_int_t)self->n_args, (const char*)(machine_int_t)n_args));
Damiend99b0522013-12-21 18:17:45 +0000261 }
Damien George20006db2014-01-18 14:10:48 +0000262 if (n_kw != 0) {
263 nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "function does not take keyword arguments"));
264 }
Damiend99b0522013-12-21 18:17:45 +0000265
266 machine_uint_t ret;
267 if (n_args == 0) {
268 ret = ((inline_asm_fun_0_t)self->fun)();
269 } else if (n_args == 1) {
270 ret = ((inline_asm_fun_1_t)self->fun)(convert_obj_for_inline_asm(args[0]));
271 } else if (n_args == 2) {
Damien George20006db2014-01-18 14:10:48 +0000272 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 +0000273 } else if (n_args == 3) {
Damien George20006db2014-01-18 14:10:48 +0000274 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 +0000275 } else {
276 assert(0);
277 ret = 0;
278 }
279
280 return convert_val_from_inline_asm(ret);
281}
282
283static const mp_obj_type_t fun_asm_type = {
284 { &mp_const_type },
285 "function",
Damien George20006db2014-01-18 14:10:48 +0000286 .call = fun_asm_call,
Damiend99b0522013-12-21 18:17:45 +0000287};
288
289mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun) {
290 mp_obj_fun_asm_t *o = m_new_obj(mp_obj_fun_asm_t);
291 o->base.type = &fun_asm_type;
292 o->n_args = n_args;
293 o->fun = fun;
294 return o;
295}