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