blob: 47f8d9f713ca2f6384dfd30435a4c9901bb53a37 [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
32#include "mpconfig.h"
33#include "nlr.h"
34#include "misc.h"
35#include "qstr.h"
36#include "obj.h"
37#include "objtuple.h"
38#include "objfun.h"
39#include "runtime0.h"
40#include "runtime.h"
41#include "bc.h"
42#include "stackctrl.h"
43
44#if 0 // print debugging info
45#define DEBUG_PRINT (1)
46#else // don't print debugging info
Damien George7860c2a2014-11-05 21:16:41 +000047#define DEBUG_PRINT (0)
Damien Georgeb534e1b2014-09-04 14:44:01 +010048#define DEBUG_printf(...) (void)0
49#endif
50
51mp_uint_t mp_decode_uint(const byte **ptr) {
52 mp_uint_t unum = 0;
53 byte val;
54 const byte *p = *ptr;
55 do {
56 val = *p++;
57 unum = (unum << 7) | (val & 0x7f);
58 } while ((val & 0x80) != 0);
59 *ptr = p;
60 return unum;
61}
62
63STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, mp_uint_t expected, mp_uint_t given) {
64#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
65 // Generic message, to be reused for other argument issues
66 nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
67 "argument num/types mismatch"));
68#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL
69 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
70 "function takes %d positional arguments but %d were given", expected, given));
71#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
72 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
73 "%s() takes %d positional arguments but %d were given",
74 mp_obj_fun_get_name(f), expected, given));
75#endif
76}
77
78#if DEBUG_PRINT
Damien George42f3de92014-10-03 17:44:14 +000079STATIC void dump_args(const mp_obj_t *a, mp_uint_t sz) {
Damien Georgeb534e1b2014-09-04 14:44:01 +010080 DEBUG_printf("%p: ", a);
Damien George42f3de92014-10-03 17:44:14 +000081 for (mp_uint_t i = 0; i < sz; i++) {
Damien Georgeb534e1b2014-09-04 14:44:01 +010082 DEBUG_printf("%p ", a[i]);
83 }
84 DEBUG_printf("\n");
85}
86#else
87#define dump_args(...) (void)0
88#endif
89
90// code_state should have ->ip filled in (pointing past code info block),
91// as well as ->n_state.
92void 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) {
93 // This function is pretty complicated. It's main aim is to be efficient in speed and RAM
94 // usage for the common case of positional only args.
95 mp_obj_fun_bc_t *self = self_in;
96 mp_uint_t n_state = code_state->n_state;
Damien Georgeb534e1b2014-09-04 14:44:01 +010097
98 code_state->code_info = self->bytecode;
99 code_state->sp = &code_state->state[0] - 1;
100 code_state->exc_sp = (mp_exc_stack_t*)(code_state->state + n_state) - 1;
101
102 // zero out the local stack to begin with
103 memset(code_state->state, 0, n_state * sizeof(*code_state->state));
104
105 const mp_obj_t *kwargs = args + n_args;
106
107 // var_pos_kw_args points to the stack where the var-args tuple, and var-kw dict, should go (if they are needed)
108 mp_obj_t *var_pos_kw_args = &code_state->state[n_state - 1 - self->n_pos_args - self->n_kwonly_args];
109
110 // check positional arguments
111
112 if (n_args > self->n_pos_args) {
113 // given more than enough arguments
114 if (!self->takes_var_args) {
115 fun_pos_args_mismatch(self, self->n_pos_args, n_args);
116 }
117 // put extra arguments in varargs tuple
118 *var_pos_kw_args-- = mp_obj_new_tuple(n_args - self->n_pos_args, args + self->n_pos_args);
119 n_args = self->n_pos_args;
120 } else {
121 if (self->takes_var_args) {
122 DEBUG_printf("passing empty tuple as *args\n");
123 *var_pos_kw_args-- = mp_const_empty_tuple;
124 }
125 // Apply processing and check below only if we don't have kwargs,
126 // otherwise, kw handling code below has own extensive checks.
127 if (n_kw == 0 && !self->has_def_kw_args) {
128 if (n_args >= self->n_pos_args - self->n_def_args) {
129 // given enough arguments, but may need to use some default arguments
130 for (mp_uint_t i = n_args; i < self->n_pos_args; i++) {
131 code_state->state[n_state - 1 - i] = self->extra_args[i - (self->n_pos_args - self->n_def_args)];
132 }
133 } else {
134 fun_pos_args_mismatch(self, self->n_pos_args - self->n_def_args, n_args);
135 }
136 }
137 }
138
139 // copy positional args into state
140 for (mp_uint_t i = 0; i < n_args; i++) {
141 code_state->state[n_state - 1 - i] = args[i];
142 }
143
144 // check keyword arguments
145
146 if (n_kw != 0 || self->has_def_kw_args) {
147 DEBUG_printf("Initial args: ");
148 dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
149
150 mp_obj_t dict = MP_OBJ_NULL;
151 if (self->takes_kw_args) {
152 dict = mp_obj_new_dict(n_kw); // TODO: better go conservative with 0?
153 *var_pos_kw_args = dict;
154 }
155
Damien George1084b0f2014-10-25 15:07:02 +0100156 // get pointer to arg_names array at start of bytecode prelude
157 const mp_obj_t *arg_names;
158 {
159 const byte *code_info = code_state->code_info;
160 mp_uint_t code_info_size = mp_decode_uint(&code_info);
161 arg_names = (const mp_obj_t*)(code_state->code_info + code_info_size);
162 }
163
Damien Georgeb534e1b2014-09-04 14:44:01 +0100164 for (mp_uint_t i = 0; i < n_kw; i++) {
Damien George1084b0f2014-10-25 15:07:02 +0100165 mp_obj_t wanted_arg_name = kwargs[2 * i];
Damien Georgeb534e1b2014-09-04 14:44:01 +0100166 for (mp_uint_t j = 0; j < self->n_pos_args + self->n_kwonly_args; j++) {
Damien George1084b0f2014-10-25 15:07:02 +0100167 if (wanted_arg_name == arg_names[j]) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100168 if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) {
169 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
Damien George1084b0f2014-10-25 15:07:02 +0100170 "function got multiple values for argument '%s'", qstr_str(MP_OBJ_QSTR_VALUE(wanted_arg_name))));
Damien Georgeb534e1b2014-09-04 14:44:01 +0100171 }
172 code_state->state[n_state - 1 - j] = kwargs[2 * i + 1];
173 goto continue2;
174 }
175 }
176 // Didn't find name match with positional args
177 if (!self->takes_kw_args) {
178 nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments"));
179 }
180 mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]);
181continue2:;
182 }
183
184 DEBUG_printf("Args with kws flattened: ");
185 dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
186
187 // fill in defaults for positional args
188 mp_obj_t *d = &code_state->state[n_state - self->n_pos_args];
189 mp_obj_t *s = &self->extra_args[self->n_def_args - 1];
Damien George42f3de92014-10-03 17:44:14 +0000190 for (mp_uint_t i = self->n_def_args; i > 0; i--, d++, s--) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100191 if (*d == MP_OBJ_NULL) {
192 *d = *s;
193 }
194 }
195
196 DEBUG_printf("Args after filling default positional: ");
197 dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
198
199 // Check that all mandatory positional args are specified
200 while (d < &code_state->state[n_state]) {
201 if (*d++ == MP_OBJ_NULL) {
202 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
203 "function missing required positional argument #%d", &code_state->state[n_state] - d));
204 }
205 }
206
207 // Check that all mandatory keyword args are specified
208 // Fill in default kw args if we have them
209 for (mp_uint_t i = 0; i < self->n_kwonly_args; i++) {
210 if (code_state->state[n_state - 1 - self->n_pos_args - i] == MP_OBJ_NULL) {
211 mp_map_elem_t *elem = NULL;
212 if (self->has_def_kw_args) {
Damien George1084b0f2014-10-25 15:07:02 +0100213 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 +0100214 }
215 if (elem != NULL) {
216 code_state->state[n_state - 1 - self->n_pos_args - i] = elem->value;
217 } else {
218 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
Damien George1084b0f2014-10-25 15:07:02 +0100219 "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 +0100220 }
221 }
222 }
223
224 } else {
225 // no keyword arguments given
226 if (self->n_kwonly_args != 0) {
227 nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
228 "function missing keyword-only argument"));
229 }
230 if (self->takes_kw_args) {
231 *var_pos_kw_args = mp_obj_new_dict(0);
232 }
233 }
234
235 // bytecode prelude: initialise closed over variables
Damien George1084b0f2014-10-25 15:07:02 +0100236 const byte *ip = code_state->ip;
Damien Georgeb534e1b2014-09-04 14:44:01 +0100237 for (mp_uint_t n_local = *ip++; n_local > 0; n_local--) {
238 mp_uint_t local_num = *ip++;
239 code_state->state[n_state - 1 - local_num] = mp_obj_new_cell(code_state->state[n_state - 1 - local_num]);
240 }
241
242 // now that we skipped over the prelude, set the ip for the VM
243 code_state->ip = ip;
244
245 DEBUG_printf("Calling: n_pos_args=%d, n_kwonly_args=%d\n", self->n_pos_args, self->n_kwonly_args);
246 dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
247 dump_args(code_state->state, n_state);
248}