blob: af855e9474c1ff3973e630e0bde0bde496fbf905 [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",
stijn3cc17c62015-02-14 18:44:31 +010065 qstr_str(mp_obj_fun_get_name(f)), expected, given));
Damien Georgeb534e1b2014-09-04 14:44:01 +010066#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
Paul Sokolovsky20397572015-03-28 01:14:44 +020089 #if MICROPY_STACKLESS
90 code_state->prev = NULL;
91 #endif
Damien Georgeb534e1b2014-09-04 14:44:01 +010092 code_state->code_info = self->bytecode;
93 code_state->sp = &code_state->state[0] - 1;
94 code_state->exc_sp = (mp_exc_stack_t*)(code_state->state + n_state) - 1;
95
96 // zero out the local stack to begin with
97 memset(code_state->state, 0, n_state * sizeof(*code_state->state));
98
99 const mp_obj_t *kwargs = args + n_args;
100
101 // var_pos_kw_args points to the stack where the var-args tuple, and var-kw dict, should go (if they are needed)
102 mp_obj_t *var_pos_kw_args = &code_state->state[n_state - 1 - self->n_pos_args - self->n_kwonly_args];
103
104 // check positional arguments
105
106 if (n_args > self->n_pos_args) {
107 // given more than enough arguments
108 if (!self->takes_var_args) {
109 fun_pos_args_mismatch(self, self->n_pos_args, n_args);
110 }
111 // put extra arguments in varargs tuple
112 *var_pos_kw_args-- = mp_obj_new_tuple(n_args - self->n_pos_args, args + self->n_pos_args);
113 n_args = self->n_pos_args;
114 } else {
115 if (self->takes_var_args) {
116 DEBUG_printf("passing empty tuple as *args\n");
117 *var_pos_kw_args-- = mp_const_empty_tuple;
118 }
119 // Apply processing and check below only if we don't have kwargs,
120 // otherwise, kw handling code below has own extensive checks.
121 if (n_kw == 0 && !self->has_def_kw_args) {
Damien George963a5a32015-01-16 17:47:07 +0000122 if (n_args >= (mp_uint_t)(self->n_pos_args - self->n_def_args)) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100123 // given enough arguments, but may need to use some default arguments
124 for (mp_uint_t i = n_args; i < self->n_pos_args; i++) {
125 code_state->state[n_state - 1 - i] = self->extra_args[i - (self->n_pos_args - self->n_def_args)];
126 }
127 } else {
128 fun_pos_args_mismatch(self, self->n_pos_args - self->n_def_args, n_args);
129 }
130 }
131 }
132
133 // copy positional args into state
134 for (mp_uint_t i = 0; i < n_args; i++) {
135 code_state->state[n_state - 1 - i] = args[i];
136 }
137
138 // check keyword arguments
139
140 if (n_kw != 0 || self->has_def_kw_args) {
141 DEBUG_printf("Initial args: ");
142 dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
143
144 mp_obj_t dict = MP_OBJ_NULL;
145 if (self->takes_kw_args) {
146 dict = mp_obj_new_dict(n_kw); // TODO: better go conservative with 0?
147 *var_pos_kw_args = dict;
148 }
149
Damien George1084b0f2014-10-25 15:07:02 +0100150 // get pointer to arg_names array at start of bytecode prelude
151 const mp_obj_t *arg_names;
152 {
153 const byte *code_info = code_state->code_info;
154 mp_uint_t code_info_size = mp_decode_uint(&code_info);
155 arg_names = (const mp_obj_t*)(code_state->code_info + code_info_size);
156 }
157
Damien Georgeb534e1b2014-09-04 14:44:01 +0100158 for (mp_uint_t i = 0; i < n_kw; i++) {
Damien George1084b0f2014-10-25 15:07:02 +0100159 mp_obj_t wanted_arg_name = kwargs[2 * i];
Damien Georgeb534e1b2014-09-04 14:44:01 +0100160 for (mp_uint_t j = 0; j < self->n_pos_args + self->n_kwonly_args; j++) {
Damien George1084b0f2014-10-25 15:07:02 +0100161 if (wanted_arg_name == arg_names[j]) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100162 if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) {
163 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
Damien George1084b0f2014-10-25 15:07:02 +0100164 "function got multiple values for argument '%s'", qstr_str(MP_OBJ_QSTR_VALUE(wanted_arg_name))));
Damien Georgeb534e1b2014-09-04 14:44:01 +0100165 }
166 code_state->state[n_state - 1 - j] = kwargs[2 * i + 1];
167 goto continue2;
168 }
169 }
170 // Didn't find name match with positional args
171 if (!self->takes_kw_args) {
172 nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments"));
173 }
174 mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]);
175continue2:;
176 }
177
178 DEBUG_printf("Args with kws flattened: ");
179 dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
180
181 // fill in defaults for positional args
182 mp_obj_t *d = &code_state->state[n_state - self->n_pos_args];
183 mp_obj_t *s = &self->extra_args[self->n_def_args - 1];
Damien George42f3de92014-10-03 17:44:14 +0000184 for (mp_uint_t i = self->n_def_args; i > 0; i--, d++, s--) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100185 if (*d == MP_OBJ_NULL) {
186 *d = *s;
187 }
188 }
189
190 DEBUG_printf("Args after filling default positional: ");
191 dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
192
193 // Check that all mandatory positional args are specified
194 while (d < &code_state->state[n_state]) {
195 if (*d++ == MP_OBJ_NULL) {
196 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
197 "function missing required positional argument #%d", &code_state->state[n_state] - d));
198 }
199 }
200
201 // Check that all mandatory keyword args are specified
202 // Fill in default kw args if we have them
203 for (mp_uint_t i = 0; i < self->n_kwonly_args; i++) {
204 if (code_state->state[n_state - 1 - self->n_pos_args - i] == MP_OBJ_NULL) {
205 mp_map_elem_t *elem = NULL;
206 if (self->has_def_kw_args) {
Damien George1084b0f2014-10-25 15:07:02 +0100207 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 +0100208 }
209 if (elem != NULL) {
210 code_state->state[n_state - 1 - self->n_pos_args - i] = elem->value;
211 } else {
212 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
Damien George1084b0f2014-10-25 15:07:02 +0100213 "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 +0100214 }
215 }
216 }
217
218 } else {
219 // no keyword arguments given
220 if (self->n_kwonly_args != 0) {
221 nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
222 "function missing keyword-only argument"));
223 }
224 if (self->takes_kw_args) {
225 *var_pos_kw_args = mp_obj_new_dict(0);
226 }
227 }
228
229 // bytecode prelude: initialise closed over variables
Damien George1084b0f2014-10-25 15:07:02 +0100230 const byte *ip = code_state->ip;
Damien Georgeb534e1b2014-09-04 14:44:01 +0100231 for (mp_uint_t n_local = *ip++; n_local > 0; n_local--) {
232 mp_uint_t local_num = *ip++;
233 code_state->state[n_state - 1 - local_num] = mp_obj_new_cell(code_state->state[n_state - 1 - local_num]);
234 }
235
236 // now that we skipped over the prelude, set the ip for the VM
237 code_state->ip = ip;
238
239 DEBUG_printf("Calling: n_pos_args=%d, n_kwonly_args=%d\n", self->n_pos_args, self->n_kwonly_args);
240 dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
241 dump_args(code_state->state, n_state);
242}