Numworks Epsilon  1.4.1
Graphing Calculator Operating System
objgenerator.c
Go to the documentation of this file.
1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2013, 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 <stdlib.h>
29 #include <assert.h>
30 
31 #include "py/runtime.h"
32 #include "py/bc.h"
33 #include "py/objgenerator.h"
34 #include "py/objfun.h"
35 
36 /******************************************************************************/
37 /* generator wrapper */
38 
39 typedef struct _mp_obj_gen_wrap_t {
43 
44 typedef struct _mp_obj_gen_instance_t {
49 
50 STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
51  mp_obj_gen_wrap_t *self = MP_OBJ_TO_PTR(self_in);
52  mp_obj_fun_bc_t *self_fun = (mp_obj_fun_bc_t*)self->fun;
53  assert(self_fun->base.type == &mp_type_fun_bc);
54 
55  // bytecode prelude: get state size and exception stack size
56  size_t n_state = mp_decode_uint_value(self_fun->bytecode);
57  size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(self_fun->bytecode));
58 
59  // allocate the generator object, with room for local stack and exception stack
61  n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t));
62  o->base.type = &mp_type_gen_instance;
63 
64  o->globals = self_fun->globals;
65  o->code_state.fun_bc = self_fun;
66  o->code_state.ip = 0;
67  mp_setup_code_state(&o->code_state, n_args, n_kw, args);
68  return MP_OBJ_FROM_PTR(o);
69 }
70 
72  { &mp_type_type },
73  .name = MP_QSTR_generator,
74  .call = gen_wrap_call,
75  .unary_op = mp_generic_unary_op,
76 };
77 
80  o->base.type = &mp_type_gen_wrap;
81  o->fun = MP_OBJ_TO_PTR(fun);
82  return MP_OBJ_FROM_PTR(o);
83 }
84 
85 /******************************************************************************/
86 /* generator instance */
87 
88 STATIC void gen_instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
89  (void)kind;
90  mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in);
91  mp_printf(print, "<generator object '%q' at %p>", mp_obj_fun_get_name(MP_OBJ_FROM_PTR(self->code_state.fun_bc)), self);
92 }
93 
94 mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) {
96  mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in);
97  if (self->code_state.ip == 0) {
98  // Trying to resume already stopped generator
99  *ret_val = MP_OBJ_STOP_ITERATION;
100  return MP_VM_RETURN_NORMAL;
101  }
102  if (self->code_state.sp == self->code_state.state - 1) {
103  if (send_value != mp_const_none) {
104  mp_raise_TypeError("can't send non-None value to a just-started generator");
105  }
106  } else {
107  *self->code_state.sp = send_value;
108  }
109  mp_obj_dict_t *old_globals = mp_globals_get();
110  mp_globals_set(self->globals);
111  mp_vm_return_kind_t ret_kind = mp_execute_bytecode(&self->code_state, throw_value);
112  mp_globals_set(old_globals);
113 
114  switch (ret_kind) {
115  case MP_VM_RETURN_NORMAL:
116  default:
117  // Explicitly mark generator as completed. If we don't do this,
118  // subsequent next() may re-execute statements after last yield
119  // again and again, leading to side effects.
120  // TODO: check how return with value behaves under such conditions
121  // in CPython.
122  self->code_state.ip = 0;
123  *ret_val = *self->code_state.sp;
124  break;
125 
126  case MP_VM_RETURN_YIELD:
127  *ret_val = *self->code_state.sp;
128  if (*ret_val == MP_OBJ_STOP_ITERATION) {
129  self->code_state.ip = 0;
130  }
131  break;
132 
133  case MP_VM_RETURN_EXCEPTION: {
134  size_t n_state = mp_decode_uint_value(self->code_state.fun_bc->bytecode);
135  self->code_state.ip = 0;
136  *ret_val = self->code_state.state[n_state - 1];
137  break;
138  }
139  }
140 
141  return ret_kind;
142 }
143 
144 STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value) {
145  mp_obj_t ret;
146  switch (mp_obj_gen_resume(self_in, send_value, throw_value, &ret)) {
147  case MP_VM_RETURN_NORMAL:
148  default:
149  // Optimize return w/o value in case generator is used in for loop
150  if (ret == mp_const_none || ret == MP_OBJ_STOP_ITERATION) {
151  return MP_OBJ_STOP_ITERATION;
152  } else {
154  }
155 
156  case MP_VM_RETURN_YIELD:
157  return ret;
158 
160  // TODO: Optimization of returning MP_OBJ_STOP_ITERATION is really part
161  // of mp_iternext() protocol, but this function is called by other methods
162  // too, which may not handled MP_OBJ_STOP_ITERATION.
165  if (val == mp_const_none) {
166  return MP_OBJ_STOP_ITERATION;
167  }
168  }
169  nlr_raise(ret);
170  }
171 }
172 
175 }
176 
178  mp_obj_t ret = gen_resume_and_raise(self_in, send_value, MP_OBJ_NULL);
179  if (ret == MP_OBJ_STOP_ITERATION) {
181  } else {
182  return ret;
183  }
184 }
185 
186 STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_send_obj, gen_instance_send);
187 
190  mp_obj_t exc = (n_args == 2) ? args[1] : args[2];
191 
193  if (ret == MP_OBJ_STOP_ITERATION) {
195  } else {
196  return ret;
197  }
198 }
199 
200 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(gen_instance_throw_obj, 2, 4, gen_instance_throw);
201 
203  mp_obj_t ret;
205  case MP_VM_RETURN_YIELD:
206  mp_raise_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit");
207 
208  // Swallow StopIteration & GeneratorExit (== successful close), and re-raise any other
210  // ret should always be an instance of an exception class
213  return mp_const_none;
214  }
215  nlr_raise(ret);
216 
217  default:
218  // The only choice left is MP_VM_RETURN_NORMAL which is successful close
219  return mp_const_none;
220  }
221 }
222 
223 STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_close_obj, gen_instance_close);
224 
226  { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&gen_instance_close_obj) },
227  { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&gen_instance_send_obj) },
228  { MP_ROM_QSTR(MP_QSTR_throw), MP_ROM_PTR(&gen_instance_throw_obj) },
229 };
230 
232 
234  { &mp_type_type },
235  .name = MP_QSTR_generator,
236  .print = gen_instance_print,
237  .unary_op = mp_generic_unary_op,
238  .getiter = mp_identity_getiter,
239  .iternext = gen_instance_iternext,
240  .locals_dict = (mp_obj_dict_t*)&gen_instance_locals_dict,
241 };
mp_obj_base_t base
Definition: objfun.h:32
const mp_obj_type_t mp_type_fun_bc
Definition: objfun.c:331
NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const char *msg)
Definition: runtime.c:1448
const byte * ip
Definition: bc.h:78
const mp_obj_type_t mp_type_gen_wrap
Definition: objgenerator.c:71
mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc)
Definition: vm.c:127
#define assert(e)
Definition: assert.h:9
#define mp_const_none
Definition: obj.h:614
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(gen_instance_throw_obj, 2, 4, gen_instance_throw)
#define MP_OBJ_IS_TYPE(o, t)
Definition: obj.h:254
mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type)
Definition: objexcept.c:329
mp_obj_t mp_generic_unary_op(mp_unary_op_t op, mp_obj_t o_in)
Definition: obj.c:530
STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args)
Definition: objgenerator.c:50
STATIC mp_obj_t gen_instance_iternext(mp_obj_t self_in)
Definition: objgenerator.c:173
mp_obj_base_t base
Definition: objgenerator.c:40
const mp_obj_type_t mp_type_StopIteration
mp_obj_type_t * mp_obj_get_type(mp_const_obj_t o_in)
Definition: obj.c:40
STATIC mp_obj_t gen_instance_throw(size_t n_args, const mp_obj_t *args)
Definition: objgenerator.c:189
#define MP_ROM_QSTR(q)
Definition: obj.h:241
#define MP_OBJ_FROM_PTR(p)
Definition: obj.h:233
mp_obj_fun_bc_t * fun_bc
Definition: bc.h:77
mp_obj_base_t base
Definition: objgenerator.c:45
#define MP_ROM_PTR(p)
Definition: obj.h:242
STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value)
Definition: objgenerator.c:144
mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val)
Definition: objgenerator.c:94
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args, const mp_obj_t *args)
Definition: objexcept.c:338
STATIC mp_obj_t gen_instance_close(mp_obj_t self_in)
Definition: objgenerator.c:202
struct _mp_obj_gen_wrap_t mp_obj_gen_wrap_t
#define STATIC
Definition: mpconfig.h:1178
bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo)
Definition: objtype.c:1143
mp_vm_return_kind_t
Definition: runtime.h:31
mp_print_kind_t
Definition: obj.h:412
STATIC mp_obj_t gen_instance_send(mp_obj_t self_in, mp_obj_t send_value)
Definition: objgenerator.c:177
#define m_new_obj_var(obj_type, var_type, var_num)
Definition: misc.h:62
STATIC void gen_instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind)
Definition: objgenerator.c:88
mp_obj_dict_t * globals
Definition: objgenerator.c:46
qstr mp_obj_fun_get_name(mp_const_obj_t fun)
Definition: objfun.c:154
#define MP_OBJ_NULL
Definition: obj.h:73
#define mp_check_self(pred)
Definition: runtime.h:161
mp_uint_t mp_decode_uint_value(const byte *ptr)
Definition: bc.c:61
const mp_obj_type_t mp_type_GeneratorExit
args
Definition: i18n.py:175
const byte * bytecode
Definition: objfun.h:34
void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args)
Definition: bc.c:108
unsigned char byte
Definition: misc.h:37
STATIC MP_DEFINE_CONST_DICT(gen_instance_locals_dict, gen_instance_locals_dict_table)
const mp_obj_type_t mp_type_type
Definition: objtype.c:969
STATIC const mp_rom_map_elem_t gen_instance_locals_dict_table[]
Definition: objgenerator.c:225
mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun)
Definition: objgenerator.c:78
mp_obj_t mp_identity_getiter(mp_obj_t self, mp_obj_iter_buf_t *iter_buf)
Definition: obj.c:507
mp_code_state_t code_state
Definition: objgenerator.c:47
mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in)
Definition: objexcept.c:183
#define MP_OBJ_TO_PTR(o)
Definition: obj.h:228
STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_send_obj, gen_instance_send)
#define nlr_raise(val)
Definition: nlr.h:89
qstr name
Definition: obj.h:478
#define MP_OBJ_STOP_ITERATION
Definition: obj.h:74
STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_close_obj, gen_instance_close)
const byte * mp_decode_uint_skip(const byte *ptr)
Definition: bc.c:67
uint64_t mp_obj_t
Definition: obj.h:39
int mp_printf(const mp_print_t *print, const char *fmt,...)
Definition: mpprint.c:380
NORETURN void mp_raise_TypeError(const char *msg)
Definition: runtime.c:1460
mp_obj_dict_t * globals
Definition: objfun.h:33
#define m_new_obj(type)
Definition: misc.h:60
struct _mp_obj_gen_instance_t mp_obj_gen_instance_t
const mp_obj_type_t mp_type_gen_instance
Definition: objgenerator.c:233
const mp_obj_type_t mp_type_RuntimeError
const struct _mp_obj_exception_t mp_const_GeneratorExit_obj
Definition: objexcept.c:97