compile.c
1 
6 #include <assert.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <stdint.h>
11 #include <unistd.h>
12 #include <kuroko/kuroko.h>
13 #include <kuroko/vm.h>
14 #include <kuroko/compiler.h>
15 #include <kuroko/util.h>
16 
17 #include "simple-repl.h"
18 
19 #ifdef ISDEBUG
20 #define DEBUGOUT(...) fprintf(stderr, __VA_ARGS__)
21 #else
22 #define DEBUGOUT(...)
23 #endif
24 
25 struct MarshalHeader {
26  uint8_t magic[4]; /* K R K B */
27  uint8_t version[4]; /* 1 0 1 2 */
28 } __attribute__((packed));
29 
31  uint32_t nameInd;
32  uint32_t docInd;
33  uint32_t qualInd;
34  uint16_t reqArgs;
35  uint16_t kwArgs;
36  uint16_t posArgs;
37  uint16_t upvalues;
38  uint32_t locals;
39  uint32_t bcSize;
40  uint32_t lmSize;
41  uint32_t ctSize;
42  uint8_t flags;
43  uint8_t data[];
44 } __attribute__((packed));
45 
46 struct LineMapEntry {
47  uint16_t startOffset;
48  uint16_t line;
49 } __attribute__((packed));
50 
51 NativeFn ListPop;
52 NativeFn ListAppend;
53 NativeFn ListContains;
54 NativeFn ListIndex;
55 KrkValue SeenFunctions;
56 KrkValue UnseenFunctions;
57 KrkValue StringTable;
58 
59 static void _initListFunctions(void) {
60  KrkValue _list_pop;
61  KrkValue _list_append;
62  KrkValue _list_contains;
63  KrkValue _list_index;
64  krk_tableGet(&vm.baseClasses->listClass->methods, OBJECT_VAL(S("pop")), &_list_pop);
65  krk_tableGet(&vm.baseClasses->listClass->methods, OBJECT_VAL(S("append")), &_list_append);
66  krk_tableGet(&vm.baseClasses->listClass->methods, OBJECT_VAL(S("__contains__")), &_list_contains);
67  krk_tableGet(&vm.baseClasses->listClass->methods, OBJECT_VAL(S("index")), &_list_index);
68  ListPop = AS_NATIVE(_list_pop)->function;
69  ListAppend = AS_NATIVE(_list_append)->function;
70  ListContains = AS_NATIVE(_list_contains)->function;
71  ListIndex = AS_NATIVE(_list_index)->function;
72 }
73 
74 static void findInterpreter(char * argv[]) {
75 #ifdef _WIN32
76  vm.binpath = strdup(_pgmptr);
77 #else
78  /* Try asking /proc */
79  char * binpath = realpath("/proc/self/exe", NULL);
80  if (!binpath || (access(binpath, X_OK) != 0)) {
81  if (strchr(argv[0], '/')) {
82  binpath = realpath(argv[0], NULL);
83  } else {
84  /* Search PATH for argv[0] */
85  char * _path = strdup(getenv("PATH"));
86  char * path = _path;
87  while (path) {
88  char * next = strchr(path,':');
89  if (next) *next++ = '\0';
90 
91  char tmp[4096];
92  snprintf(tmp, 4096, "%s/%s", path, argv[0]);
93  if (access(tmp, X_OK) == 0) {
94  binpath = strdup(tmp);
95  break;
96  }
97  path = next;
98  }
99  free(_path);
100  }
101  }
102  if (binpath) {
103  vm.binpath = binpath;
104  } /* Else, give up at this point and just don't attach it at all. */
105 #endif
106 }
107 
108 static KrkString ** myStrings = NULL;
109 static size_t available = 0;
110 static size_t count = 0;
111 static size_t internString(KrkString * str) {
112  for (size_t i = 0; i < count; ++i) {
113  if (myStrings[i] == str) return i;
114  }
115 
116  if (count + 1 > available) {
117  available = (available == 0) ? 8 : (available * 2);
118  myStrings = realloc(myStrings,available * sizeof(KrkString*));
119  }
120 
121  myStrings[count] = str;
122  return count++;
123 }
124 
125 static int doStringTable(FILE * out) {
126  uint32_t stringCount = count;
127  fwrite(&stringCount, 1, sizeof(uint32_t), out);
128 
129  for (size_t i = 0; i < count; ++i) {
130  uint32_t strLen = myStrings[i]->length;
131  fwrite(&strLen, 1, sizeof(uint32_t), out);
132  fwrite(myStrings[i]->chars, 1, strLen, out);
133  }
134 
135  return 0;
136 }
137 
138 #define WRITE_INTEGER(i) _writeInteger(out, i)
139 static void _writeInteger(FILE* out, krk_integer_type i) {
140  if (i >= 0 && i < 256) { \
141  fwrite((uint8_t[]){'i',i}, 1, 2, out);
142  } else {
143  uint8_t data[9];
144  data[0] = 'I';
145  int64_t value = i;
146  memcpy(&data[1], &value, sizeof(int64_t));
147  fwrite(data, 1, 9, out);
148  }
149 }
150 
151 #define WRITE_FLOATING(f) _writeFloating(out, f)
152 static void _writeFloating(FILE * out, double f) {
153  uint64_t doubleOut;
154  memcpy(&doubleOut, &f, sizeof(double));
155  fwrite("d", 1, 1, out);
156  fwrite(&doubleOut, 1, sizeof(uint64_t), out);
157 }
158 
159 #define WRITE_KWARGS(k) fwrite("k",1,1,out);
160 
161 #define WRITE_STRING(s) _writeString(out, s)
162 static void _writeString(FILE * out, KrkString * s) {
163  uint32_t ind = internString(s);
164  if (ind < 256) {
165  fwrite((uint8_t[]){'s',(uint8_t)ind}, 1, 2, out);
166  } else {
167  fwrite("S",1,1,out);
168  fwrite(&ind,1,sizeof(uint32_t),out);
169  }
170 }
171 
172 #define WRITE_BYTES(b) _writeBytes(out,b)
173 static void _writeBytes(FILE * out, KrkBytes * b) {
174  if (b->length < 256) {
175  fwrite((uint8_t[]){'b', (uint8_t)b->length}, 1, 2, out);
176  fwrite(b->bytes, 1, b->length, out);
177  } else {
178  fwrite("B",1,1,out);
179  uint32_t len = b->length;
180  fwrite(&len, 1, sizeof(uint32_t), out);
181  fwrite(b->bytes, 1, b->length, out);
182  }
183 }
184 
185 #define WRITE_FUNCTION(f) _writeFunction(out,f)
186 static void _writeFunction(FILE * out, KrkCodeObject * f) {
187  /* Find this function in the function table. */
188  KrkValue this = OBJECT_VAL(f);
189  KrkValue index = ListIndex(2,(KrkValue[]){SeenFunctions,this},0);
190  if (!IS_INTEGER(index)) {
191  fprintf(stderr, "Internal error: Expected int from list.index, got '%s'\n", krk_typeName(index));
192  exit(1);
193  }
194  krk_integer_type i = AS_INTEGER(index);
195  if (i < 0) {
196  fprintf(stderr, "Internal error: expected an index, not %ld\n", (unsigned long)i);
197  exit(1);
198  }
199  if (i < 256) {
200  fwrite((uint8_t[]){'f',(uint8_t)i},1,2,out);
201  } else {
202  uint32_t val = i;
203  fwrite("F",1,1,out);
204  fwrite(&val,1,sizeof(uint32_t),out);
205  }
206 }
207 
208 static int doFirstPass(FILE * out) {
209  /* Go through all functions and build string tables and function index */
210 
211  while (AS_LIST(UnseenFunctions)->count) {
212  KrkValue nextFunc = ListPop(2,(KrkValue[]){UnseenFunctions,INTEGER_VAL(0)},0);
213  krk_push(nextFunc);
214  ListAppend(2,(KrkValue[]){SeenFunctions,nextFunc},0);
215 
216  /* Examine */
217  KrkCodeObject * func = AS_codeobject(nextFunc);
218 
219  if (func->name) internString(func->name);
220  if (func->docstring) internString(func->docstring);
221  if (func->qualname) internString(func->qualname);
222 
223  for (size_t i = 0; i < (size_t)func->potentialPositionals + !!(func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS); ++i) {
224  internString(AS_STRING(func->positionalArgNames.values[i]));
225  }
226 
227  for (size_t i = 0; i < (size_t)func->keywordArgs + !!(func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS); ++i) {
228  internString(AS_STRING(func->keywordArgNames.values[i]));
229  }
230 
231  for (size_t i = 0; i < func->chunk.constants.count; ++i) {
232  KrkValue value = func->chunk.constants.values[i];
233  if (IS_OBJECT(value)) {
234  if (IS_STRING(value)) {
235  internString(AS_STRING(value));
236  } else if (IS_codeobject(value)) {
237  /* If we haven't seen this function yet, append it to the list */
238  krk_push(value);
239  KrkValue boolResult = ListContains(2,(KrkValue[]){SeenFunctions,value},0);
240  if (IS_BOOLEAN(boolResult) && AS_BOOLEAN(boolResult) == 0) {
241  ListAppend(2,(KrkValue[]){UnseenFunctions,value},0);
242  }
243  krk_pop();
244  }
245  }
246  }
247 
248  krk_pop();
249  }
250 
251  return 0;
252 }
253 
254 static int doSecondPass(FILE * out) {
255 
256  /* Write the function count */
257  uint32_t functionCount = AS_LIST(SeenFunctions)->count;
258  fwrite(&functionCount, 1, sizeof(uint32_t), out);
259 
260  for (size_t funcIndex = 0; funcIndex < AS_LIST(SeenFunctions)->count; ++funcIndex) {
261  KrkCodeObject * func = AS_codeobject(AS_LIST(SeenFunctions)->values[funcIndex]);
262 
263  uint8_t flags = func->obj.flags;
264 
265  struct FunctionHeader header = {
266  func->name ? internString(func->name) : UINT32_MAX,
267  func->docstring ? internString(func->docstring) : UINT32_MAX,
268  func->qualname ? internString(func->qualname) : UINT32_MAX,
269  func->requiredArgs,
270  func->keywordArgs,
271  func->potentialPositionals,
272  func->upvalueCount,
273  func->localNameCount,
274  func->chunk.count,
275  func->chunk.linesCount,
276  func->chunk.constants.count,
277  flags
278  };
279 
280  fwrite(&header, 1, sizeof(struct FunctionHeader), out);
281 
282  /* Argument names first */
283  for (size_t i = 0; i < (size_t)func->potentialPositionals + !!(func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS); ++i) {
284  WRITE_STRING(AS_STRING(func->positionalArgNames.values[i]));
285  }
286 
287  for (size_t i = 0; i < (size_t)func->keywordArgs + !!(func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS); ++i) {
288  WRITE_STRING(AS_STRING(func->keywordArgNames.values[i]));
289  }
290 
291  /* Bytecode operations next */
292  fwrite(func->chunk.code, 1, func->chunk.count, out);
293 
294  /* Now let's do line references */
295  for (size_t i = 0; i < func->chunk.linesCount; ++i) {
296  struct LineMapEntry entry = {
297  func->chunk.lines[i].startOffset,
298  func->chunk.lines[i].line
299  };
300  fwrite(&entry, 1, sizeof(struct LineMapEntry), out);
301  }
302 
303  for (size_t i = 0; i < func->chunk.constants.count; ++i) {
304  KrkValue * val = &func->chunk.constants.values[i];
305  switch (KRK_VAL_TYPE(*val)) {
306  case KRK_VAL_OBJECT:
307  switch (AS_OBJECT(*val)->type) {
308  case KRK_OBJ_STRING:
309  WRITE_STRING(AS_STRING(*val));
310  break;
311  case KRK_OBJ_BYTES:
312  WRITE_BYTES(AS_BYTES(*val));
313  break;
314  case KRK_OBJ_CODEOBJECT:
315  WRITE_FUNCTION(AS_codeobject(*val));
316  break;
317  default:
318  fprintf(stderr,
319  "Invalid object found in constants table,"
320  "this marashal format can not store '%s'\n",
321  krk_typeName(*val));
322  return 1;
323  }
324  break;
325  case KRK_VAL_KWARGS: /* This should always be KWARGS_VAL(0) */
326  WRITE_KWARGS(AS_INTEGER(*val));
327  break;
328  case KRK_VAL_INTEGER:
329  WRITE_INTEGER(AS_INTEGER(*val));
330  break;
331  default:
332  if (IS_FLOATING(*val)) {
333  WRITE_FLOATING(AS_FLOATING(*val));
334  break;
335  }
336  fprintf(stderr,
337  "Invalid value found in constants table,"
338  "this marashal format can not store '%s'\n",
339  krk_typeName(*val));
340  return 1;
341  }
342  }
343  }
344 
345  return 0;
346 }
347 
348 static int compileFile(char * fileName) {
349  /* Compile source file */
350  FILE * f = fopen(fileName, "r");
351  if (!f) {
352  fprintf(stderr, "%s: %s\n", fileName, strerror(errno));
353  return 1;
354  }
355 
356  fseek(f, 0, SEEK_END);
357  size_t size = ftell(f);
358  fseek(f, 0, SEEK_SET);
359  char * buf = malloc(size + 1);
360  if (fread(buf, 1, size, f) != size) {
361  fprintf(stderr, "%s: %s\n", fileName, strerror(errno));
362  return 2;
363  }
364  fclose(f);
365  buf[size] = '\0';
366 
367  FILE * out = fopen("out.kbc", "w");
368 
369 
370  krk_startModule("__main__");
371  KrkCodeObject * func = krk_compile(buf, fileName);
372 
373  if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) {
374  fprintf(stderr, "%s: exception during compilation:\n", fileName);
376  return 3;
377  }
378 
379  /* Start with the primary header */
380  struct MarshalHeader header = {
381  {'K','R','K','B'},
382  {'1','0','1','2'},
383  };
384 
385  fwrite(&header, 1, sizeof(header), out);
386 
387  SeenFunctions = krk_list_of(0,NULL,0);
388  krk_push(SeenFunctions);
389 
390  UnseenFunctions = krk_list_of(1,(KrkValue[]){OBJECT_VAL(func)},0);
391  krk_push(UnseenFunctions);
392 
393  if (doFirstPass(out)) return 1;
394  if (doStringTable(out)) return 1;
395  if (doSecondPass(out)) return 1;
396 
397  krk_pop(); /* UnseenFunctions */
398  krk_pop(); /* SeenFunctions */
399 
400  return 0;
401 }
402 
403 static KrkValue valueFromConstant(int i, FILE * inFile) {
404  uint8_t c = fgetc(inFile);
405  DEBUGOUT(" %4lu: ", (unsigned long)i);
406  switch (c) {
407  case 'i':
408  case 'I': {
409  int64_t inVal = (c == 'i') ? fgetc(inFile) : 0;
410  if (c == 'I') assert(fread(&inVal, 1, sizeof(int64_t), inFile) == sizeof(int64_t));
411  DEBUGOUT("int %lld\n", (long long)inVal);
412  return INTEGER_VAL(inVal);
413  }
414  case 's':
415  case 'S': {
416  uint32_t ind = (c == 's') ? fgetc(inFile) : 0;
417  if (c == 'S') assert(fread(&ind, 1, sizeof(uint32_t), inFile) == sizeof(uint32_t));
418  KrkValue valOut = AS_LIST(StringTable)->values[ind];
419 #ifdef ISDEBUG
420  fprintf(stderr, "str #%lu ", (unsigned long)ind);
421  krk_printValueSafe(stderr, valOut);
422  fprintf(stderr, "\n");
423 #endif
424  return valOut;
425  }
426  case 'd': {
427  double val;
428  assert(fread(&val, 1, sizeof(double), inFile) == sizeof(double));
429  DEBUGOUT("float %g\n", val);
430  return FLOATING_VAL(val);
431  }
432  case 'f':
433  case 'F': {
434  uint32_t ind = (c == 'f') ? fgetc(inFile) : 0;
435  if (c == 'F') assert(fread(&ind, 1, sizeof(uint32_t), inFile) == sizeof(uint32_t));
436  DEBUGOUT("function #%lu\n", (unsigned long)ind);
437  return AS_LIST(SeenFunctions)->values[ind];
438  }
439  case 'k': {
440  return KWARGS_VAL(0);
441  }
442  default: {
443  fprintf(stderr, "Unknown type '%c'.\n", c);
444  return NONE_VAL();
445  }
446  }
447 }
448 
449 static int readFile(char * fileName) {
450 
451  FILE * inFile = fopen(fileName, "r");
452  if (!inFile) {
453  fprintf(stderr, "%s: %s\n", fileName, strerror(errno));
454  return 1;
455  }
456 
457  krk_startModule("__main__");
458 
459  StringTable = krk_list_of(0,NULL,0);
460  krk_push(StringTable);
461 
462  SeenFunctions = krk_list_of(0,NULL,0);
463  krk_push(SeenFunctions);
464 
465  struct MarshalHeader header;
466  assert(fread(&header, 1, sizeof(header), inFile) == sizeof(header));
467 
468  if (memcmp(header.magic,(uint8_t[]){'K','R','K','B'},4) != 0)
469  return fprintf(stderr, "Invalid header.\n"), 1;
470 
471  if (memcmp(header.version,(uint8_t[]){'1','0','1','2'},4) != 0)
472  return fprintf(stderr, "Bytecode is for a different version.\n"), 2;
473 
474  /* Read string table */
475  uint32_t stringCount;
476  assert(fread(&stringCount, 1, sizeof(uint32_t), inFile) == sizeof(uint32_t));
477 
478  DEBUGOUT("[String Table (count=%lu)]\n", (unsigned long)stringCount);
479  for (size_t i = 0; i < (size_t)stringCount; ++i) {
480  uint32_t strLen;
481  assert(fread(&strLen, 1, sizeof(uint32_t), inFile) == sizeof(uint32_t));
482 
483  char * strVal = malloc(strLen+1);
484  assert(fread(strVal, 1, strLen, inFile) == strLen);
485  strVal[strLen] = '\0';
486 
487  /* Create a string */
488  krk_push(OBJECT_VAL(krk_takeString(strVal,strLen)));
489  ListAppend(2,(KrkValue[]){StringTable, krk_peek(0)},0);
490 #ifdef ISDEBUG
491  fprintf(stderr, "%04lu: ", (unsigned long)i);
492  krk_printValueSafe(stderr, krk_peek(0));
493  fprintf(stderr, " (len=%lu)\n", (unsigned long)strLen);
494 #endif
495  krk_pop();
496  }
497 
498  uint32_t functionCount;
499  assert(fread(&functionCount, 1, sizeof(uint32_t), inFile) == sizeof(uint32_t));
500 
501  DEBUGOUT("[Code Objects (count=%lu)]\n", (unsigned long)functionCount);
502 
503  for (size_t i = 0; i < (size_t)functionCount; ++i) {
504  krk_push(OBJECT_VAL(krk_newCodeObject()));
505  ListAppend(2,(KrkValue[]){SeenFunctions, krk_peek(0)}, 0);
506  krk_pop();
507  }
508 
509  for (size_t i = 0; i < (size_t)functionCount; ++i) {
510 
511  KrkCodeObject * self = AS_codeobject(AS_LIST(SeenFunctions)->values[i]);
512 
513  struct FunctionHeader function;
514  assert(fread(&function, 1, sizeof(function), inFile) == sizeof(function));
515 
516  if (function.nameInd != UINT32_MAX) {
517  self->name = AS_STRING(AS_LIST(StringTable)->values[function.nameInd]);
518  } else {
519  self->name = S("__main__");
520  }
521 
522 #ifdef ISDEBUG
523  fprintf(stderr, "<");
524  krk_printValueSafe(stderr,OBJECT_VAL(self->name));
525  fprintf(stderr, ">\n");
526 #endif
527 
528  if (function.docInd != UINT32_MAX) {
529  self->docstring = AS_STRING(AS_LIST(StringTable)->values[function.docInd]);
530  }
531 
532  if (function.qualInd != UINT32_MAX) {
533  self->qualname = AS_STRING(AS_LIST(StringTable)->values[function.qualInd]);
534  }
535 
536 #ifdef ISDEBUG
537  fprintf(stderr, " Required arguments: %lu\n", (unsigned long)function.reqArgs);
538  fprintf(stderr, " Keyword arguments: %lu\n", (unsigned long)function.kwArgs);
539  fprintf(stderr, " Named locals: %lu\n", (unsigned long)function.locals);
540  fprintf(stderr, " Bytes of bytecode: %lu\n", (unsigned long)function.bcSize);
541  fprintf(stderr, " Line mappings: %lu\n", (unsigned long)function.lmSize);
542  fprintf(stderr, " Constants: %lu\n", (unsigned long)function.ctSize);
543 #endif
544 
545  self->requiredArgs = function.reqArgs;
546  self->keywordArgs = function.kwArgs;
547  self->obj.flags = function.flags;
548  self->upvalueCount = function.upvalues;
549  self->potentialPositionals = function.posArgs;
550 
551  self->totalArguments = self->potentialPositionals + !!(self->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) + !!(self->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS);
552 
553  /* Read argument names */
554  DEBUGOUT(" [Positional Arguments]\n");
555  for (size_t i = 0; i < (size_t)function.posArgs + !!(self->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS); i++) {
556  krk_writeValueArray(&self->positionalArgNames, valueFromConstant(i,inFile));
557  }
558 
559  DEBUGOUT(" [Keyword Arguments]\n");
560  for (size_t i = 0; i < (size_t)function.kwArgs + !!(self->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS); i++) {
561  krk_writeValueArray(&self->keywordArgNames, valueFromConstant(i,inFile));
562  }
563 
564  /* Skip bytecode for now, we'll look at it later */
565  self->chunk.capacity = function.bcSize;
566  self->chunk.code = malloc(self->chunk.capacity);
567  assert(fread(self->chunk.code, 1, self->chunk.capacity, inFile) == self->chunk.capacity);
568  self->chunk.count = self->chunk.capacity;
569 
570  self->chunk.linesCapacity = function.lmSize;
571  self->chunk.lines = malloc(sizeof(KrkLineMap) * function.lmSize);
572  /* Examine line mappings */
573  DEBUGOUT(" [Line Mapping]\n");
574  for (size_t i = 0; i < function.lmSize; ++i) {
575  struct LineMapEntry entry;
576  assert(fread(&entry,1,sizeof(struct LineMapEntry),inFile) == sizeof(struct LineMapEntry));
577 
578 
579  DEBUGOUT(" %4lu = 0x%04lx\n", (unsigned long)entry.line, (unsigned long)entry.startOffset);
580 
581  self->chunk.lines[i].startOffset = entry.startOffset;
582  self->chunk.lines[i].line = entry.line;
583  }
584  self->chunk.linesCount = self->chunk.linesCapacity;
585 
586  /* Read constants */
587  DEBUGOUT(" [Constants Table]\n");
588  for (size_t i = 0; i < function.ctSize; i++) {
589  krk_writeValueArray(&self->chunk.constants, valueFromConstant(i, inFile));
590  }
591  }
592 
593  /* Now we can move the first function up and call it to initialize a module */
594  krk_pop();
595  krk_pop();
596  krk_push(AS_LIST(SeenFunctions)->values[0]);
597 
598  KrkClosure * closure = krk_newClosure(AS_codeobject(krk_peek(0)), OBJECT_VAL(krk_currentThread.module));
599  krk_pop();
600  krk_push(OBJECT_VAL(closure));
601 
602  krk_callValue(OBJECT_VAL(closure), 0, 1);
603 
604  /* TODO: Load module into module table */
605  KrkValue result = krk_runNext();
606  if (IS_INTEGER(result)) return AS_INTEGER(result);
607  else {
608  return runSimpleRepl();
609  }
610 }
611 
612 int main(int argc, char * argv[]) {
613  if (argc < 2) {
614  fprintf(stderr, "usage: %s path-to-file.krk\n"
615  " %s -r path-to-file.kbc\n",
616  argv[0], argv[0]);
617  return 1;
618  }
619 
620  /* Initialize a VM */
621  findInterpreter(argv);
622  krk_initVM(0);
623  _initListFunctions();
624 
625  if (argc < 3) {
626  return compileFile(argv[1]);
627  } else if (argc == 3 && !strcmp(argv[1],"-r")) {
628  return readFile(argv[2]);
629  }
630 
631  return 1;
632 }
KrkCodeObject * krk_compile(const char *src, char *fileName)
Compile a source string to bytecode.
Definition: compiler.c:3986
Exported methods for the source compiler.
void krk_dumpTraceback(void)
If there is an active exception, print a traceback to stderr.
Definition: exceptions.c:351
Top-level header with configuration macros.
Immutable sequence of bytes.
Definition: object.h:105
size_t length
Length of data in bytes.
Definition: object.h:107
uint8_t * bytes
Pointer to separately-stored bytes data.
Definition: object.h:108
Function object.
Definition: object.h:169
KrkClosure * krk_newClosure(KrkCodeObject *function, KrkValue globals)
Create a new function object.
Definition: object.c:286
Code object.
Definition: object.h:144
unsigned short potentialPositionals
Precalculated positional arguments for complex argument processing.
Definition: object.h:148
KrkChunk chunk
Bytecode data.
Definition: object.h:151
KrkValueArray positionalArgNames
Array of names for positional arguments (and *args)
Definition: object.h:154
unsigned short keywordArgs
Arity of keyword (default) arguments.
Definition: object.h:147
KrkObj obj
Base.
Definition: object.h:145
KrkValueArray keywordArgNames
Array of names for keyword-only arguments (and **kwargs)
Definition: object.h:155
KrkCodeObject * krk_newCodeObject(void)
Create a new, uninitialized code object.
Definition: object.c:261
KrkString * name
Name of the function.
Definition: object.h:152
Map entry of instruction offsets to line numbers.
Definition: chunk.h:19
KrkValue krk_list_of(int argc, const KrkValue argv[], int hasKw)
Create a list object.
Definition: obj_list.c:30
uint16_t flags
General object flags, mostly related to garbage collection.
Definition: object.h:43
Immutable sequence of Unicode codepoints.
Definition: object.h:93
KrkString * krk_takeString(char *chars, size_t length)
Yield ownership of a C string to the GC and obtain a string object.
Definition: object.c:205
size_t length
String length in bytes.
Definition: object.h:95
int krk_tableGet(KrkTable *table, KrkValue key, KrkValue *value)
Obtain the value associated with a key in a table.
Definition: table.c:178
int flags
Definition: vm.h:174
KrkInstance * module
Definition: vm.h:172
void krk_initVM(int flags)
Initialize the VM at program startup.
Definition: vm.c:904
KrkValue * values
Definition: value.h:73
void krk_writeValueArray(KrkValueArray *array, KrkValue value)
Add a value to a value array.
Definition: value.c:17
size_t count
Definition: value.h:72
Stack reference or primative value.
const char * krk_typeName(KrkValue value)
Get the name of the type of a value.
Definition: vm.c:1023
int krk_callValue(KrkValue callee, int argCount, int callableOnStack)
Call a callable value in the current stack context.
Definition: vm.c:722
void krk_printValueSafe(FILE *f, KrkValue value)
Print a value without calling the VM.
Definition: value.c:52
Utilities for creating native bindings.
Core API for the bytecode virtual machine.
KrkValue krk_runNext(void)
Continue VM execution until the next exit trigger.
Definition: vm.c:3211
#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
KrkInstance * krk_startModule(const char *name)
Set up a new module object in the current thread.
Definition: vm.c:3219
KrkValue krk_peek(int distance)
Peek down from the top of the stack.
Definition: vm.c:178