blob: d58480f9e7e715ac14b55f49e19462dfc74023f1 [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"
Damien Georgeeb7bfcb2014-01-04 15:57:35 +00009#include "mpqstr.h"
Damiend99b0522013-12-21 18:17:45 +000010#include "obj.h"
11#include "runtime.h"
12#include "bc.h"
13
14/******************************************************************************/
15/* generator wrapper */
16
17typedef struct _mp_obj_gen_wrap_t {
18 mp_obj_base_t base;
Damien George0ff88392014-01-02 20:57:05 +000019 uint n_state;
Damiend99b0522013-12-21 18:17:45 +000020 mp_obj_t *fun;
21} mp_obj_gen_wrap_t;
22
Damien George20006db2014-01-18 14:10:48 +000023mp_obj_t gen_wrap_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
Damiend99b0522013-12-21 18:17:45 +000024 mp_obj_gen_wrap_t *self = self_in;
25 mp_obj_t self_fun = self->fun;
26 assert(MP_OBJ_IS_TYPE(self_fun, &fun_bc_type));
27 int bc_n_args;
28 uint bc_n_state;
29 const byte *bc_code;
30 mp_obj_fun_bc_get(self_fun, &bc_n_args, &bc_n_state, &bc_code);
31 if (n_args != bc_n_args) {
Damien Georgeeb7bfcb2014-01-04 15:57:35 +000032 nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError, "function takes %d positional arguments but %d were given", (const char*)(machine_int_t)bc_n_args, (const char*)(machine_int_t)n_args));
Damiend99b0522013-12-21 18:17:45 +000033 }
Damien George20006db2014-01-18 14:10:48 +000034 if (n_kw != 0) {
35 nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "function does not take keyword arguments"));
36 }
Damien George6baf76e2013-12-30 22:32:17 +000037
Damien George0ff88392014-01-02 20:57:05 +000038 return mp_obj_new_gen_instance(bc_code, self->n_state, n_args, args);
Damiend99b0522013-12-21 18:17:45 +000039}
40
41const mp_obj_type_t gen_wrap_type = {
42 { &mp_const_type },
43 "generator",
Damien George20006db2014-01-18 14:10:48 +000044 .call = gen_wrap_call,
Damiend99b0522013-12-21 18:17:45 +000045};
46
Damien George6baf76e2013-12-30 22:32:17 +000047mp_obj_t mp_obj_new_gen_wrap(uint n_locals, uint n_stack, mp_obj_t fun) {
Damiend99b0522013-12-21 18:17:45 +000048 mp_obj_gen_wrap_t *o = m_new_obj(mp_obj_gen_wrap_t);
49 o->base.type = &gen_wrap_type;
50 // we have at least 3 locals so the bc can write back fast[0,1,2] safely; should improve how this is done
Damien George6baf76e2013-12-30 22:32:17 +000051 o->n_state = (n_locals < 3 ? 3 : n_locals) + n_stack;
Damiend99b0522013-12-21 18:17:45 +000052 o->fun = fun;
53 return o;
54}
55
56/******************************************************************************/
57/* generator instance */
58
59typedef struct _mp_obj_gen_instance_t {
60 mp_obj_base_t base;
Damiend99b0522013-12-21 18:17:45 +000061 const byte *ip;
62 mp_obj_t *sp;
Damien George20006db2014-01-18 14:10:48 +000063 uint n_state;
Damien George0ff88392014-01-02 20:57:05 +000064 mp_obj_t state[];
Damiend99b0522013-12-21 18:17:45 +000065} mp_obj_gen_instance_t;
66
Paul Sokolovsky76d982e2014-01-13 19:19:16 +020067void gen_instance_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
Damiend99b0522013-12-21 18:17:45 +000068 print(env, "<generator object 'fun-name' at %p>", self_in);
69}
70
71mp_obj_t gen_instance_getiter(mp_obj_t self_in) {
72 return self_in;
73}
74
75mp_obj_t gen_instance_iternext(mp_obj_t self_in) {
76 mp_obj_gen_instance_t *self = self_in;
Damien George20006db2014-01-18 14:10:48 +000077 bool yield = mp_execute_byte_code_2(&self->ip, &self->state[self->n_state - 1], &self->sp);
Damiend99b0522013-12-21 18:17:45 +000078 if (yield) {
79 return *self->sp;
80 } else {
81 if (*self->sp == mp_const_none) {
82 return mp_const_stop_iteration;
83 } else {
84 // TODO return StopIteration with value *self->sp
85 return mp_const_stop_iteration;
86 }
87 }
88}
89
90const mp_obj_type_t gen_instance_type = {
91 { &mp_const_type },
92 "generator",
Damien George97209d32014-01-07 15:58:30 +000093 .print = gen_instance_print,
94 .getiter = gen_instance_getiter,
95 .iternext = gen_instance_iternext,
Damiend99b0522013-12-21 18:17:45 +000096};
97
Damien George0ff88392014-01-02 20:57:05 +000098mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_state, int n_args, const mp_obj_t *args) {
99 mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, mp_obj_t, n_state);
Damiend99b0522013-12-21 18:17:45 +0000100 o->base.type = &gen_instance_type;
Damien George0ff88392014-01-02 20:57:05 +0000101 o->ip = bytecode;
Damien George20006db2014-01-18 14:10:48 +0000102 o->sp = &o->state[0] - 1; // sp points to top of stack, which starts off 1 below the state
103 o->n_state = n_state;
Damien George0ff88392014-01-02 20:57:05 +0000104
Damien George20006db2014-01-18 14:10:48 +0000105 // copy args to end of state array, in reverse (that's how mp_execute_byte_code_2 needs it)
Damien George0ff88392014-01-02 20:57:05 +0000106 for (int i = 0; i < n_args; i++) {
Damien George20006db2014-01-18 14:10:48 +0000107 o->state[n_state - 1 - i] = args[i];
Damien George0ff88392014-01-02 20:57:05 +0000108 }
109
110 // TODO
111 // prelude for making cells (closed over variables)
112 // for now we just make sure there are no cells variables
113 // need to work out how to implement closed over variables in generators
114 assert(o->ip[0] == 0);
115 o->ip += 1;
116
Damiend99b0522013-12-21 18:17:45 +0000117 return o;
118}