blob: cefc9a95fe36888e4164dd4d3b36e523c51ac936 [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"
9#include "obj.h"
10#include "runtime.h"
11#include "bc.h"
12
13/******************************************************************************/
14/* native functions */
15
16// mp_obj_fun_native_t defined in obj.h
17
18// args are in reverse order in the array
19mp_obj_t fun_native_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
20 mp_obj_fun_native_t *self = self_in;
21 if (self->n_args_min == self->n_args_max) {
22 // function requires a fixed number of arguments
23
24 // check number of arguments
25 if (n_args != self->n_args_min) {
26 nlr_jump(mp_obj_new_exception_msg_2_args(rt_q_TypeError, "function takes %d positional arguments but %d were given", (const char*)(machine_int_t)self->n_args_min, (const char*)(machine_int_t)n_args));
27 }
28
29 // dispatch function call
30 switch (self->n_args_min) {
31 case 0:
32 return ((mp_fun_0_t)self->fun)();
33
34 case 1:
35 return ((mp_fun_1_t)self->fun)(args[0]);
36
37 case 2:
38 return ((mp_fun_2_t)self->fun)(args[1], args[0]);
39
40 default:
41 assert(0);
42 return mp_const_none;
43 }
44
45 } else {
46 // function takes a variable number of arguments
47
48 if (n_args < self->n_args_min) {
49 nlr_jump(mp_obj_new_exception_msg_1_arg(rt_q_TypeError, "<fun name>() missing %d required positional arguments: <list of names of params>", (const char*)(machine_int_t)(self->n_args_min - n_args)));
50 } else if (n_args > self->n_args_max) {
51 nlr_jump(mp_obj_new_exception_msg_2_args(rt_q_TypeError, "<fun name> expected at most %d arguments, got %d", (void*)(machine_int_t)self->n_args_max, (void*)(machine_int_t)n_args));
52 }
53
54 // TODO really the args need to be passed in as a Python tuple, as the form f(*[1,2]) can be used to pass var args
55 mp_obj_t *args_ordered = m_new(mp_obj_t, n_args);
56 for (int i = 0; i < n_args; i++) {
57 args_ordered[i] = args[n_args - i - 1];
58 }
59
60 mp_obj_t res = ((mp_fun_var_t)self->fun)(n_args, args_ordered);
Damien732407f2013-12-29 19:33:23 +000061 m_del(mp_obj_t, args_ordered, n_args);
Damiend99b0522013-12-21 18:17:45 +000062
63 return res;
64 }
65}
66
67const mp_obj_type_t fun_native_type = {
68 { &mp_const_type },
69 "function",
70 NULL, // print
71 fun_native_call_n, // call_n
72 NULL, // unary_op
73 NULL, // binary_op
74 NULL, // getiter
75 NULL, // iternext
76 { // method list
77 {NULL, NULL}, // end-of-list sentinel
78 },
79};
80
81mp_obj_t rt_make_function_0(mp_fun_0_t fun) {
82 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
83 o->base.type = &fun_native_type;
84 o->n_args_min = 0;
85 o->n_args_max = 0;
86 o->fun = fun;
87 return o;
88}
89
90mp_obj_t rt_make_function_1(mp_fun_1_t fun) {
91 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
92 o->base.type = &fun_native_type;
93 o->n_args_min = 1;
94 o->n_args_max = 1;
95 o->fun = fun;
96 return o;
97}
98
99mp_obj_t rt_make_function_2(mp_fun_2_t fun) {
100 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
101 o->base.type = &fun_native_type;
102 o->n_args_min = 2;
103 o->n_args_max = 2;
104 o->fun = fun;
105 return o;
106}
107
108mp_obj_t rt_make_function_var(int n_args_min, mp_fun_var_t fun) {
109 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
110 o->base.type = &fun_native_type;
111 o->n_args_min = n_args_min;
112 o->n_args_max = ~((machine_uint_t)0);
113 o->fun = fun;
114 return o;
115}
116
117// min and max are inclusive
118mp_obj_t rt_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var_t fun) {
119 mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
120 o->base.type = &fun_native_type;
121 o->n_args_min = n_args_min;
122 o->n_args_max = n_args_max;
123 o->fun = fun;
124 return o;
125}
126
127/******************************************************************************/
128/* byte code functions */
129
130typedef struct _mp_obj_fun_bc_t {
131 mp_obj_base_t base;
132 int n_args;
133 uint n_state;
134 const byte *code;
135} mp_obj_fun_bc_t;
136
137// args are in reverse order in the array
138mp_obj_t fun_bc_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
139 mp_obj_fun_bc_t *self = self_in;
140
141 if (n_args != self->n_args) {
142 nlr_jump(mp_obj_new_exception_msg_2_args(rt_q_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));
143 }
144
145 return mp_execute_byte_code(self->code, args, n_args, self->n_state);
146}
147
148void mp_obj_fun_bc_get(mp_obj_t self_in, int *n_args, uint *n_state, const byte **code) {
149 assert(MP_OBJ_IS_TYPE(self_in, &fun_bc_type));
150 mp_obj_fun_bc_t *self = self_in;
151 *n_args = self->n_args;
152 *n_state = self->n_state;
153 *code = self->code;
154}
155
156const mp_obj_type_t fun_bc_type = {
157 { &mp_const_type },
158 "function",
159 NULL, // print
160 fun_bc_call_n, // call_n
161 NULL, // unary_op
162 NULL, // binary_op
163 NULL, // getiter
164 NULL, // iternext
165 { // method list
166 {NULL, NULL}, // end-of-list sentinel
167 },
168};
169
170mp_obj_t mp_obj_new_fun_bc(int n_args, uint n_state, const byte *code) {
171 mp_obj_fun_bc_t *o = m_new_obj(mp_obj_fun_bc_t);
172 o->base.type = &fun_bc_type;
173 o->n_args = n_args;
174 o->n_state = n_state;
175 o->code = code;
176 return o;
177}
178
179/******************************************************************************/
180/* inline assembler functions */
181
182typedef struct _mp_obj_fun_asm_t {
183 mp_obj_base_t base;
184 int n_args;
185 void *fun;
186} mp_obj_fun_asm_t;
187
188typedef machine_uint_t (*inline_asm_fun_0_t)();
189typedef machine_uint_t (*inline_asm_fun_1_t)(machine_uint_t);
190typedef machine_uint_t (*inline_asm_fun_2_t)(machine_uint_t, machine_uint_t);
191typedef machine_uint_t (*inline_asm_fun_3_t)(machine_uint_t, machine_uint_t, machine_uint_t);
192
193// convert a Micro Python object to a sensible value for inline asm
194machine_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
195 // TODO for byte_array, pass pointer to the array
196 if (MP_OBJ_IS_SMALL_INT(obj)) {
197 return MP_OBJ_SMALL_INT_VALUE(obj);
198 } else if (obj == mp_const_none) {
199 return 0;
200 } else if (obj == mp_const_false) {
201 return 0;
202 } else if (obj == mp_const_true) {
203 return 1;
204 } else if (MP_OBJ_IS_TYPE(obj, &str_type)) {
205 // pointer to the string (it's probably constant though!)
206 return (machine_uint_t)qstr_str(mp_obj_str_get(obj));
207#if MICROPY_ENABLE_FLOAT
208 } else if (MP_OBJ_IS_TYPE(obj, &float_type)) {
209 // convert float to int (could also pass in float registers)
210 return (machine_int_t)mp_obj_float_get(obj);
211#endif
212 } else if (MP_OBJ_IS_TYPE(obj, &tuple_type)) {
213 // pointer to start of tuple (could pass length, but then could use len(x) for that)
214 uint len;
215 mp_obj_t *items;
216 mp_obj_tuple_get(obj, &len, &items);
217 return (machine_uint_t)items;
218 } else if (MP_OBJ_IS_TYPE(obj, &list_type)) {
219 // pointer to start of list (could pass length, but then could use len(x) for that)
220 uint len;
221 mp_obj_t *items;
222 mp_obj_list_get(obj, &len, &items);
223 return (machine_uint_t)items;
224 } else {
225 // just pass along a pointer to the object
226 return (machine_uint_t)obj;
227 }
228}
229
230// convert a return value from inline asm to a sensible Micro Python object
231mp_obj_t convert_val_from_inline_asm(machine_uint_t val) {
232 return MP_OBJ_NEW_SMALL_INT(val);
233}
234
235// args are in reverse order in the array
236mp_obj_t fun_asm_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
237 mp_obj_fun_asm_t *self = self_in;
238
239 if (n_args != self->n_args) {
240 nlr_jump(mp_obj_new_exception_msg_2_args(rt_q_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));
241 }
242
243 machine_uint_t ret;
244 if (n_args == 0) {
245 ret = ((inline_asm_fun_0_t)self->fun)();
246 } else if (n_args == 1) {
247 ret = ((inline_asm_fun_1_t)self->fun)(convert_obj_for_inline_asm(args[0]));
248 } else if (n_args == 2) {
249 ret = ((inline_asm_fun_2_t)self->fun)(convert_obj_for_inline_asm(args[1]), convert_obj_for_inline_asm(args[0]));
250 } else if (n_args == 3) {
251 ret = ((inline_asm_fun_3_t)self->fun)(convert_obj_for_inline_asm(args[2]), convert_obj_for_inline_asm(args[1]), convert_obj_for_inline_asm(args[0]));
252 } else {
253 assert(0);
254 ret = 0;
255 }
256
257 return convert_val_from_inline_asm(ret);
258}
259
260static const mp_obj_type_t fun_asm_type = {
261 { &mp_const_type },
262 "function",
263 NULL, // print
264 fun_asm_call_n, // call_n
265 NULL, // unary_op
266 NULL, // binary_op
267 NULL, // getiter
268 NULL, // iternext
269 { // method list
270 {NULL, NULL}, // end-of-list sentinel
271 },
272};
273
274mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun) {
275 mp_obj_fun_asm_t *o = m_new_obj(mp_obj_fun_asm_t);
276 o->base.type = &fun_asm_type;
277 o->n_args = n_args;
278 o->fun = fun;
279 return o;
280}