blob: 6aa20172ff9fe0b47269aea095aea50b353830f7 [file] [log] [blame]
Damien Georgeb534e1b2014-09-04 14:44:01 +01001/*
2 * This file is part of the Micro Python project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2014 Damien P. George
7 * Copyright (c) 2014 Paul Sokolovsky
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28#include <stdbool.h>
29#include <string.h>
30#include <assert.h>
31
Damien George51dfcb42015-01-01 20:27:54 +000032#include "py/nlr.h"
33#include "py/objfun.h"
34#include "py/bc.h"
Damien Georgeb534e1b2014-09-04 14:44:01 +010035
36#if 0 // print debugging info
37#define DEBUG_PRINT (1)
38#else // don't print debugging info
Damien George7860c2a2014-11-05 21:16:41 +000039#define DEBUG_PRINT (0)
Damien Georgeb534e1b2014-09-04 14:44:01 +010040#define DEBUG_printf(...) (void)0
41#endif
42
43mp_uint_t mp_decode_uint(const byte **ptr) {
44 mp_uint_t unum = 0;
45 byte val;
46 const byte *p = *ptr;
47 do {
48 val = *p++;
49 unum = (unum << 7) | (val & 0x7f);
50 } while ((val & 0x80) != 0);
51 *ptr = p;
52 return unum;
53}
54
55STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, mp_uint_t expected, mp_uint_t given) {
56#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
Damien George7f233842015-01-01 15:33:50 +000057 // generic message, used also for other argument issues
58 mp_arg_error_terse_mismatch();
Damien Georgeb534e1b2014-09-04 14:44:01 +010059#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL
60 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
61 "function takes %d positional arguments but %d were given", expected, given));
62#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
63 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
64 "%s() takes %d positional arguments but %d were given",
65 mp_obj_fun_get_name(f), expected, given));
66#endif
67}
68
69#if DEBUG_PRINT
Damien George42f3de92014-10-03 17:44:14 +000070STATIC void dump_args(const mp_obj_t *a, mp_uint_t sz) {
Damien Georgeb534e1b2014-09-04 14:44:01 +010071 DEBUG_printf("%p: ", a);
Damien George42f3de92014-10-03 17:44:14 +000072 for (mp_uint_t i = 0; i < sz; i++) {
Damien Georgeb534e1b2014-09-04 14:44:01 +010073 DEBUG_printf("%p ", a[i]);
74 }
75 DEBUG_printf("\n");
76}
77#else
78#define dump_args(...) (void)0
79#endif
80
81// code_state should have ->ip filled in (pointing past code info block),
82// as well as ->n_state.
83void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
84 // This function is pretty complicated. It's main aim is to be efficient in speed and RAM
85 // usage for the common case of positional only args.
86 mp_obj_fun_bc_t *self = self_in;
87 mp_uint_t n_state = code_state->n_state;
Damien Georgeb534e1b2014-09-04 14:44:01 +010088
89 code_state->code_info = self->bytecode;
90 code_state->sp = &code_state->state[0] - 1;
91 code_state->exc_sp = (mp_exc_stack_t*)(code_state->state + n_state) - 1;
92
93 // zero out the local stack to begin with
94 memset(code_state->state, 0, n_state * sizeof(*code_state->state));
95
96 const mp_obj_t *kwargs = args + n_args;
97
98 // var_pos_kw_args points to the stack where the var-args tuple, and var-kw dict, should go (if they are needed)
99 mp_obj_t *var_pos_kw_args = &code_state->state[n_state - 1 - self->n_pos_args - self->n_kwonly_args];
100
101 // check positional arguments
102
103 if (n_args > self->n_pos_args) {
104 // given more than enough arguments
105 if (!self->takes_var_args) {
106 fun_pos_args_mismatch(self, self->n_pos_args, n_args);
107 }
108 // put extra arguments in varargs tuple
109 *var_pos_kw_args-- = mp_obj_new_tuple(n_args - self->n_pos_args, args + self->n_pos_args);
110 n_args = self->n_pos_args;
111 } else {
112 if (self->takes_var_args) {
113 DEBUG_printf("passing empty tuple as *args\n");
114 *var_pos_kw_args-- = mp_const_empty_tuple;
115 }
116 // Apply processing and check below only if we don't have kwargs,
117 // otherwise, kw handling code below has own extensive checks.
118 if (n_kw == 0 && !self->has_def_kw_args) {
119 if (n_args >= self->n_pos_args - self->n_def_args) {
120 // given enough arguments, but may need to use some default arguments
121 for (mp_uint_t i = n_args; i < self->n_pos_args; i++) {
122 code_state->state[n_state - 1 - i] = self->extra_args[i - (self->n_pos_args - self->n_def_args)];
123 }
124 } else {
125 fun_pos_args_mismatch(self, self->n_pos_args - self->n_def_args, n_args);
126 }
127 }
128 }
129
130 // copy positional args into state
131 for (mp_uint_t i = 0; i < n_args; i++) {
132 code_state->state[n_state - 1 - i] = args[i];
133 }
134
135 // check keyword arguments
136
137 if (n_kw != 0 || self->has_def_kw_args) {
138 DEBUG_printf("Initial args: ");
139 dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
140
141 mp_obj_t dict = MP_OBJ_NULL;
142 if (self->takes_kw_args) {
143 dict = mp_obj_new_dict(n_kw); // TODO: better go conservative with 0?
144 *var_pos_kw_args = dict;
145 }
146
Damien George1084b0f2014-10-25 15:07:02 +0100147 // get pointer to arg_names array at start of bytecode prelude
148 const mp_obj_t *arg_names;
149 {
150 const byte *code_info = code_state->code_info;
151 mp_uint_t code_info_size = mp_decode_uint(&code_info);
152 arg_names = (const mp_obj_t*)(code_state->code_info + code_info_size);
153 }
154
Damien Georgeb534e1b2014-09-04 14:44:01 +0100155 for (mp_uint_t i = 0; i < n_kw; i++) {
Damien George1084b0f2014-10-25 15:07:02 +0100156 mp_obj_t wanted_arg_name = kwargs[2 * i];
Damien Georgeb534e1b2014-09-04 14:44:01 +0100157 for (mp_uint_t j = 0; j < self->n_pos_args + self->n_kwonly_args; j++) {
Damien George1084b0f2014-10-25 15:07:02 +0100158 if (wanted_arg_name == arg_names[j]) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100159 if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) {
160 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
Damien George1084b0f2014-10-25 15:07:02 +0100161 "function got multiple values for argument '%s'", qstr_str(MP_OBJ_QSTR_VALUE(wanted_arg_name))));
Damien Georgeb534e1b2014-09-04 14:44:01 +0100162 }
163 code_state->state[n_state - 1 - j] = kwargs[2 * i + 1];
164 goto continue2;
165 }
166 }
167 // Didn't find name match with positional args
168 if (!self->takes_kw_args) {
169 nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments"));
170 }
171 mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]);
172continue2:;
173 }
174
175 DEBUG_printf("Args with kws flattened: ");
176 dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
177
178 // fill in defaults for positional args
179 mp_obj_t *d = &code_state->state[n_state - self->n_pos_args];
180 mp_obj_t *s = &self->extra_args[self->n_def_args - 1];
Damien George42f3de92014-10-03 17:44:14 +0000181 for (mp_uint_t i = self->n_def_args; i > 0; i--, d++, s--) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100182 if (*d == MP_OBJ_NULL) {
183 *d = *s;
184 }
185 }
186
187 DEBUG_printf("Args after filling default positional: ");
188 dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
189
190 // Check that all mandatory positional args are specified
191 while (d < &code_state->state[n_state]) {
192 if (*d++ == MP_OBJ_NULL) {
193 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
194 "function missing required positional argument #%d", &code_state->state[n_state] - d));
195 }
196 }
197
198 // Check that all mandatory keyword args are specified
199 // Fill in default kw args if we have them
200 for (mp_uint_t i = 0; i < self->n_kwonly_args; i++) {
201 if (code_state->state[n_state - 1 - self->n_pos_args - i] == MP_OBJ_NULL) {
202 mp_map_elem_t *elem = NULL;
203 if (self->has_def_kw_args) {
Damien George1084b0f2014-10-25 15:07:02 +0100204 elem = mp_map_lookup(&((mp_obj_dict_t*)self->extra_args[self->n_def_args])->map, arg_names[self->n_pos_args + i], MP_MAP_LOOKUP);
Damien Georgeb534e1b2014-09-04 14:44:01 +0100205 }
206 if (elem != NULL) {
207 code_state->state[n_state - 1 - self->n_pos_args - i] = elem->value;
208 } else {
209 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
Damien George1084b0f2014-10-25 15:07:02 +0100210 "function missing required keyword argument '%s'", qstr_str(MP_OBJ_QSTR_VALUE(arg_names[self->n_pos_args + i]))));
Damien Georgeb534e1b2014-09-04 14:44:01 +0100211 }
212 }
213 }
214
215 } else {
216 // no keyword arguments given
217 if (self->n_kwonly_args != 0) {
218 nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
219 "function missing keyword-only argument"));
220 }
221 if (self->takes_kw_args) {
222 *var_pos_kw_args = mp_obj_new_dict(0);
223 }
224 }
225
226 // bytecode prelude: initialise closed over variables
Damien George1084b0f2014-10-25 15:07:02 +0100227 const byte *ip = code_state->ip;
Damien Georgeb534e1b2014-09-04 14:44:01 +0100228 for (mp_uint_t n_local = *ip++; n_local > 0; n_local--) {
229 mp_uint_t local_num = *ip++;
230 code_state->state[n_state - 1 - local_num] = mp_obj_new_cell(code_state->state[n_state - 1 - local_num]);
231 }
232
233 // now that we skipped over the prelude, set the ip for the VM
234 code_state->ip = ip;
235
236 DEBUG_printf("Calling: n_pos_args=%d, n_kwonly_args=%d\n", self->n_pos_args, self->n_kwonly_args);
237 dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
238 dump_args(code_state->state, n_state);
239}