blob: b749860c25d7b6395530fc4f7fe2474678c60c18 [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"
Damien George66028ab2014-01-03 14:03:48 +000011#include "map.h"
Damiend99b0522013-12-21 18:17:45 +000012#include "runtime.h"
13#include "bc.h"
14
15/******************************************************************************/
16/* native functions */
17
18// mp_obj_fun_native_t defined in obj.h
19
John R. Lenton88cb1e62014-01-13 19:55:18 +000020void check_nargs(mp_obj_fun_native_t *self, int n_args, int n_kw) {
21 if (n_kw && !self->is_kw) {
22 nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError,
23 "function does not take keyword arguments"));
24 }
25
26 if (self->n_args_min == self->n_args_max) {
27 if (n_args != self->n_args_min) {
28 nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError,
29 "function takes %d positional arguments but %d were given",
30 (const char*)(machine_int_t)self->n_args_min,
31 (const char*)(machine_int_t)n_args));
32 }
33 } else {
34 if (n_args < self->n_args_min) {
35 nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError,
36 "<fun name>() missing %d required positional arguments: <list of names of params>",
37 (const char*)(machine_int_t)(self->n_args_min - n_args)));
38 } else if (n_args > self->n_args_max) {
39 nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError,
40 "<fun name> expected at most %d arguments, got %d",
41 (void*)(machine_int_t)self->n_args_max, (void*)(machine_int_t)n_args));
42 }
43 }
44}
45
Damien George20006db2014-01-18 14:10:48 +000046mp_obj_t fun_native_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
47 assert(MP_OBJ_IS_TYPE(self_in, &fun_native_type));
Damiend99b0522013-12-21 18:17:45 +000048 mp_obj_fun_native_t *self = self_in;
Damien George20006db2014-01-18 14:10:48 +000049
John R. Lenton88cb1e62014-01-13 19:55:18 +000050 // check number of arguments
Damien George20006db2014-01-18 14:10:48 +000051 check_nargs(self, n_args, n_kw);
52
John R. Lentonc06763a2014-01-07 17:29:16 +000053 if (self->is_kw) {
Damien George20006db2014-01-18 14:10:48 +000054 // function allows keywords
55
56 // TODO if n_kw==0 then don't allocate any memory for map (either pass NULL or allocate it on the heap)
57 mp_map_t *kw_args = mp_map_new(n_kw);
58 for (int i = 0; i < 2 * n_kw; i += 2) {
59 qstr name = mp_obj_str_get(args[n_args + i]);
60 mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(name), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = args[n_args + i + 1];
61 }
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
67 } else if (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
140 int n_args; // number of arguments this function takes
141 uint n_state; // total state size for the executing function (incl args, locals, stack)
142 const byte *bytecode; // bytecode for the function
Damiend99b0522013-12-21 18:17:45 +0000143} mp_obj_fun_bc_t;
144
Damien George20006db2014-01-18 14:10:48 +0000145mp_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 +0000146 mp_obj_fun_bc_t *self = self_in;
147
148 if (n_args != self->n_args) {
Damien Georgeeb7bfcb2014-01-04 15:57:35 +0000149 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 +0000150 }
Damien George20006db2014-01-18 14:10:48 +0000151 if (n_kw != 0) {
152 nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "function does not take keyword arguments"));
153 }
Damiend99b0522013-12-21 18:17:45 +0000154
Damien George66028ab2014-01-03 14:03:48 +0000155 // optimisation: allow the compiler to optimise this tail call for
156 // the common case when the globals don't need to be changed
157 mp_map_t *old_globals = rt_globals_get();
158 if (self->globals == old_globals) {
159 return mp_execute_byte_code(self->bytecode, args, n_args, self->n_state);
160 } else {
161 rt_globals_set(self->globals);
162 mp_obj_t result = mp_execute_byte_code(self->bytecode, args, n_args, self->n_state);
163 rt_globals_set(old_globals);
164 return result;
165 }
Damiend99b0522013-12-21 18:17:45 +0000166}
167
168const mp_obj_type_t fun_bc_type = {
169 { &mp_const_type },
170 "function",
Damien George20006db2014-01-18 14:10:48 +0000171 .call = fun_bc_call,
Damiend99b0522013-12-21 18:17:45 +0000172};
173
174mp_obj_t mp_obj_new_fun_bc(int n_args, uint n_state, const byte *code) {
175 mp_obj_fun_bc_t *o = m_new_obj(mp_obj_fun_bc_t);
176 o->base.type = &fun_bc_type;
Damien George66028ab2014-01-03 14:03:48 +0000177 o->globals = rt_globals_get();
Damiend99b0522013-12-21 18:17:45 +0000178 o->n_args = n_args;
179 o->n_state = n_state;
Damien George66028ab2014-01-03 14:03:48 +0000180 o->bytecode = code;
Damiend99b0522013-12-21 18:17:45 +0000181 return o;
182}
183
Damien George66028ab2014-01-03 14:03:48 +0000184void mp_obj_fun_bc_get(mp_obj_t self_in, int *n_args, uint *n_state, const byte **code) {
185 assert(MP_OBJ_IS_TYPE(self_in, &fun_bc_type));
186 mp_obj_fun_bc_t *self = self_in;
187 *n_args = self->n_args;
188 *n_state = self->n_state;
189 *code = self->bytecode;
190}
191
Damiend99b0522013-12-21 18:17:45 +0000192/******************************************************************************/
193/* inline assembler functions */
194
195typedef struct _mp_obj_fun_asm_t {
196 mp_obj_base_t base;
197 int n_args;
198 void *fun;
199} mp_obj_fun_asm_t;
200
201typedef machine_uint_t (*inline_asm_fun_0_t)();
202typedef machine_uint_t (*inline_asm_fun_1_t)(machine_uint_t);
203typedef machine_uint_t (*inline_asm_fun_2_t)(machine_uint_t, machine_uint_t);
204typedef machine_uint_t (*inline_asm_fun_3_t)(machine_uint_t, machine_uint_t, machine_uint_t);
205
206// convert a Micro Python object to a sensible value for inline asm
207machine_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
208 // TODO for byte_array, pass pointer to the array
209 if (MP_OBJ_IS_SMALL_INT(obj)) {
210 return MP_OBJ_SMALL_INT_VALUE(obj);
211 } else if (obj == mp_const_none) {
212 return 0;
213 } else if (obj == mp_const_false) {
214 return 0;
215 } else if (obj == mp_const_true) {
216 return 1;
217 } else if (MP_OBJ_IS_TYPE(obj, &str_type)) {
218 // pointer to the string (it's probably constant though!)
219 return (machine_uint_t)qstr_str(mp_obj_str_get(obj));
220#if MICROPY_ENABLE_FLOAT
221 } else if (MP_OBJ_IS_TYPE(obj, &float_type)) {
222 // convert float to int (could also pass in float registers)
223 return (machine_int_t)mp_obj_float_get(obj);
224#endif
225 } else if (MP_OBJ_IS_TYPE(obj, &tuple_type)) {
226 // pointer to start of tuple (could pass length, but then could use len(x) for that)
227 uint len;
228 mp_obj_t *items;
229 mp_obj_tuple_get(obj, &len, &items);
230 return (machine_uint_t)items;
231 } else if (MP_OBJ_IS_TYPE(obj, &list_type)) {
232 // pointer to start of list (could pass length, but then could use len(x) for that)
233 uint len;
234 mp_obj_t *items;
235 mp_obj_list_get(obj, &len, &items);
236 return (machine_uint_t)items;
237 } else {
238 // just pass along a pointer to the object
239 return (machine_uint_t)obj;
240 }
241}
242
243// convert a return value from inline asm to a sensible Micro Python object
244mp_obj_t convert_val_from_inline_asm(machine_uint_t val) {
245 return MP_OBJ_NEW_SMALL_INT(val);
246}
247
Damien George20006db2014-01-18 14:10:48 +0000248mp_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 +0000249 mp_obj_fun_asm_t *self = self_in;
250
251 if (n_args != self->n_args) {
Damien Georgeeb7bfcb2014-01-04 15:57:35 +0000252 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 +0000253 }
Damien George20006db2014-01-18 14:10:48 +0000254 if (n_kw != 0) {
255 nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "function does not take keyword arguments"));
256 }
Damiend99b0522013-12-21 18:17:45 +0000257
258 machine_uint_t ret;
259 if (n_args == 0) {
260 ret = ((inline_asm_fun_0_t)self->fun)();
261 } else if (n_args == 1) {
262 ret = ((inline_asm_fun_1_t)self->fun)(convert_obj_for_inline_asm(args[0]));
263 } else if (n_args == 2) {
Damien George20006db2014-01-18 14:10:48 +0000264 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 +0000265 } else if (n_args == 3) {
Damien George20006db2014-01-18 14:10:48 +0000266 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 +0000267 } else {
268 assert(0);
269 ret = 0;
270 }
271
272 return convert_val_from_inline_asm(ret);
273}
274
275static const mp_obj_type_t fun_asm_type = {
276 { &mp_const_type },
277 "function",
Damien George20006db2014-01-18 14:10:48 +0000278 .call = fun_asm_call,
Damiend99b0522013-12-21 18:17:45 +0000279};
280
281mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun) {
282 mp_obj_fun_asm_t *o = m_new_obj(mp_obj_fun_asm_t);
283 o->base.type = &fun_asm_type;
284 o->n_args = n_args;
285 o->fun = fun;
286 return o;
287}