module_fileio.c
1 
5 #include <assert.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <errno.h>
9 #include <dirent.h>
10 
11 #include <kuroko/vm.h>
12 #include <kuroko/value.h>
13 #include <kuroko/object.h>
14 #include <kuroko/memory.h>
15 #include <kuroko/util.h>
16 
17 
18 static KrkClass * fileio_File;
19 static KrkClass * fileio_BinaryFile;
20 static KrkClass * fileio_Directory;
21 
26 struct File {
27  KrkInstance inst;
28  FILE * filePtr;
29  int unowned;
30 };
31 
32 #define IS_File(o) (krk_isInstanceOf(o, fileio_File))
33 #define AS_File(o) ((struct File*)AS_OBJECT(o))
34 
35 #define IS_BinaryFile(o) (krk_isInstanceOf(o, fileio_BinaryFile))
36 #define AS_BinaryFile(o) ((struct File*)AS_OBJECT(o))
37 
42 struct Directory {
43  KrkInstance inst;
44  DIR * dirPtr;
45 };
46 
47 #define IS_Directory(o) (krk_isInstanceOf(o, fileio_Directory))
48 #define AS_Directory(o) ((struct Directory*)AS_OBJECT(o))
49 
50 #define CURRENT_CTYPE struct File *
51 #define CURRENT_NAME self
52 
53 KRK_Function(open) {
54  FUNCTION_TAKES_AT_LEAST(1);
55  FUNCTION_TAKES_AT_MOST(2);
56  CHECK_ARG(0,str,KrkString*,filename);
57  if (argc == 2 && !IS_STRING(argv[1])) return TYPE_ERROR(str,argv[1]);
58  KrkValue arg;
59  int isBinary = 0;
60  if (argc == 1) {
61  arg = OBJECT_VAL(S("r"));
62  krk_push(arg); /* Will be peeked to find arg string for fopen */
63  } else {
64  /* Check mode against allowable modes */
65  if (AS_STRING(argv[1])->length == 0) return krk_runtimeError(vm.exceptions->typeError, "open: mode string must not be empty");
66  for (size_t i = 0; i < AS_STRING(argv[1])->length-1; ++i) {
67  if (AS_CSTRING(argv[1])[i] == 'b') {
68  return krk_runtimeError(vm.exceptions->typeError, "open: 'b' mode indicator must appear at end of mode string");
69  }
70  }
71  arg = argv[1];
72  if (AS_CSTRING(argv[1])[AS_STRING(argv[1])->length-1] == 'b') {
73  KrkValue tmp = OBJECT_VAL(krk_copyString(AS_CSTRING(argv[1]), AS_STRING(argv[1])->length-1));
74  krk_push(tmp);
75  isBinary = 1;
76  } else {
77  krk_push(arg);
78  }
79  }
80 
81  FILE * file = fopen(filename->chars, AS_CSTRING(krk_peek(0)));
82  if (!file) return krk_runtimeError(vm.exceptions->ioError, "open: failed to open file; system returned: %s", strerror(errno));
83 
84  /* Now let's build an object to hold it */
85  KrkInstance * fileObject = krk_newInstance(isBinary ? fileio_BinaryFile : fileio_File);
86  krk_push(OBJECT_VAL(fileObject));
87 
88  /* Let's put the filename in there somewhere... */
89  krk_attachNamedValue(&fileObject->fields, "filename", OBJECT_VAL(filename));
90  krk_attachNamedValue(&fileObject->fields, "modestr", arg);
91 
92  ((struct File*)fileObject)->filePtr = file;
93 
94  krk_pop();
95  krk_pop();
96  return OBJECT_VAL(fileObject);
97 }
98 
99 #define BLOCK_SIZE 1024
100 
101 KRK_Method(File,__repr__) {
102  METHOD_TAKES_NONE();
103  KrkValue filename;
104  KrkValue modestr;
105  if (!krk_tableGet(&self->inst.fields, OBJECT_VAL(S("filename")), &filename) || !IS_STRING(filename)) return krk_runtimeError(vm.exceptions->baseException, "Corrupt File");
106  if (!krk_tableGet(&self->inst.fields, OBJECT_VAL(S("modestr")), &modestr) || !IS_STRING(modestr)) return krk_runtimeError(vm.exceptions->baseException, "Corrupt File");
107 
108  return krk_stringFromFormat("<%s file '%S', mode '%S' at %p>", self->filePtr ? "open" : "closed", AS_STRING(filename), AS_STRING(modestr), (void*)self);
109 }
110 
111 KRK_Method(File,readline) {
112  METHOD_TAKES_NONE();
113  FILE * file = self->filePtr;
114 
115  if (!file || feof(file)) {
116  return NONE_VAL();
117  }
118 
119  size_t sizeRead = 0;
120  size_t spaceAvailable = 0;
121  char * buffer = NULL;
122 
123  do {
124  if (spaceAvailable < sizeRead + BLOCK_SIZE) {
125  spaceAvailable = (spaceAvailable ? spaceAvailable * 2 : (2 * BLOCK_SIZE));
126  buffer = realloc(buffer, spaceAvailable);
127  }
128 
129  char * target = &buffer[sizeRead];
130  while (sizeRead < spaceAvailable) {
131  int c = fgetc(file);
132  if (krk_currentThread.flags & KRK_THREAD_SIGNALLED) break;
133  if (c < 0) break;
134  sizeRead++;
135  *target++ = c;
136  if (c == '\n') goto _finish_line;
137  }
138 
139  if (krk_currentThread.flags & KRK_THREAD_SIGNALLED) break;
140  } while (!feof(file));
141 
142 _finish_line: (void)0;
143  if (sizeRead == 0) {
144  free(buffer);
145  return NONE_VAL();
146  }
147 
148  /* Make a new string to fit our output. */
149  KrkString * out = krk_copyString(buffer,sizeRead);
150  free(buffer);
151  return OBJECT_VAL(out);
152 }
153 
154 KRK_Method(File,readlines) {
155  METHOD_TAKES_NONE();
156  KrkValue myList = krk_list_of(0,NULL,0);
157  krk_push(myList);
158 
159  for (;;) {
160  KrkValue line = FUNC_NAME(File,readline)(1, argv, 0);
161  if (IS_NONE(line)) break;
162  if (krk_currentThread.flags & KRK_THREAD_SIGNALLED) break;
163 
164  krk_push(line);
165  krk_writeValueArray(AS_LIST(myList), line);
166  krk_pop(); /* line */
167  }
168 
169  krk_pop(); /* myList */
170  return myList;
171 }
172 
173 KRK_Method(File,read) {
174  METHOD_TAKES_AT_MOST(1);
175 
176  krk_integer_type sizeToRead = -1;
177  if (argc > 1) {
178  CHECK_ARG(1,int,krk_integer_type,sizeFromArg);
179  if (sizeFromArg < -1) return krk_runtimeError(vm.exceptions->valueError, "size must be >= -1");
180  sizeToRead = sizeFromArg;
181  }
182 
183  /* Get the file ptr reference */
184  FILE * file = self->filePtr;
185 
186  if (!file || feof(file)) {
187  return NONE_VAL();
188  }
189 
190  /* We'll do our read entirely with some native buffers and manage them here. */
191  size_t sizeRead = 0;
192  size_t spaceAvailable = 0;
193  char * buffer = NULL;
194 
195  if (sizeToRead == -1) {
196  do {
197  if (spaceAvailable < sizeRead + BLOCK_SIZE) {
198  spaceAvailable = (spaceAvailable ? spaceAvailable * 2 : (2 * BLOCK_SIZE));
199  buffer = realloc(buffer, spaceAvailable);
200  }
201 
202  char * target = &buffer[sizeRead];
203  size_t newlyRead = fread(target, 1, BLOCK_SIZE, file);
204  if (krk_currentThread.flags & KRK_THREAD_SIGNALLED) break;
205 
206  if (newlyRead < BLOCK_SIZE) {
207  if (ferror(file)) {
208  free(buffer);
209  return krk_runtimeError(vm.exceptions->ioError, "Read error.");
210  }
211  }
212 
213  sizeRead += newlyRead;
214  } while (!feof(file));
215  } else {
216  spaceAvailable = sizeToRead;
217  buffer = realloc(buffer, spaceAvailable);
218  sizeRead = fread(buffer, 1, sizeToRead, file);
219  }
220 
221  /* Make a new string to fit our output. */
222  KrkString * out = krk_copyString(buffer,sizeRead);
223  free(buffer);
224  return OBJECT_VAL(out);
225 }
226 
227 KRK_Method(File,write) {
228  METHOD_TAKES_EXACTLY(1);
229  if (!IS_STRING(argv[1])) return TYPE_ERROR(str,argv[1]);
230  /* Find the file ptr reference */
231  FILE * file = self->filePtr;
232 
233  if (!file || feof(file)) {
234  return NONE_VAL();
235  }
236 
237  return INTEGER_VAL(fwrite(AS_CSTRING(argv[1]), 1, AS_STRING(argv[1])->length, file));
238 }
239 
240 KRK_Method(File,close) {
241  METHOD_TAKES_NONE();
242  FILE * file = self->filePtr;
243  if (file) fclose(file);
244  self->filePtr = NULL;
245  return NONE_VAL();
246 }
247 
248 KRK_Method(File,flush) {
249  METHOD_TAKES_NONE();
250  FILE * file = self->filePtr;
251  if (file) fflush(file);
252  return NONE_VAL();
253 }
254 
255 KRK_Method(File,__init__) {
256  return krk_runtimeError(vm.exceptions->typeError, "File objects can not be instantiated; use fileio.open() to obtain File objects.");
257 }
258 
259 KRK_Method(File,__enter__) {
260  return NONE_VAL();
261 }
262 KRK_Method(File,__exit__) {
263  return FUNC_NAME(File,close)(1,argv,0);
264 }
265 
266 static void makeFileInstance(KrkInstance * module, const char name[], FILE * file, const char mode[]) {
267  KrkInstance * fileObject = krk_newInstance(fileio_File);
268  krk_push(OBJECT_VAL(fileObject));
269  KrkValue filename = OBJECT_VAL(krk_copyString(name,strlen(name)));
270  krk_push(filename);
271  KrkValue modestr = OBJECT_VAL(krk_copyString(mode,strlen(mode)));
272  krk_push(modestr);
273 
274  krk_attachNamedValue(&fileObject->fields, "filename", filename);
275  krk_attachNamedValue(&fileObject->fields, "modestr", modestr);
276  ((struct File*)fileObject)->filePtr = file;
277  ((struct File*)fileObject)->unowned = 1;
278 
279  krk_attachNamedObject(&module->fields, name, (KrkObj*)fileObject);
280 
281  krk_pop(); /* modestr */
282  krk_pop(); /* filename */
283  krk_pop(); /* fileObject */
284 }
285 
286 KRK_Method(BinaryFile,readline) {
287  METHOD_TAKES_NONE();
288  FILE * file = self->filePtr;
289 
290  if (!file || feof(file)) {
291  return NONE_VAL();
292  }
293 
294  size_t sizeRead = 0;
295  size_t spaceAvailable = 0;
296  char * buffer = NULL;
297 
298  do {
299  if (spaceAvailable < sizeRead + BLOCK_SIZE) {
300  spaceAvailable = (spaceAvailable ? spaceAvailable * 2 : (2 * BLOCK_SIZE));
301  buffer = realloc(buffer, spaceAvailable);
302  }
303 
304  char * target = &buffer[sizeRead];
305  while (sizeRead < spaceAvailable) {
306  int c = fgetc(file);
307  if (krk_currentThread.flags & KRK_THREAD_SIGNALLED) break;
308  if (c < 0) break;
309  sizeRead++;
310  *target++ = c;
311  if (c == '\n') goto _finish_line;
312  }
313 
314  if (krk_currentThread.flags & KRK_THREAD_SIGNALLED) break;
315  } while (!feof(file));
316 
317 _finish_line: (void)0;
318  if (sizeRead == 0) {
319  free(buffer);
320  return NONE_VAL();
321  }
322 
323  /* Make a new string to fit our output. */
324  KrkBytes * out = krk_newBytes(sizeRead, (unsigned char*)buffer);
325  free(buffer);
326  return OBJECT_VAL(out);
327 }
328 
329 KRK_Method(BinaryFile,readlines) {
330  METHOD_TAKES_NONE();
331  KrkValue myList = krk_list_of(0,NULL,0);
332  krk_push(myList);
333 
334  for (;;) {
335  KrkValue line = FUNC_NAME(BinaryFile,readline)(1, argv, 0);
336  if (IS_NONE(line)) break;
337  if (krk_currentThread.flags & KRK_THREAD_SIGNALLED) break;
338 
339  krk_push(line);
340  krk_writeValueArray(AS_LIST(myList), line);
341  krk_pop(); /* line */
342  }
343 
344  krk_pop(); /* myList */
345  return myList;
346 }
347 
348 KRK_Method(BinaryFile,read) {
349  METHOD_TAKES_AT_MOST(1);
350 
351  krk_integer_type sizeToRead = -1;
352  if (argc > 1) {
353  CHECK_ARG(1,int,krk_integer_type,sizeFromArg);
354  if (sizeFromArg < -1) return krk_runtimeError(vm.exceptions->valueError, "size must be >= -1");
355  sizeToRead = sizeFromArg;
356  }
357 
358  /* Get the file ptr reference */
359  FILE * file = self->filePtr;
360 
361  if (!file || feof(file)) {
362  return NONE_VAL();
363  }
364 
365  /* We'll do our read entirely with some native buffers and manage them here. */
366  size_t sizeRead = 0;
367  size_t spaceAvailable = 0;
368  char * buffer = NULL;
369 
370  if (sizeToRead == -1) {
371  do {
372  if (spaceAvailable < sizeRead + BLOCK_SIZE) {
373  spaceAvailable = (spaceAvailable ? spaceAvailable * 2 : (2 * BLOCK_SIZE));
374  buffer = realloc(buffer, spaceAvailable);
375  }
376 
377  char * target = &buffer[sizeRead];
378  size_t newlyRead = fread(target, 1, BLOCK_SIZE, file);
379 
380  if (krk_currentThread.flags & KRK_THREAD_SIGNALLED) break;
381 
382  if (newlyRead < BLOCK_SIZE) {
383  if (ferror(file)) {
384  free(buffer);
385  return krk_runtimeError(vm.exceptions->ioError, "Read error.");
386  }
387  }
388 
389  sizeRead += newlyRead;
390  } while (!feof(file));
391  } else {
392  spaceAvailable = sizeToRead;
393  buffer = realloc(buffer, spaceAvailable);
394  sizeRead = fread(buffer, 1, sizeToRead, file);
395  }
396 
397  /* Make a new string to fit our output. */
398  KrkBytes * out = krk_newBytes(sizeRead, (unsigned char*)buffer);
399  free(buffer);
400  return OBJECT_VAL(out);
401 }
402 
403 KRK_Method(BinaryFile,write) {
404  METHOD_TAKES_EXACTLY(1);
405  if (!IS_BYTES(argv[1])) return TYPE_ERROR(bytes,argv[1]);
406  /* Find the file ptr reference */
407  FILE * file = self->filePtr;
408 
409  if (!file || feof(file)) {
410  return NONE_VAL();
411  }
412 
413  return INTEGER_VAL(fwrite(AS_BYTES(argv[1])->bytes, 1, AS_BYTES(argv[1])->length, file));
414 }
415 
416 #undef CURRENT_CTYPE
417 
418 static void _file_sweep(KrkInstance * self) {
419  struct File * me = (void *)self;
420  if (me->filePtr && !me->unowned) {
421  fclose(me->filePtr);
422  me->filePtr = NULL;
423  }
424 }
425 
426 static void _dir_sweep(KrkInstance * self) {
427  struct Directory * me = (void *)self;
428  if (me->dirPtr) {
429  closedir(me->dirPtr);
430  me->dirPtr = NULL;
431  }
432 }
433 
434 KRK_Function(opendir) {
435  FUNCTION_TAKES_EXACTLY(1);
436  CHECK_ARG(0,str,KrkString*,path);
437 
438  DIR * dir = opendir(path->chars);
439  if (!dir) return krk_runtimeError(vm.exceptions->ioError, "opendir: %s", strerror(errno));
440 
441  struct Directory * dirObj = (void *)krk_newInstance(fileio_Directory);
442  krk_push(OBJECT_VAL(dirObj));
443 
444  krk_attachNamedValue(&dirObj->inst.fields, "path", OBJECT_VAL(path));
445  dirObj->dirPtr = dir;
446 
447  return krk_pop();
448 }
449 
450 #define CURRENT_CTYPE struct Directory *
451 
452 KRK_Method(Directory,__call__) {
453  METHOD_TAKES_NONE();
454  if (!self->dirPtr) return argv[0];
455  struct dirent * entry = readdir(self->dirPtr);
456  if (!entry) return argv[0];
457 
458  KrkValue outDict = krk_dict_of(0, NULL, 0);
459  krk_push(outDict);
460 
461  krk_attachNamedValue(AS_DICT(outDict), "name", OBJECT_VAL(krk_copyString(entry->d_name,strlen(entry->d_name))));
462  krk_attachNamedValue(AS_DICT(outDict), "inode", INTEGER_VAL(entry->d_ino));
463 
464  return krk_pop();
465 }
466 
467 KRK_Method(Directory,__iter__) {
468  METHOD_TAKES_NONE();
469  return argv[0];
470 }
471 
472 KRK_Method(Directory,close) {
473  METHOD_TAKES_NONE();
474  if (self->dirPtr) {
475  closedir(self->dirPtr);
476  self->dirPtr = NULL;
477  }
478  return NONE_VAL();
479 }
480 
481 KRK_Method(Directory,__repr__) {
482  METHOD_TAKES_NONE();
483  KrkValue path;
484  if (!krk_tableGet(&self->inst.fields, OBJECT_VAL(S("path")), &path) || !IS_STRING(path))
485  return krk_runtimeError(vm.exceptions->valueError, "corrupt Directory");
486 
487  return krk_stringFromFormat("<%s directory '%S' at %p>", self->dirPtr ? "open" : "closed", AS_STRING(path), (void*)self);
488 }
489 
490 KRK_Method(Directory,__enter__) {
491  return NONE_VAL();
492 }
493 KRK_Method(Directory,__exit__) {
494  return FUNC_NAME(Directory,close)(1,argv,0);
495 }
496 
497 KRK_Module(fileio) {
498  KRK_DOC(module,
499  "@brief Provides access to C <stdio> buffered file I/O functions.\n\n"
500  "The @c fileio module provides classes and functions for reading "
501  "and writing files using the system's buffer I/O interfaces, as "
502  "well as classes for listing the contents of directories."
503  );
504 
505  /* Define a class to represent files. (Should this be a helper method?) */
506  KrkClass * File = krk_makeClass(module, &fileio_File, "File", KRK_BASE_CLASS(object));
507  KRK_DOC(File,"Interface to a buffered file stream.");
508  File->allocSize = sizeof(struct File);
509  File->_ongcsweep = _file_sweep;
510 
511  /* Add methods to it... */
512  KRK_DOC(BIND_METHOD(File,read), "@brief Read from the stream.\n"
513  "@arguments bytes=-1\n\n"
514  "Reads up to @p bytes bytes from the stream. If @p bytes is @c -1 then reading "
515  "will continue until the system returns _end of file_.");
516  KRK_DOC(BIND_METHOD(File,readline), "@brief Read one line from the stream.");
517  KRK_DOC(BIND_METHOD(File,readlines), "@brief Read the entire stream and return a list of lines.");
518  KRK_DOC(BIND_METHOD(File,write), "@brief Write to the stream.\n"
519  "@arguments data\n\n"
520  "Writes the contents of @p data to the stream.");
521  KRK_DOC(BIND_METHOD(File,close), "@brief Close the stream and flush any remaining buffered writes.");
522  KRK_DOC(BIND_METHOD(File,flush), "@brief Flush unbuffered writes to the stream.");
523  BIND_METHOD(File,__repr__);
524  KRK_DOC(BIND_METHOD(File,__init__), "@bsnote{%File objects can not be initialized using this constructor. "
525  "Use the <a class=\"el\" href=\"#open\">open()</a> function instead.}");
526  BIND_METHOD(File,__enter__);
527  BIND_METHOD(File,__exit__);
529 
530  KrkClass * BinaryFile = krk_makeClass(module, &fileio_BinaryFile, "BinaryFile", File);
531  KRK_DOC(BinaryFile,
532  "Equivalent to @ref File but using @ref bytes instead of string @ref str."
533  );
534  BIND_METHOD(BinaryFile,read);
535  BIND_METHOD(BinaryFile,readline);
536  BIND_METHOD(BinaryFile,readlines);
537  BIND_METHOD(BinaryFile,write);
538  krk_finalizeClass(BinaryFile);
539 
540  KrkClass * Directory = krk_makeClass(module, &fileio_Directory, "Directory", KRK_BASE_CLASS(object));
542  "Represents an opened file system directory."
543  );
544  Directory->allocSize = sizeof(struct Directory);
545  Directory->_ongcsweep = _dir_sweep;
546  BIND_METHOD(Directory,__repr__);
547  KRK_DOC(BIND_METHOD(Directory,__iter__), "@brief Iterates over the contents of the directory.\n\n"
548  "Each iteration returns @ref dict with two entries: <i>\"name\"</i> and <i>\"inode\"</i>.");
549  KRK_DOC(BIND_METHOD(Directory,__call__), "@brief Yields one iteration through the directory.");
550  BIND_METHOD(Directory,__enter__);
551  KRK_DOC(BIND_METHOD(Directory,__exit__), "@brief Closes the directory upon exit from a @c with block.");
552  KRK_DOC(BIND_METHOD(Directory,close), "@brief Close the directory.\n\nFurther reads can not be made after the directory has been closed.");
554 
555  /* Make an instance for stdout, stderr, and stdin */
556  makeFileInstance(module, "stdin", stdin, "r");
557  makeFileInstance(module, "stdout", stdout, "w");
558  makeFileInstance(module, "stderr", stderr, "w");
559 
560  /* Our base will be the open method */
561  KRK_DOC(BIND_FUNC(module,open), "@brief Open a file.\n"
562  "@arguments path,mode=\"r\"\n\n"
563  "Opens @p path using the modestring @p mode. Supported modestring characters depend on the system implementation. "
564  "If the last character of @p mode is @c 'b' a @ref BinaryFile will be returned. If the file could not be opened, "
565  "an @ref IOError will be raised.");
566  KRK_DOC(BIND_FUNC(module,opendir), "@brief Open a directory for scanning.\n"
567  "@arguments path\n\n"
568  "Opens the directory at @p path and returns a @ref Directory object. If @p path could not be opened or is not "
569  "a directory, @ref IOError will be raised.");
570 }
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.
KRK_Module(socket)
Struct definitions for core object types.
OBject for a C DIR* stream.
Definition: module_fileio.c:42
Object for a C FILE* stream.
Definition: module_fileio.c:26
Immutable sequence of bytes.
Definition: object.h:105
KrkBytes * krk_newBytes(size_t length, uint8_t *source)
Create a new byte array.
Definition: object.c:367
Type object.
Definition: object.h:215
KrkClass * krk_makeClass(KrkInstance *module, KrkClass **_class, const char *name, KrkClass *base)
Convenience function for creating new types.
Definition: vm.c:164
void krk_finalizeClass(KrkClass *_class)
Finalize a class by collecting pointers to core methods.
Definition: vm.c:189
KrkValue krk_dict_of(int argc, const KrkValue argv[], int hasKw)
Create a dict object.
Definition: obj_dict.c:19
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
KrkTable fields
Attributes table.
Definition: object.h:284
KrkValue krk_list_of(int argc, const KrkValue argv[], int hasKw)
Create a list object.
Definition: obj_list.c:30
The most basic object type.
Definition: object.h:41
Immutable sequence of Unicode codepoints.
Definition: object.h:93
KrkString * krk_copyString(const char *chars, size_t length)
Obtain a string object representation of the given C string.
Definition: object.c:224
int krk_tableGet(KrkTable *table, KrkValue key, KrkValue *value)
Obtain the value associated with a key in a table.
Definition: table.c:211
void krk_attachNamedObject(KrkTable *table, const char name[], KrkObj *obj)
Attach an object to an attribute table.
Definition: vm.c:808
void krk_attachNamedValue(KrkTable *table, const char name[], KrkValue obj)
Attach a value to an attribute table.
Definition: vm.c:794
int flags
Definition: vm.h:165
void krk_writeValueArray(KrkValueArray *array, KrkValue value)
Add a value to a value array.
Definition: value.c:17
Stack reference or primative value.
Utilities for creating native bindings.
#define KRK_DOC(thing, text)
Attach documentation to a thing of various types.
Definition: util.h:304
Definitions for primitive stack references.
Core API for the bytecode virtual machine.
krk_threadLocal KrkThreadState krk_currentThread
Thread-local VM state.
#define vm
Convenience macro for namespacing.
Definition: vm.h:257
KrkValue krk_pop(void)
Pop the top of the stack.
Definition: vm.c:131
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