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