obj_gen.c
Go to the documentation of this file.
1 
9 #include <string.h>
10 #include <kuroko/vm.h>
11 #include <kuroko/value.h>
12 #include <kuroko/memory.h>
13 #include <kuroko/util.h>
14 #include <kuroko/debug.h>
15 
20 struct generator {
21  KrkInstance inst;
22  KrkClosure * closure;
23  KrkValue * args;
24  size_t argCount;
25  uint8_t * ip;
26  int running;
27  int started;
28  KrkValue result;
29  int type;
30  KrkThreadState fakethread;
31  KrkUpvalue * capturedUpvalues;
32 };
33 
34 #define AS_generator(o) ((struct generator *)AS_OBJECT(o))
35 #define IS_generator(o) (krk_isInstanceOf(o, KRK_BASE_CLASS(generator)))
36 
37 #define CURRENT_CTYPE struct generator *
38 #define CURRENT_NAME self
39 
40 static void _generator_close_upvalues(struct generator * self) {
41  while (self->capturedUpvalues) {
42  KrkUpvalue * upvalue = self->capturedUpvalues;
43  upvalue->closed = self->args[upvalue->location];
44  upvalue->location = -1;
45  self->capturedUpvalues = upvalue->next;
46  }
47 }
48 
49 static void _generator_gcscan(KrkInstance * _self) {
50  struct generator * self = (struct generator*)_self;
51  krk_markObject((KrkObj*)self->closure);
52  for (size_t i = 0; i < self->argCount; ++i) {
53  krk_markValue(self->args[i]);
54  }
55  for (KrkUpvalue * upvalue = self->capturedUpvalues; upvalue; upvalue = upvalue->next) {
56  krk_markObject((KrkObj*)upvalue);
57  }
58  krk_markValue(self->result);
59 }
60 
61 static void _generator_gcsweep(KrkInstance * self) {
62  _generator_close_upvalues((struct generator*)self);
63  free(((struct generator*)self)->args);
64 }
65 
66 static void _set_generator_done(struct generator * self) {
67  self->ip = NULL;
68  _generator_close_upvalues(self);
69 }
70 
82 KrkInstance * krk_buildGenerator(KrkClosure * closure, KrkValue * argsIn, size_t argCount) {
83  /* Copy the args */
84  KrkValue * args = malloc(sizeof(KrkValue) * (argCount));
85  memcpy(args, argsIn, sizeof(KrkValue) * argCount);
86 
87  /* Create a generator object */
88  struct generator * self = (struct generator *)krk_newInstance(KRK_BASE_CLASS(generator));
89  self->args = args;
90  self->argCount = argCount;
91  self->closure = closure;
92  self->ip = self->closure->function->chunk.code;
93  self->result = NONE_VAL();
94  self->type = closure->function->obj.flags & (KRK_OBJ_FLAGS_CODEOBJECT_IS_GENERATOR | KRK_OBJ_FLAGS_CODEOBJECT_IS_COROUTINE);
95  return (KrkInstance *)self;
96 }
97 
98 FUNC_SIG(generator,__init__) {
99  return krk_runtimeError(vm.exceptions->typeError, "cannot create '%s' instances", "generator");
100 }
101 
102 KRK_Method(generator,__repr__) {
103  METHOD_TAKES_NONE();
104 
105  char * typeStr = "generator";
106  if (self->type == KRK_OBJ_FLAGS_CODEOBJECT_IS_COROUTINE) {
107  /* Regular coroutine */
108  typeStr = "coroutine";
109  } else if (self->type == (KRK_OBJ_FLAGS_CODEOBJECT_IS_COROUTINE | KRK_OBJ_FLAGS_CODEOBJECT_IS_GENERATOR)) {
110  typeStr = "async_generator";
111  }
112 
113  return krk_stringFromFormat("<%s object %S at %p>",
114  typeStr, self->closure->function->name, (void*)self);
115 }
116 
117 KRK_Method(generator,__iter__) {
118  METHOD_TAKES_NONE();
119  return OBJECT_VAL(self);
120 }
121 
122 KRK_Method(generator,__call__) {
123  METHOD_TAKES_AT_MOST(1);
124  if (!self->ip) return OBJECT_VAL(self);
125  if (self->running) {
126  return krk_runtimeError(vm.exceptions->valueError, "generator already executing");
127  }
128  /* Prepare frame */
130  frame->closure = self->closure;
131  frame->ip = self->ip;
133  frame->outSlots = frame->slots;
134  frame->globals = self->closure->globalsTable;
135  frame->globalsOwner = self->closure->globalsOwner;
136 
137  /* Stick our stack on their stack */
138  for (size_t i = 0; i < self->argCount; ++i) {
139  krk_push(self->args[i]);
140  }
141 
142  /* Point any of our captured upvalues back to their actual stack locations */
143  while (self->capturedUpvalues) {
144  KrkUpvalue * upvalue = self->capturedUpvalues;
145  upvalue->owner = &krk_currentThread;
146  upvalue->location = upvalue->location + frame->slots;
147  self->capturedUpvalues = upvalue->next;
150  }
151 
152  if (self->started) {
153  krk_pop();
154  if (argc > 1) {
155  krk_push(argv[1]);
156  } else {
157  krk_push(NONE_VAL());
158  }
159  }
160 
161  /* Jump into the iterator */
162  self->running = 1;
163  size_t stackBefore = krk_currentThread.stackTop - krk_currentThread.stack;
164  KrkValue result = krk_runNext();
165  size_t stackAfter = krk_currentThread.stackTop - krk_currentThread.stack;
166  self->running = 0;
167 
168  self->started = 1;
169 
170  if (IS_KWARGS(result) && AS_INTEGER(result) == 0) {
171  self->result = krk_pop();
172  _set_generator_done(self);
173  return OBJECT_VAL(self);
174  }
175 
176  /* Was there an exception? */
177  if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) {
178  _set_generator_done(self);
180  return NONE_VAL();
181  }
182 
183  /* Redirect any remaining upvalues captured from us, and release them from the VM */
184  while (krk_currentThread.openUpvalues != NULL && krk_currentThread.openUpvalues->location >= (int)frame->slots) {
186  upvalue->location = upvalue->location - frame->slots;
187  upvalue->owner = &self->fakethread;
189  upvalue->next = self->capturedUpvalues;
190  self->capturedUpvalues = upvalue;
191  }
192 
193  /* Determine the stack state */
194  if (stackAfter > stackBefore) {
195  size_t newArgs = stackAfter - stackBefore;
196  self->args = realloc(self->args, sizeof(KrkValue) * (self->argCount + newArgs));
197  self->argCount += newArgs;
198  } else if (stackAfter < stackBefore) {
199  size_t deadArgs = stackBefore - stackAfter;
200  self->args = realloc(self->args, sizeof(KrkValue) * (self->argCount - deadArgs));
201  self->argCount -= deadArgs;
202  }
203 
204  /* Save stack entries */
205  memcpy(self->args, krk_currentThread.stackTop - self->argCount, sizeof(KrkValue) * self->argCount);
206  self->ip = frame->ip;
207  self->fakethread.stack = self->args;
208 
210 
211  return result;
212 }
213 
214 KRK_Method(generator,send) {
215  METHOD_TAKES_EXACTLY(1);
216  if (!self->started && !IS_NONE(argv[1])) {
217  return krk_runtimeError(vm.exceptions->typeError, "Can not send non-None value to just-started generator");
218  }
219  return FUNC_NAME(generator,__call__)(argc,argv,0);
220 }
221 
222 KRK_Method(generator,__finish__) {
223  METHOD_TAKES_NONE();
224  return self->result;
225 }
226 
227 /*
228  * For compatibility with Python...
229  */
230 KRK_Method(generator,gi_running) {
231  METHOD_TAKES_NONE();
232  return BOOLEAN_VAL(self->running);
233 }
234 
235 int krk_getAwaitable(void) {
236  if (IS_generator(krk_peek(0)) && AS_generator(krk_peek(0))->type == KRK_OBJ_FLAGS_CODEOBJECT_IS_COROUTINE) {
237  /* Good to go */
238  return 1;
239  }
240 
241  /* Need to try for __await__ */
242  KrkValue method = krk_valueGetAttribute_default(krk_peek(0), "__await__", NONE_VAL());
243  if (!IS_NONE(method)) {
244  krk_push(method);
245  krk_swap(1);
246  krk_pop();
248  KrkClass * _type = krk_getType(krk_peek(0));
249  if (!_type || !_type->_iter) {
250  krk_runtimeError(vm.exceptions->attributeError, "__await__ returned non-iterator of type '%T'", krk_peek(0));
251  return 0;
252  }
253  } else {
254  krk_runtimeError(vm.exceptions->attributeError, "'%T' object is not awaitable", krk_peek(0));
255  return 0;
256  }
257 
258  return 1;
259 }
260 
261 _noexport
262 void _createAndBind_generatorClass(void) {
263  KrkClass * generator = ADD_BASE_CLASS(vm.baseClasses->generatorClass, "generator", vm.baseClasses->objectClass);
264  generator->allocSize = sizeof(struct generator);
265  generator->_ongcscan = _generator_gcscan;
266  generator->_ongcsweep = _generator_gcsweep;
267  generator->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
268  BIND_METHOD(generator,__init__);
269  BIND_METHOD(generator,__iter__);
270  BIND_METHOD(generator,__call__);
271  BIND_METHOD(generator,__repr__);
272  BIND_METHOD(generator,__finish__);
273  BIND_METHOD(generator,send);
274  BIND_PROP(generator,gi_running);
276 }
Functions for debugging bytecode execution.
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
Definition: exceptions.c:460
Functions for dealing with garbage collection and memory allocation.
void krk_markValue(KrkValue value)
During a GC scan cycle, mark a value as used.
Definition: memory.c:334
void krk_markObject(KrkObj *object)
During a GC scan cycle, mark an object as used.
Definition: memory.c:321
int krk_getAwaitable(void)
Calls await
Definition: obj_gen.c:235
Represents a managed call state in a VM thread.
Definition: vm.h:44
size_t slots
Definition: vm.h:47
KrkTable * globals
Definition: vm.h:49
size_t outSlots
Definition: vm.h:48
KrkValue globalsOwner
Definition: vm.h:50
KrkClosure * closure
Definition: vm.h:45
uint8_t * ip
Definition: vm.h:46
Type object.
Definition: object.h:215
KrkObj * _iter
__iter__ Called by for ... in ..., etc.
Definition: object.h:238
void krk_finalizeClass(KrkClass *_class)
Finalize a class by collecting pointers to core methods.
Definition: vm.c:189
Function object.
Definition: object.h:195
KrkCodeObject * function
The codeobject containing the bytecode run when this function is called.
Definition: object.h:197
KrkInstance * krk_buildGenerator(KrkClosure *function, KrkValue *arguments, size_t argCount)
Convert a function into a generator with the given arguments.
Definition: obj_gen.c:82
KrkChunk chunk
Bytecode data.
Definition: object.h:170
KrkObj obj
Base.
Definition: object.h:164
An object of a class.
Definition: object.h:281
KrkInstance * krk_newInstance(KrkClass *_class)
Create a new instance of the given class.
Definition: object.c:343
KrkObj obj
Base.
Definition: object.h:282
The most basic object type.
Definition: object.h:41
uint16_t flags
General object flags, mostly related to garbage collection.
Definition: object.h:43
Execution state of a VM thread.
Definition: vm.h:152
size_t frameCount
Definition: vm.h:156
KrkValue * stack
Definition: vm.h:158
KrkUpvalue * openUpvalues
Definition: vm.h:160
KrkValue * stackTop
Definition: vm.h:159
KrkCallFrame * frames
Definition: vm.h:155
int flags
Definition: vm.h:165
Storage for values referenced from nested functions.
Definition: object.h:115
int location
Stack offset or -1 if closed.
Definition: object.h:117
KrkValue closed
Heap storage for closed value.
Definition: object.h:118
struct KrkThreadState * owner
The thread that owns the stack this upvalue belongs in.
Definition: object.h:120
struct KrkUpvalue * next
Invasive linked list pointer to next upvalue.
Definition: object.h:119
Stack reference or primative value.
KrkClass * krk_getType(KrkValue value)
Get the class representing a value.
Definition: vm.c:240
Generator object implementation.
Definition: obj_gen.c:20
Utilities for creating native bindings.
Definitions for primitive stack references.
Core API for the bytecode virtual machine.
krk_threadLocal KrkThreadState krk_currentThread
Thread-local VM state.
KrkValue krk_runNext(void)
Continue VM execution until the next exit trigger.
Definition: vm.c:3201
KrkValue krk_callStack(int argCount)
Call a callable on the stack with argCount arguments.
Definition: vm.c:732
#define vm
Convenience macro for namespacing.
Definition: vm.h:257
KrkValue krk_pop(void)
Pop the top of the stack.
Definition: vm.c:131
KrkValue krk_valueGetAttribute_default(KrkValue value, char *name, KrkValue defaultVal)
See krk_valueGetAttribute.
Definition: vm.c:1780
void krk_swap(int distance)
Swap the top of the stack of the value distance slots down.
Definition: vm.c:145
void krk_push(KrkValue value)
Push a stack value.
Definition: vm.c:118
KrkValue krk_peek(int distance)
Peek down from the top of the stack.
Definition: vm.c:139