compiler.c
Go to the documentation of this file.
1 
30 #include <assert.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/types.h>
35 
36 #include <kuroko/kuroko.h>
37 #include <kuroko/compiler.h>
38 #include <kuroko/memory.h>
39 #include <kuroko/scanner.h>
40 #include <kuroko/object.h>
41 #include <kuroko/debug.h>
42 #include <kuroko/vm.h>
43 #include <kuroko/util.h>
44 
45 #include "private.h"
46 #include "opcode_enum.h"
47 
56 typedef struct {
59  char hadError;
60  unsigned int eatingWhitespace;
61 } Parser;
62 
69 typedef enum {
70  PREC_NONE,
90 } Precedence;
91 
97 typedef enum {
103  EXPR_CLASS_PARAMETERS,
105 
106 struct RewindState;
107 struct GlobalState;
108 
116 typedef void (*ParseFn)(struct GlobalState *, int, struct RewindState *);
117 
124 typedef struct {
128 } ParseRule;
129 
137 typedef struct {
139  ssize_t depth;
140  char isCaptured;
141 } Local;
142 
148 typedef struct {
149  size_t index;
150  char isLocal;
152 } Upvalue;
153 
160 typedef enum {
171 } FunctionType;
172 
181  size_t ind;
182  struct IndexWithNext * next;
183 };
184 
188 struct LoopExit {
189  int offset;
191 };
192 
199 typedef struct Compiler {
200  struct Compiler * enclosing;
203  size_t scopeDepth;
204  size_t localCount;
205  size_t localsSpace;
207  size_t upvaluesSpace;
210  size_t loopLocalCount;
211  size_t breakCount;
212  size_t breakSpace;
213  struct LoopExit * breaks;
214  size_t continueCount;
215  size_t continueSpace;
216  struct LoopExit * continues;
221  struct Compiler * enclosed;
226  size_t optionsFlags;
229 
230 #define OPTIONS_FLAG_COMPILE_TIME_BUILTINS (1 << 0)
231 #define OPTIONS_FLAG_NO_IMPLICIT_SELF (1 << 1)
232 
240 typedef struct ClassCompiler {
245 
258 typedef struct ChunkRecorder {
259  size_t count;
260  size_t lines;
261  size_t constants;
263 
269 typedef struct RewindState {
274 
275 typedef struct GlobalState {
281 } GlobalState;
282 
283 static void _GlobalState_gcscan(KrkInstance * _self) {
284  struct GlobalState * self = (void*)_self;
285  Compiler * compiler = self->current;
286  while (compiler != NULL) {
287  if (compiler->enclosed && compiler->enclosed->codeobject) krk_markObject((KrkObj*)compiler->enclosed->codeobject);
288  krk_markObject((KrkObj*)compiler->codeobject);
289  compiler = compiler->enclosing;
290  }
291 }
292 
293 static void _GlobalState_gcsweep(KrkInstance * _self) {
294  /* nothing to do? */
295 }
296 
297 #define currentChunk() (&state->current->codeobject->chunk)
298 
299 #define EMIT_OPERAND_OP(opc, arg) do { if (arg < 256) { emitBytes(opc, arg); } \
300  else { emitBytes(opc ## _LONG, arg >> 16); emitBytes(arg >> 8, arg); } } while (0)
301 
302 static int isMethod(int type) {
303  return type == TYPE_METHOD || type == TYPE_INIT || type == TYPE_COROUTINE_METHOD;
304 }
305 
306 static int isCoroutine(int type) {
307  return type == TYPE_COROUTINE || type == TYPE_COROUTINE_METHOD;
308 }
309 
310 static char * calculateQualName(struct GlobalState * state) {
311  static char space[1024]; /* We'll just truncate if we need to */
312  space[1023] = '\0';
313  char * writer = &space[1023];
314 
315 #define WRITE(s) do { \
316  size_t len = strlen(s); \
317  if (writer - len < space) goto _exit; \
318  writer -= len; \
319  memcpy(writer, s, len); \
320 } while (0)
321 
322  WRITE(state->current->codeobject->name->chars);
323  /* Go up by _compiler_, ignore class compilers as we don't need them. */
324  Compiler * ptr = state->current->enclosing;
325  while (ptr->enclosing) { /* Ignores the top level module */
326  if (ptr->type != TYPE_CLASS) {
327  /* We must be the locals of a function. */
328  WRITE("<locals>.");
329  }
330  WRITE(".");
331  WRITE(ptr->codeobject->name->chars);
332  ptr = ptr->enclosing;
333  }
334 
335 _exit:
336  return writer;
337 }
338 
339 static ChunkRecorder recordChunk(KrkChunk * in) {
340  return (ChunkRecorder){in->count, in->linesCount, in->constants.count};
341 }
342 
343 static void rewindChunk(KrkChunk * out, ChunkRecorder from) {
344  out->count = from.count;
345  out->linesCount = from.lines;
346  out->constants.count = from.constants;
347 }
348 
349 static size_t renameLocal(struct GlobalState * state, size_t ind, KrkToken name);
350 
351 static void initCompiler(struct GlobalState * state, Compiler * compiler, FunctionType type) {
352  compiler->enclosing = state->current;
353  state->current = compiler;
354  compiler->codeobject = NULL;
355  compiler->type = type;
356  compiler->scopeDepth = 0;
357  compiler->enclosed = NULL;
358  compiler->codeobject = krk_newCodeObject();
359  compiler->localCount = 0;
360  compiler->localsSpace = 8;
361  compiler->locals = GROW_ARRAY(Local,NULL,0,8);
362  compiler->upvaluesSpace = 0;
363  compiler->upvalues = NULL;
364  compiler->breakCount = 0;
365  compiler->breakSpace = 0;
366  compiler->breaks = NULL;
367  compiler->continueCount = 0;
368  compiler->continueSpace = 0;
369  compiler->continues = NULL;
370  compiler->loopLocalCount = 0;
371  compiler->localNameCapacity = 0;
372  compiler->properties = NULL;
373  compiler->annotationCount = 0;
374  compiler->delSatisfied = 0;
375  compiler->unnamedArgs = 0;
376  compiler->optionsFlags = compiler->enclosing ? compiler->enclosing->optionsFlags : 0;
377 
378  if (type != TYPE_MODULE) {
379  state->current->codeobject->name = krk_copyString(state->parser.previous.start, state->parser.previous.length);
380  char * qualname = calculateQualName(state);
381  state->current->codeobject->qualname = krk_copyString(qualname, strlen(qualname));
382  }
383 
384  if (isMethod(type) && !(compiler->optionsFlags & OPTIONS_FLAG_NO_IMPLICIT_SELF)) {
385  Local * local = &state->current->locals[state->current->localCount++];
386  local->depth = 0;
387  local->isCaptured = 0;
388  local->name.start = "self";
389  local->name.length = 4;
390  renameLocal(state, 0, local->name);
391  state->current->codeobject->requiredArgs = 1;
393  }
394 
395  if (type == TYPE_CLASS) {
396  Local * local = &state->current->locals[state->current->localCount++];
397  local->depth = 0;
398  local->isCaptured = 0;
399  local->name.start = "";
400  local->name.length = 0;
401  renameLocal(state, 0, local->name);
402  state->current->codeobject->requiredArgs = 1;
404  }
405 
406  if (isCoroutine(type)) state->current->codeobject->obj.flags |= KRK_OBJ_FLAGS_CODEOBJECT_IS_COROUTINE;
407 }
408 
409 static void rememberClassProperty(struct GlobalState * state, size_t ind) {
410  struct IndexWithNext * me = malloc(sizeof(struct IndexWithNext));
411  me->ind = ind;
412  me->next = state->current->properties;
413  state->current->properties = me;
414 }
415 
416 static void parsePrecedence(struct GlobalState * state, Precedence precedence);
417 static ParseRule * getRule(KrkTokenType type);
418 
419 /* These need to be forward declared or the ordering just gets really confusing... */
420 static void defDeclaration(struct GlobalState * state);
421 static void asyncDeclaration(struct GlobalState * state, int);
422 static void statement(struct GlobalState * state);
423 static void declaration(struct GlobalState * state);
424 static KrkToken classDeclaration(struct GlobalState * state);
425 static void declareVariable(struct GlobalState * state);
426 static void string(struct GlobalState * state, int exprType, RewindState *rewind);
427 static KrkToken decorator(struct GlobalState * state, size_t level, FunctionType type);
428 static void complexAssignment(struct GlobalState * state, ChunkRecorder before, KrkScanner oldScanner, Parser oldParser, size_t targetCount, int parenthesized, size_t argBefore, size_t argAfter);
429 static void complexAssignmentTargets(struct GlobalState * state, KrkScanner oldScanner, Parser oldParser, size_t targetCount, int parenthesized, size_t argBefore, size_t argAfter);
430 static int invalidTarget(struct GlobalState * state, int exprType, const char * description);
431 static void call(struct GlobalState * state, int exprType, RewindState *rewind);
432 
433 static void finishError(struct GlobalState * state, KrkToken * token) {
434  if (!token->linePtr) token->linePtr = token->start;
435  size_t i = 0;
436  while (token->linePtr[i] && token->linePtr[i] != '\n') i++;
437 
438  krk_attachNamedObject(&AS_INSTANCE(krk_currentThread.currentException)->fields, "line", (KrkObj*)krk_copyString(token->linePtr, i));
439  krk_attachNamedObject(&AS_INSTANCE(krk_currentThread.currentException)->fields, "file", (KrkObj*)currentChunk()->filename);
440  krk_attachNamedValue (&AS_INSTANCE(krk_currentThread.currentException)->fields, "lineno", INTEGER_VAL(token->line));
441  krk_attachNamedValue (&AS_INSTANCE(krk_currentThread.currentException)->fields, "colno", INTEGER_VAL(token->col));
442  krk_attachNamedValue (&AS_INSTANCE(krk_currentThread.currentException)->fields, "width", INTEGER_VAL(token->literalWidth));
443 
444  if (state->current->codeobject->name) {
445  krk_attachNamedObject(&AS_INSTANCE(krk_currentThread.currentException)->fields, "func", (KrkObj*)state->current->codeobject->name);
446  } else {
447  KrkValue name = NONE_VAL();
448  krk_tableGet(&krk_currentThread.module->fields, vm.specialMethodNames[METHOD_NAME], &name);
449  krk_attachNamedValue(&AS_INSTANCE(krk_currentThread.currentException)->fields, "func", name);
450  }
451 
452  state->parser.hadError = 1;
453 }
454 
455 #ifdef KRK_NO_DOCUMENTATION
456 # define raiseSyntaxError(token, ...) do { if (state->parser.hadError) break; krk_runtimeError(vm.exceptions->syntaxError, "syntax error"); finishError(state,token); } while (0)
457 #else
458 # define raiseSyntaxError(token, ...) do { if (state->parser.hadError) break; krk_runtimeError(vm.exceptions->syntaxError, __VA_ARGS__); finishError(state,token); } while (0)
459 #endif
460 
461 #define error(...) raiseSyntaxError(&state->parser.previous, __VA_ARGS__)
462 #define errorAtCurrent(...) raiseSyntaxError(&state->parser.current, __VA_ARGS__)
463 
464 static void _advance(struct GlobalState * state) {
465  state->parser.previous = state->parser.current;
466 
467  for (;;) {
468  state->parser.current = krk_scanToken(&state->scanner);
469 
470  if (state->parser.eatingWhitespace &&
471  (state->parser.current.type == TOKEN_INDENTATION || state->parser.current.type == TOKEN_EOL)) continue;
472 
473  if (state->parser.current.type == TOKEN_RETRY) continue;
474  if (state->parser.current.type != TOKEN_ERROR) break;
475 
476  errorAtCurrent("%s", state->parser.current.start);
477  break;
478  }
479 }
480 
481 #define advance() _advance(state)
482 
483 static void _skipToEnd(struct GlobalState * state) {
484  while (state->parser.current.type != TOKEN_EOF) advance();
485 }
486 
487 #define skipToEnd() _skipToEnd(state)
488 
489 static void _startEatingWhitespace(struct GlobalState * state) {
490  state->parser.eatingWhitespace++;
491  if (state->parser.current.type == TOKEN_INDENTATION || state->parser.current.type == TOKEN_EOL) advance();
492 }
493 
494 #define startEatingWhitespace() _startEatingWhitespace(state)
495 
496 static void _stopEatingWhitespace(struct GlobalState * state) {
497  if (state->parser.eatingWhitespace == 0) {
498  error("Internal scanner error: Invalid nesting of `startEatingWhitespace`/`stopEatingWhitespace` calls.");
499  }
500  state->parser.eatingWhitespace--;
501 }
502 
503 #define stopEatingWhitespace() _stopEatingWhitespace(state)
504 
505 static void _consume(struct GlobalState * state, KrkTokenType type, const char * message) {
506  if (state->parser.current.type == type) {
507  advance();
508  return;
509  }
510 
511  if (state->parser.current.type == TOKEN_EOL || state->parser.current.type == TOKEN_EOF) {
512  state->parser.current = state->parser.previous;
513  }
514  errorAtCurrent("%s", message);
515 }
516 
517 #define consume(...) _consume(state,__VA_ARGS__)
518 
519 static int _check(struct GlobalState * state, KrkTokenType type) {
520  return state->parser.current.type == type;
521 }
522 
523 #define check(t) _check(state,t)
524 
525 static int _match(struct GlobalState * state, KrkTokenType type) {
526  if (!check(type)) return 0;
527  advance();
528  return 1;
529 }
530 
531 #define match(t) _match(state,t)
532 
533 static int identifiersEqual(KrkToken * a, KrkToken * b) {
534  return (a->length == b->length && memcmp(a->start, b->start, a->length) == 0);
535 }
536 
537 static KrkToken _syntheticToken(struct GlobalState * state, const char * text) {
538  KrkToken token;
539  token.start = text;
540  token.length = (int)strlen(text);
541  token.line = state->parser.previous.line;
542  return token;
543 }
544 
545 #define syntheticToken(t) _syntheticToken(state,t)
546 
547 static void _emitByte(struct GlobalState * state, uint8_t byte) {
548  krk_writeChunk(currentChunk(), byte, state->parser.previous.line);
549 }
550 
551 #define emitByte(b) _emitByte(state,b)
552 
553 static void _emitBytes(struct GlobalState * state, uint8_t byte1, uint8_t byte2) {
554  emitByte(byte1);
555  emitByte(byte2);
556 }
557 
558 #define emitBytes(a,b) _emitBytes(state,a,b)
559 
560 static void emitReturn(struct GlobalState * state) {
561  if (state->current->type != TYPE_LAMBDA && state->current->type != TYPE_CLASS) {
562  emitByte(OP_NONE);
563  }
564  emitByte(OP_RETURN);
565 }
566 
567 static KrkCodeObject * endCompiler(struct GlobalState * state) {
568  KrkCodeObject * function = state->current->codeobject;
569 
570  for (size_t i = 0; i < function->localNameCount; i++) {
571  if (function->localNames[i].deathday == 0) {
572  function->localNames[i].deathday = currentChunk()->count;
573  }
574  }
575  function->localNames = GROW_ARRAY(KrkLocalEntry, function->localNames, \
576  state->current->localNameCapacity, function->localNameCount); /* Shorten this down for runtime */
577 
578  if (state->current->continueCount) { state->parser.previous = state->current->continues[0].token; error("continue without loop"); }
579  if (state->current->breakCount) { state->parser.previous = state->current->breaks[0].token; error("break without loop"); }
580  emitReturn(state);
581 
582  /* Attach contants for arguments */
583  for (int i = 0; i < function->potentialPositionals; ++i) {
584  if (i < state->current->unnamedArgs) {
585  krk_writeValueArray(&function->positionalArgNames, NONE_VAL());
586  continue;
587  }
588  KrkValue value = OBJECT_VAL(krk_copyString(state->current->locals[i].name.start, state->current->locals[i].name.length));
589  krk_push(value);
590  krk_writeValueArray(&function->positionalArgNames, value);
591  krk_pop();
592  }
593 
594  size_t args = function->potentialPositionals;
595  if (function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) {
596  KrkValue value = OBJECT_VAL(krk_copyString(state->current->locals[args].name.start,
597  state->current->locals[args].name.length));
598  krk_push(value);
599  krk_writeValueArray(&function->positionalArgNames, value);
600  krk_pop();
601  args++;
602  }
603 
604  for (int i = 0; i < function->keywordArgs; ++i) {
605  KrkValue value = OBJECT_VAL(krk_copyString(state->current->locals[i+args].name.start,
606  state->current->locals[i+args].name.length));
607  krk_push(value);
608  krk_writeValueArray(&function->keywordArgNames, value);
609  krk_pop();
610  }
611  args += function->keywordArgs;
612 
613  if (function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS) {
614  KrkValue value = OBJECT_VAL(krk_copyString(state->current->locals[args].name.start,
615  state->current->locals[args].name.length));
616  krk_push(value);
617  krk_writeValueArray(&function->keywordArgNames, value);
618  krk_pop();
619  args++;
620  }
621 
622  function->totalArguments = function->potentialPositionals + function->keywordArgs + !!(function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) + !!(function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS);
623 
624 #ifndef KRK_NO_DISASSEMBLY
625  if ((krk_currentThread.flags & KRK_THREAD_ENABLE_DISASSEMBLY) && !state->parser.hadError) {
626  krk_disassembleCodeObject(stderr, function, function->name ? function->name->chars : "(module)");
627  }
628 #endif
629 
630  state->current = state->current->enclosing;
631  return function;
632 }
633 
634 static void freeCompiler(Compiler * compiler) {
635  FREE_ARRAY(Local,compiler->locals, compiler->localsSpace);
636  FREE_ARRAY(Upvalue,compiler->upvalues, compiler->upvaluesSpace);
637  FREE_ARRAY(struct LoopExit,compiler->breaks, compiler->breakSpace);
638  FREE_ARRAY(struct LoopExit,compiler->continues, compiler->continueSpace);
639 
640  while (compiler->properties) {
641  void * tmp = compiler->properties;
642  compiler->properties = compiler->properties->next;
643  free(tmp);
644  }
645 }
646 
647 static size_t _emitConstant(struct GlobalState * state, KrkValue value) {
648  return krk_writeConstant(currentChunk(), value, state->parser.previous.line);
649 }
650 
651 #define emitConstant(v) _emitConstant(state,v)
652 
653 static int isMangleable(const char * name, size_t len) {
654  return (len > 2 && name[0] == '_' && name[1] == '_' && name[len-1] != '_' && (len < 4 || name[len-2] != '_'));
655 }
656 
657 static ssize_t identifierConstant(struct GlobalState * state, KrkToken * name) {
658  if (state->currentClass && isMangleable(name->start, name->length)) {
659  /* Mangle it */
660  const char * className = state->currentClass->name.start;
661  size_t classLength = state->currentClass->name.length;
662  while (classLength && *className == '_') {
663  classLength--;
664  className++;
665  }
666 
667  struct StringBuilder sb = {0};
668  krk_pushStringBuilderFormat(&sb,"_%.*s%.*s",
669  (int)classLength, className,
670  (int)name->length, name->start);
671 
672  return krk_addConstant(currentChunk(), krk_finishStringBuilder(&sb));
673  }
674 
675  return krk_addConstant(currentChunk(), OBJECT_VAL(krk_copyString(name->start, name->length)));
676 }
677 
678 static ssize_t nonidentifierTokenConstant(struct GlobalState * state, KrkToken * name) {
679  return krk_addConstant(currentChunk(), OBJECT_VAL(krk_copyString(name->start, name->length)));
680 }
681 
682 static ssize_t resolveLocal(struct GlobalState * state, Compiler * compiler, KrkToken * name) {
683  for (ssize_t i = compiler->localCount - 1; i >= 0; i--) {
684  Local * local = &compiler->locals[i];
685  if (identifiersEqual(name, &local->name)) {
686  if (local->depth == -1) {
687  error("Invalid recursive reference in declaration initializer");
688  }
689  if (local->depth == -2) {
690  continue;
691  }
692  return i;
693  }
694  }
695  return -1;
696 }
697 
698 static size_t renameLocal(struct GlobalState * state, size_t ind, KrkToken name) {
699  if (state->current->codeobject->localNameCount + 1 > state->current->localNameCapacity) {
700  size_t old = state->current->localNameCapacity;
701  state->current->localNameCapacity = GROW_CAPACITY(old);
702  state->current->codeobject->localNames = GROW_ARRAY(KrkLocalEntry, state->current->codeobject->localNames, old, state->current->localNameCapacity);
703  }
705  state->current->codeobject->localNames[state->current->codeobject->localNameCount].birthday = currentChunk()->count;
707  state->current->codeobject->localNames[state->current->codeobject->localNameCount].name = krk_copyString(name.start, name.length);
708  return state->current->codeobject->localNameCount++;
709 }
710 
711 static size_t addLocal(struct GlobalState * state, KrkToken name) {
712  if (state->current->localCount + 1 > state->current->localsSpace) {
713  size_t old = state->current->localsSpace;
714  state->current->localsSpace = GROW_CAPACITY(old);
715  state->current->locals = GROW_ARRAY(Local,state->current->locals,old,state->current->localsSpace);
716  }
717  size_t out = state->current->localCount;
718  Local * local = &state->current->locals[state->current->localCount++];
719  local->name = name;
720  local->depth = -1;
721  local->isCaptured = 0;
722 
723  if (name.length) {
724  renameLocal(state, out, name);
725  }
726 
727  return out;
728 }
729 
730 static void declareVariable(struct GlobalState * state) {
731  if (state->current->scopeDepth == 0) return;
732  KrkToken * name = &state->parser.previous;
733  /* Detect duplicate definition */
734  for (ssize_t i = state->current->localCount - 1; i >= 0; i--) {
735  Local * local = &state->current->locals[i];
736  if (local->depth != -1 && local->depth < (ssize_t)state->current->scopeDepth) break;
737  if (identifiersEqual(name, &local->name)) {
738  error("Duplicate definition for local '%.*s' in this scope.", (int)name->literalWidth, name->start);
739  }
740  }
741  addLocal(state, *name);
742 }
743 
744 static ssize_t parseVariable(struct GlobalState * state, const char * errorMessage) {
745  consume(TOKEN_IDENTIFIER, errorMessage);
746 
747  declareVariable(state);
748  if (state->current->scopeDepth > 0) return 0;
749 
750  if ((state->current->optionsFlags & OPTIONS_FLAG_COMPILE_TIME_BUILTINS) && *state->parser.previous.start != '_') {
751  KrkValue value;
752  if (krk_tableGet_fast(&vm.builtins->fields, krk_copyString(state->parser.previous.start, state->parser.previous.length), &value)) {
753  error("Conflicting declaration of global '%.*s' is invalid when 'compile_time_builtins' is enabled.",
754  (int)state->parser.previous.length, state->parser.previous.start);
755  return 0;
756  }
757  }
758 
759  return identifierConstant(state, &state->parser.previous);
760 }
761 
762 static void markInitialized(struct GlobalState * state) {
763  if (state->current->scopeDepth == 0) return;
764  state->current->locals[state->current->localCount - 1].depth = state->current->scopeDepth;
765 }
766 
767 static size_t anonymousLocal(struct GlobalState * state) {
768  size_t val = addLocal(state, syntheticToken(""));
769  markInitialized(state);
770  return val;
771 }
772 
773 static void defineVariable(struct GlobalState * state, size_t global) {
774  if (state->current->scopeDepth > 0) {
775  markInitialized(state);
776  return;
777  }
778 
779  EMIT_OPERAND_OP(OP_DEFINE_GLOBAL, global);
780 }
781 
782 static void number(struct GlobalState * state, int exprType, RewindState *rewind) {
783  const char * start = state->parser.previous.start;
784  invalidTarget(state, exprType, "literal");
785 
786  for (size_t j = 0; j < state->parser.previous.length; ++j) {
787  if (state->parser.previous.start[j] == '.') {
788 #ifndef KRK_NO_FLOAT
789  double value = strtod(start, NULL);
790  emitConstant(FLOATING_VAL(value));
791 #else
792  error("no float support");
793 #endif
794  return;
795  }
796  }
797 
798  /* If we got here, it's an integer of some sort. */
799  KrkValue result = krk_parse_int(start, state->parser.previous.literalWidth, 0);
800  if (IS_NONE(result)) {
801  error("invalid numeric literal");
802  return;
803  }
804  emitConstant(result);
805 }
806 
807 static int _emitJump(struct GlobalState * state, uint8_t opcode) {
808  emitByte(opcode);
809  emitBytes(0xFF, 0xFF);
810  return currentChunk()->count - 2;
811 }
812 #define emitJump(o) _emitJump(state,o)
813 
814 static void _patchJump(struct GlobalState * state, int offset) {
815  int jump = currentChunk()->count - offset - 2;
816  if (jump > 0xFFFF) error("Jump offset is too large for opcode.");
817 
818  currentChunk()->code[offset] = (jump >> 8) & 0xFF;
819  currentChunk()->code[offset + 1] = (jump) & 0xFF;
820 }
821 
822 #define patchJump(o) _patchJump(state,o)
823 
824 static void compareChained(struct GlobalState * state, int inner) {
825  KrkTokenType operatorType = state->parser.previous.type;
826  if (operatorType == TOKEN_NOT) consume(TOKEN_IN, "'in' must follow infix 'not'");
827  int invert = (operatorType == TOKEN_IS && match(TOKEN_NOT));
828 
829  ParseRule * rule = getRule(operatorType);
830  parsePrecedence(state, (Precedence)(rule->precedence + 1));
831 
832  if (getRule(state->parser.current.type)->precedence == PREC_COMPARISON) {
833  emitByte(OP_SWAP);
834  emitBytes(OP_DUP, 1);
835  }
836 
837  switch (operatorType) {
838  case TOKEN_BANG_EQUAL: emitBytes(OP_EQUAL, OP_NOT); break;
839  case TOKEN_EQUAL_EQUAL: emitByte(OP_EQUAL); break;
840  case TOKEN_GREATER: emitByte(OP_GREATER); break;
841  case TOKEN_GREATER_EQUAL: emitByte(OP_GREATER_EQUAL); break;
842  case TOKEN_LESS: emitByte(OP_LESS); break;
843  case TOKEN_LESS_EQUAL: emitByte(OP_LESS_EQUAL); break;
844 
845  case TOKEN_IS: emitByte(OP_IS); if (invert) emitByte(OP_NOT); break;
846 
847  case TOKEN_IN: emitByte(OP_INVOKE_CONTAINS); break;
848  case TOKEN_NOT: emitBytes(OP_INVOKE_CONTAINS, OP_NOT); break;
849 
850  default: error("Invalid binary comparison operator?"); break;
851  }
852 
853  if (getRule(state->parser.current.type)->precedence == PREC_COMPARISON) {
854  size_t exitJump = emitJump(OP_JUMP_IF_FALSE_OR_POP);
855  advance();
856  compareChained(state, 1);
857  patchJump(exitJump);
858  if (getRule(state->parser.current.type)->precedence != PREC_COMPARISON) {
859  if (!inner) {
860  emitBytes(OP_SWAP,OP_POP);
861  }
862  }
863  } else if (inner) {
864  emitByte(OP_JUMP);
865  emitBytes(0,2);
866  }
867 }
868 
869 static void compare(struct GlobalState * state, int exprType, RewindState *rewind) {
870  compareChained(state, 0);
871  invalidTarget(state, exprType, "operator");
872 }
873 
874 static void binary(struct GlobalState * state, int exprType, RewindState *rewind) {
875  KrkTokenType operatorType = state->parser.previous.type;
876  ParseRule * rule = getRule(operatorType);
877  parsePrecedence(state, (Precedence)(rule->precedence + (rule->precedence != PREC_EXPONENT)));
878  invalidTarget(state, exprType, "operator");
879 
880  switch (operatorType) {
881  case TOKEN_PIPE: emitByte(OP_BITOR); break;
882  case TOKEN_CARET: emitByte(OP_BITXOR); break;
883  case TOKEN_AMPERSAND: emitByte(OP_BITAND); break;
884  case TOKEN_LEFT_SHIFT: emitByte(OP_SHIFTLEFT); break;
885  case TOKEN_RIGHT_SHIFT: emitByte(OP_SHIFTRIGHT); break;
886 
887  case TOKEN_PLUS: emitByte(OP_ADD); break;
888  case TOKEN_MINUS: emitByte(OP_SUBTRACT); break;
889  case TOKEN_ASTERISK: emitByte(OP_MULTIPLY); break;
890  case TOKEN_POW: emitByte(OP_POW); break;
891  case TOKEN_SOLIDUS: emitByte(OP_DIVIDE); break;
892  case TOKEN_DOUBLE_SOLIDUS: emitByte(OP_FLOORDIV); break;
893  case TOKEN_MODULO: emitByte(OP_MODULO); break;
894  case TOKEN_IN: emitByte(OP_EQUAL); break;
895  case TOKEN_AT: emitByte(OP_MATMUL); break;
896  default: return;
897  }
898 }
899 
900 static int matchAssignment(struct GlobalState * state) {
901  return (state->parser.current.type >= TOKEN_EQUAL && state->parser.current.type <= TOKEN_MODULO_EQUAL) ? (advance(), 1) : 0;
902 }
903 
904 static int checkEndOfDel(struct GlobalState * state) {
905  if (check(TOKEN_COMMA) || check(TOKEN_EOL) || check(TOKEN_EOF) || check(TOKEN_SEMICOLON)) {
906  state->current->delSatisfied = 1;
907  return 1;
908  }
909  return 0;
910 }
911 
912 static int matchComplexEnd(struct GlobalState * state) {
913  return match(TOKEN_COMMA) ||
914  match(TOKEN_EQUAL) ||
915  match(TOKEN_RIGHT_PAREN);
916 }
917 
918 static int invalidTarget(struct GlobalState * state, int exprType, const char * description) {
919  if (exprType == EXPR_CAN_ASSIGN && matchAssignment(state)) {
920  error("Can not assign to %s", description);
921  return 0;
922  }
923 
924  if (exprType == EXPR_DEL_TARGET && checkEndOfDel(state)) {
925  error("Can not delete %s", description);
926  return 0;
927  }
928 
929  return 1;
930 }
931 
932 static void assignmentValue(struct GlobalState * state) {
933  KrkTokenType type = state->parser.previous.type;
934  if (type == TOKEN_PLUS_PLUS || type == TOKEN_MINUS_MINUS) {
935  emitConstant(INTEGER_VAL(1));
936  } else {
937  parsePrecedence(state, PREC_COMMA); /* But adding a tuple is maybe not defined */
938  }
939 
940  switch (type) {
941  case TOKEN_PIPE_EQUAL: emitByte(OP_INPLACE_BITOR); break;
942  case TOKEN_CARET_EQUAL: emitByte(OP_INPLACE_BITXOR); break;
943  case TOKEN_AMP_EQUAL: emitByte(OP_INPLACE_BITAND); break;
944  case TOKEN_LSHIFT_EQUAL: emitByte(OP_INPLACE_SHIFTLEFT); break;
945  case TOKEN_RSHIFT_EQUAL: emitByte(OP_INPLACE_SHIFTRIGHT); break;
946 
947  case TOKEN_PLUS_EQUAL: emitByte(OP_INPLACE_ADD); break;
948  case TOKEN_PLUS_PLUS: emitByte(OP_INPLACE_ADD); break;
949  case TOKEN_MINUS_EQUAL: emitByte(OP_INPLACE_SUBTRACT); break;
950  case TOKEN_MINUS_MINUS: emitByte(OP_INPLACE_SUBTRACT); break;
951  case TOKEN_ASTERISK_EQUAL: emitByte(OP_INPLACE_MULTIPLY); break;
952  case TOKEN_POW_EQUAL: emitByte(OP_INPLACE_POW); break;
953  case TOKEN_SOLIDUS_EQUAL: emitByte(OP_INPLACE_DIVIDE); break;
954  case TOKEN_DSOLIDUS_EQUAL: emitByte(OP_INPLACE_FLOORDIV); break;
955  case TOKEN_MODULO_EQUAL: emitByte(OP_INPLACE_MODULO); break;
956  case TOKEN_AT_EQUAL: emitByte(OP_INPLACE_MATMUL); break;
957 
958  default:
959  error("Unexpected operand in assignment");
960  break;
961  }
962 }
963 
964 static void expression(struct GlobalState * state) {
965  parsePrecedence(state, PREC_CAN_ASSIGN);
966 }
967 
968 static void sliceExpression(struct GlobalState * state) {
969  int isSlice = 0;
970  if (match(TOKEN_COLON)) {
971  emitByte(OP_NONE);
972  isSlice = 1;
973  } else {
974  parsePrecedence(state, PREC_CAN_ASSIGN);
975  }
976  if (isSlice || match(TOKEN_COLON)) {
977  /* We have the start value, which is either something or None */
978  if (check(TOKEN_RIGHT_SQUARE) || check(TOKEN_COMMA)) {
979  /* foo[x:] */
980  emitByte(OP_NONE);
981  EMIT_OPERAND_OP(OP_SLICE, 2);
982  } else {
983  if (check(TOKEN_COLON)) {
984  /* foo[x::... */
985  emitByte(OP_NONE);
986  } else {
987  /* foo[x:e... */
988  parsePrecedence(state, PREC_CAN_ASSIGN);
989  }
990  if (match(TOKEN_COLON) && !check(TOKEN_RIGHT_SQUARE) && !check(TOKEN_COMMA)) {
991  /* foo[x:e:s] */
992  parsePrecedence(state, PREC_CAN_ASSIGN);
993  EMIT_OPERAND_OP(OP_SLICE, 3);
994  } else {
995  /* foo[x:e] */
996  EMIT_OPERAND_OP(OP_SLICE, 2);
997  }
998  }
999  }
1000 }
1001 
1002 static void getitem(struct GlobalState * state, int exprType, RewindState *rewind) {
1003 
1004  sliceExpression(state);
1005 
1006  if (match(TOKEN_COMMA)) {
1007  size_t argCount = 1;
1008  if (!check(TOKEN_RIGHT_SQUARE)) {
1009  do {
1010  sliceExpression(state);
1011  argCount++;
1012  } while (match(TOKEN_COMMA) && !check(TOKEN_RIGHT_SQUARE));
1013  }
1014  EMIT_OPERAND_OP(OP_TUPLE, argCount);
1015  }
1016 
1017  consume(TOKEN_RIGHT_SQUARE, "Expected ']' after index.");
1018  if (exprType == EXPR_ASSIGN_TARGET) {
1019  if (matchComplexEnd(state)) {
1020  EMIT_OPERAND_OP(OP_DUP, 2);
1021  emitByte(OP_INVOKE_SETTER);
1022  emitByte(OP_POP);
1023  return;
1024  }
1025  exprType = EXPR_NORMAL;
1026  }
1027  if (exprType == EXPR_CAN_ASSIGN && match(TOKEN_EQUAL)) {
1028  parsePrecedence(state, PREC_ASSIGNMENT);
1029  emitByte(OP_INVOKE_SETTER);
1030  } else if (exprType == EXPR_CAN_ASSIGN && matchAssignment(state)) {
1031  emitBytes(OP_DUP, 1); /* o e o */
1032  emitBytes(OP_DUP, 1); /* o e o e */
1033  emitByte(OP_INVOKE_GETTER); /* o e v */
1034  assignmentValue(state); /* o e v a */
1035  emitByte(OP_INVOKE_SETTER); /* r */
1036  } else if (exprType == EXPR_DEL_TARGET && checkEndOfDel(state)) {
1037  emitByte(OP_INVOKE_DELETE);
1038  } else {
1039  emitByte(OP_INVOKE_GETTER);
1040  }
1041 }
1042 
1043 static void attributeUnpack(struct GlobalState * state, int exprType) {
1044  startEatingWhitespace();
1045  size_t argCount = 0;
1046  size_t argSpace = 1;
1047  ssize_t * args = GROW_ARRAY(ssize_t,NULL,0,1);
1048 
1049  do {
1050  if (argSpace < argCount + 1) {
1051  size_t old = argSpace;
1052  argSpace = GROW_CAPACITY(old);
1053  args = GROW_ARRAY(ssize_t,args,old,argSpace);
1054  }
1055  consume(TOKEN_IDENTIFIER, "Expected attribute name");
1056  size_t ind = identifierConstant(state, &state->parser.previous);
1057  args[argCount++] = ind;
1058  } while (match(TOKEN_COMMA));
1059 
1060  stopEatingWhitespace();
1061  consume(TOKEN_RIGHT_PAREN, "Expected ')' after attribute list");
1062 
1063  if (exprType == EXPR_ASSIGN_TARGET) {
1064  error("Can not assign to '.(' in multiple target list");
1065  goto _dotDone;
1066  }
1067 
1068  if (exprType == EXPR_CAN_ASSIGN && match(TOKEN_EQUAL)) {
1069  size_t expressionCount = 0;
1070  do {
1071  expressionCount++;
1072  expression(state);
1073  } while (match(TOKEN_COMMA));
1074 
1075  if (expressionCount == 1 && argCount > 1) {
1076  EMIT_OPERAND_OP(OP_UNPACK, argCount);
1077  } else if (expressionCount > 1 && argCount == 1) {
1078  EMIT_OPERAND_OP(OP_TUPLE, expressionCount);
1079  } else if (expressionCount != argCount) {
1080  error("Invalid assignment to attribute pack");
1081  goto _dotDone;
1082  }
1083 
1084  for (size_t i = argCount; i > 0; i--) {
1085  if (i != 1) {
1086  emitBytes(OP_DUP, i);
1087  emitByte(OP_SWAP);
1088  }
1089  EMIT_OPERAND_OP(OP_SET_PROPERTY, args[i-1]);
1090  if (i != 1) {
1091  emitByte(OP_POP);
1092  }
1093  }
1094  } else {
1095  for (size_t i = 0; i < argCount; i++) {
1096  emitBytes(OP_DUP,0);
1097  EMIT_OPERAND_OP(OP_GET_PROPERTY,args[i]);
1098  emitByte(OP_SWAP);
1099  }
1100  emitByte(OP_POP);
1101  emitBytes(OP_TUPLE,argCount);
1102  }
1103 
1104 _dotDone:
1105  FREE_ARRAY(ssize_t,args,argSpace);
1106  return;
1107 }
1108 
1109 static void dot(struct GlobalState * state, int exprType, RewindState *rewind) {
1110  if (match(TOKEN_LEFT_PAREN)) {
1111  attributeUnpack(state, exprType);
1112  return;
1113  }
1114  consume(TOKEN_IDENTIFIER, "Expected property name");
1115  size_t ind = identifierConstant(state, &state->parser.previous);
1116  if (exprType == EXPR_ASSIGN_TARGET) {
1117  if (matchComplexEnd(state)) {
1118  EMIT_OPERAND_OP(OP_DUP, 1);
1119  EMIT_OPERAND_OP(OP_SET_PROPERTY, ind);
1120  emitByte(OP_POP);
1121  return;
1122  }
1123  exprType = EXPR_NORMAL;
1124  }
1125  if (exprType == EXPR_CAN_ASSIGN && match(TOKEN_EQUAL)) {
1126  parsePrecedence(state, PREC_ASSIGNMENT);
1127  EMIT_OPERAND_OP(OP_SET_PROPERTY, ind);
1128  } else if (exprType == EXPR_CAN_ASSIGN && matchAssignment(state)) {
1129  emitBytes(OP_DUP, 0); /* Duplicate the object */
1130  EMIT_OPERAND_OP(OP_GET_PROPERTY, ind);
1131  assignmentValue(state);
1132  EMIT_OPERAND_OP(OP_SET_PROPERTY, ind);
1133  } else if (exprType == EXPR_DEL_TARGET && checkEndOfDel(state)) {
1134  EMIT_OPERAND_OP(OP_DEL_PROPERTY, ind);
1135  } else if (match(TOKEN_LEFT_PAREN)) {
1136  EMIT_OPERAND_OP(OP_GET_METHOD, ind);
1137  call(state, EXPR_METHOD_CALL,NULL);
1138  } else {
1139  EMIT_OPERAND_OP(OP_GET_PROPERTY, ind);
1140  }
1141 }
1142 
1143 static void literal(struct GlobalState * state, int exprType, RewindState *rewind) {
1144  invalidTarget(state, exprType, "literal");
1145  switch (state->parser.previous.type) {
1146  case TOKEN_FALSE: emitByte(OP_FALSE); break;
1147  case TOKEN_NONE: emitByte(OP_NONE); break;
1148  case TOKEN_TRUE: emitByte(OP_TRUE); break;
1149  default: return;
1150  }
1151 }
1152 
1153 static void typeHintLocal(struct GlobalState * state) {
1154  state->current->enclosing->enclosed = state->current;
1155  state->current = state->current->enclosing;
1156  state->current->enclosed->annotationCount++;
1157  emitConstant(INTEGER_VAL(state->current->enclosed->codeobject->localNameCount-1));
1158  parsePrecedence(state, PREC_TERNARY);
1159  state->current = state->current->enclosed;
1160  state->current->enclosing->enclosed = NULL;
1161 }
1162 
1163 static void letDeclaration(struct GlobalState * state) {
1164  size_t argCount = 0;
1165  size_t argSpace = 1;
1166  ssize_t * args = GROW_ARRAY(ssize_t,NULL,0,1);
1167 
1168  do {
1169  if (argSpace < argCount + 1) {
1170  size_t old = argSpace;
1171  argSpace = GROW_CAPACITY(old);
1172  args = GROW_ARRAY(ssize_t,args,old,argSpace);
1173  }
1174  ssize_t ind = parseVariable(state, "Expected variable name.");
1175  if (state->parser.hadError) goto _letDone;
1176  if (state->current->scopeDepth > 0) {
1177  /* Need locals space */
1178  args[argCount++] = state->current->localCount - 1;
1179  } else {
1180  args[argCount++] = ind;
1181  }
1182  if (check(TOKEN_COLON)) {
1183  KrkToken name = state->parser.previous;
1184  match(TOKEN_COLON);
1185  if (state->current->enclosing) {
1186  typeHintLocal(state);
1187  } else {
1188  KrkToken annotations = syntheticToken("__annotations__");
1189  size_t ind = identifierConstant(state, &annotations);
1190  EMIT_OPERAND_OP(OP_GET_GLOBAL, ind);
1191  emitConstant(OBJECT_VAL(krk_copyString(name.start, name.length)));
1192  parsePrecedence(state, PREC_TERNARY);
1193  emitBytes(OP_INVOKE_SETTER, OP_POP);
1194  }
1195  }
1196  } while (match(TOKEN_COMMA));
1197 
1198  if (match(TOKEN_EQUAL)) {
1199  size_t expressionCount = 0;
1200  do {
1201  expressionCount++;
1202  expression(state);
1203  } while (match(TOKEN_COMMA));
1204  if (expressionCount == 1 && argCount > 1) {
1205  EMIT_OPERAND_OP(OP_UNPACK, argCount);
1206  } else if (expressionCount == argCount) {
1207  /* Do nothing */
1208  } else if (expressionCount > 1 && argCount == 1) {
1209  EMIT_OPERAND_OP(OP_TUPLE, expressionCount);
1210  } else {
1211  error("Invalid sequence unpack in 'let' statement");
1212  goto _letDone;
1213  }
1214  } else {
1215  /* Need to nil it */
1216  for (size_t i = 0; i < argCount; ++i) {
1217  emitByte(OP_NONE);
1218  }
1219  }
1220 
1221  if (state->current->scopeDepth == 0) {
1222  for (size_t i = argCount; i > 0; i--) {
1223  defineVariable(state, args[i-1]);
1224  }
1225  } else {
1226  for (size_t i = 0; i < argCount; i++) {
1227  state->current->locals[state->current->localCount - 1 - i].depth = state->current->scopeDepth;
1228  }
1229  }
1230 
1231 _letDone:
1232  FREE_ARRAY(ssize_t,args,argSpace);
1233  return;
1234 }
1235 
1236 static void declaration(struct GlobalState * state) {
1237  if (check(TOKEN_DEF)) {
1238  defDeclaration(state);
1239  } else if (check(TOKEN_CLASS)) {
1240  KrkToken className = classDeclaration(state);
1241  size_t classConst = identifierConstant(state, &className);
1242  state->parser.previous = className;
1243  declareVariable(state);
1244  defineVariable(state, classConst);
1245  } else if (check(TOKEN_AT)) {
1246  decorator(state, 0, TYPE_FUNCTION);
1247  } else if (check(TOKEN_ASYNC)) {
1248  asyncDeclaration(state, 1);
1249  } else if (match(TOKEN_EOL) || match(TOKEN_EOF)) {
1250  return;
1251  } else if (check(TOKEN_INDENTATION)) {
1252  return;
1253  } else {
1254  statement(state);
1255  }
1256 
1257  if (state->parser.hadError) skipToEnd();
1258 }
1259 
1260 static void expressionStatement(struct GlobalState * state) {
1261  parsePrecedence(state, PREC_ASSIGNMENT);
1262  emitByte(OP_POP);
1263 }
1264 
1265 static void beginScope(struct GlobalState * state) {
1266  state->current->scopeDepth++;
1267 }
1268 
1269 static void endScope(struct GlobalState * state) {
1270  state->current->scopeDepth--;
1271 
1272  int closeCount = 0;
1273  int popCount = 0;
1274 
1275  while (state->current->localCount > 0 &&
1276  state->current->locals[state->current->localCount - 1].depth > (ssize_t)state->current->scopeDepth) {
1277  if (state->current->locals[state->current->localCount - 1].isCaptured) {
1278  if (popCount) {
1279  if (popCount == 1) emitByte(OP_POP);
1280  else { EMIT_OPERAND_OP(OP_POP_MANY, popCount); }
1281  popCount = 0;
1282  }
1283  closeCount++;
1284  } else {
1285  if (closeCount) {
1286  if (closeCount == 1) emitByte(OP_CLOSE_UPVALUE);
1287  else { EMIT_OPERAND_OP(OP_CLOSE_MANY, closeCount); }
1288  closeCount = 0;
1289  }
1290  popCount++;
1291  }
1292 
1293  for (size_t i = 0; i < state->current->codeobject->localNameCount; i++) {
1294  if (state->current->codeobject->localNames[i].id == state->current->localCount - 1 &&
1295  state->current->codeobject->localNames[i].deathday == 0) {
1296  state->current->codeobject->localNames[i].deathday = (size_t)currentChunk()->count;
1297  }
1298  }
1299  state->current->localCount--;
1300  }
1301 
1302  if (popCount) {
1303  if (popCount == 1) emitByte(OP_POP);
1304  else { EMIT_OPERAND_OP(OP_POP_MANY, popCount); }
1305  }
1306  if (closeCount) {
1307  if (closeCount == 1) emitByte(OP_CLOSE_UPVALUE);
1308  else { EMIT_OPERAND_OP(OP_CLOSE_MANY, closeCount); }
1309  }
1310 }
1311 
1312 static void block(struct GlobalState * state, size_t indentation, const char * blockName) {
1313  if (match(TOKEN_EOL)) {
1314  if (check(TOKEN_INDENTATION)) {
1315  size_t currentIndentation = state->parser.current.length;
1316  if (currentIndentation <= indentation) return;
1317  advance();
1318  if (!strcmp(blockName,"def") && (match(TOKEN_STRING) || match(TOKEN_BIG_STRING))) {
1319  size_t before = currentChunk()->count;
1320  string(state, EXPR_NORMAL, NULL);
1321  /* That wrote to the chunk, rewind it; this should only ever go back two bytes
1322  * because this should only happen as the first thing in a function definition,
1323  * and thus this _should_ be the first constant and thus opcode + one-byte operand
1324  * to OP_CONSTANT, but just to be safe we'll actually use the previous offset... */
1325  currentChunk()->count = before;
1326  /* Retreive the docstring from the constant table */
1327  state->current->codeobject->docstring = AS_STRING(currentChunk()->constants.values[currentChunk()->constants.count-1]);
1328  consume(TOKEN_EOL,"Garbage after docstring defintion");
1329  if (!check(TOKEN_INDENTATION) || state->parser.current.length != currentIndentation) {
1330  error("Expected at least one statement in function with docstring.");
1331  }
1332  advance();
1333  }
1334  declaration(state);
1335  while (check(TOKEN_INDENTATION)) {
1336  if (state->parser.current.length < currentIndentation) break;
1337  advance();
1338  declaration(state);
1339  if (check(TOKEN_EOL)) {
1340  advance();
1341  }
1342  if (state->parser.hadError) skipToEnd();
1343  };
1344  }
1345  } else {
1346  statement(state);
1347  }
1348 }
1349 
1350 static void doUpvalues(struct GlobalState * state, Compiler * compiler, KrkCodeObject * function) {
1351  assert(!!function->upvalueCount == !!compiler->upvalues);
1352  for (size_t i = 0; i < function->upvalueCount; ++i) {
1353  size_t index = compiler->upvalues[i].index;
1354  emitByte((compiler->upvalues[i].isLocal) | ((index > 255) ? 2 : 0));
1355  if (index > 255) {
1356  emitByte((index >> 16) & 0xFF);
1357  emitByte((index >> 8) & 0xFF);
1358  }
1359  emitByte(index & 0xFF);
1360  }
1361 }
1362 
1363 static void typeHint(struct GlobalState * state, KrkToken name) {
1364  state->current->enclosing->enclosed = state->current;
1365  state->current = state->current->enclosing;
1366 
1367  state->current->enclosed->annotationCount++;
1368 
1369  /* Emit name */
1370  emitConstant(OBJECT_VAL(krk_copyString(name.start, name.length)));
1371  parsePrecedence(state, PREC_TERNARY);
1372 
1373  state->current = state->current->enclosed;
1374  state->current->enclosing->enclosed = NULL;
1375 }
1376 
1377 static void hideLocal(struct GlobalState * state) {
1378  state->current->locals[state->current->localCount - 1].depth = -2;
1379 }
1380 
1381 static void argumentDefinition(struct GlobalState * state, int hasCollectors) {
1382  if (match(TOKEN_EQUAL)) {
1383  /*
1384  * We inline default arguments by checking if they are equal
1385  * to a sentinel value and replacing them with the requested
1386  * argument. This allows us to send None (useful) to override
1387  * defaults that are something else. This essentially ends
1388  * up as the following at the top of the function:
1389  * if param == KWARGS_SENTINEL:
1390  * param = EXPRESSION
1391  */
1392  size_t myLocal = state->current->localCount - 1;
1393  EMIT_OPERAND_OP(OP_GET_LOCAL, myLocal);
1394  int jumpIndex = emitJump(OP_TEST_ARG);
1395  beginScope(state);
1396  expression(state); /* Read expression */
1397  EMIT_OPERAND_OP(OP_SET_LOCAL_POP, myLocal);
1398  endScope(state);
1399  patchJump(jumpIndex);
1400  if (hasCollectors) {
1401  state->current->codeobject->keywordArgs++;
1402  } else {
1404  }
1405  } else {
1406  if (hasCollectors) {
1407  size_t myLocal = state->current->localCount - 1;
1408  EMIT_OPERAND_OP(OP_GET_LOCAL, myLocal);
1409  int jumpIndex = emitJump(OP_TEST_ARG);
1410  EMIT_OPERAND_OP(OP_MISSING_KW, state->current->codeobject->keywordArgs);
1411  patchJump(jumpIndex);
1412  state->current->codeobject->keywordArgs++;
1413  } else {
1415  error("non-default argument follows default argument");
1416  return;
1417  }
1418  state->current->codeobject->requiredArgs++;
1420  }
1421  }
1422 }
1423 
1424 static void functionPrologue(struct GlobalState * state, Compiler * compiler) {
1425  KrkCodeObject * func = endCompiler(state);
1426  if (compiler->annotationCount) {
1427  EMIT_OPERAND_OP(OP_MAKE_DICT, compiler->annotationCount * 2);
1428  }
1429  size_t ind = krk_addConstant(currentChunk(), OBJECT_VAL(func));
1430  EMIT_OPERAND_OP(OP_CLOSURE, ind);
1431  doUpvalues(state, compiler, func);
1432  if (compiler->annotationCount) {
1433  emitByte(OP_ANNOTATE);
1434  }
1435  freeCompiler(compiler);
1436 }
1437 
1438 static int argumentList(struct GlobalState * state, FunctionType type) {
1439  int hasCollectors = 0;
1440  KrkToken self = syntheticToken("self");
1441 
1442  do {
1443  if (!(state->current->optionsFlags & OPTIONS_FLAG_NO_IMPLICIT_SELF) &&
1444  isMethod(type) && check(TOKEN_IDENTIFIER) &&
1445  identifiersEqual(&state->parser.current, &self)) {
1446  if (hasCollectors || state->current->codeobject->requiredArgs != 1) {
1447  errorAtCurrent("Argument name 'self' in a method signature is reserved for the implicit first argument.");
1448  return 1;
1449  }
1450  advance();
1451  if (type != TYPE_LAMBDA && check(TOKEN_COLON)) {
1452  KrkToken name = state->parser.previous;
1453  match(TOKEN_COLON);
1454  typeHint(state, name);
1455  }
1456  if (check(TOKEN_EQUAL)) {
1457  errorAtCurrent("'self' can not be a default argument.");
1458  return 1;
1459  }
1460  continue;
1461  }
1462  if (match(TOKEN_SOLIDUS)) {
1463  if (hasCollectors || state->current->unnamedArgs || !state->current->codeobject->potentialPositionals) {
1464  error("Syntax error.");
1465  return 1;
1466  }
1468  continue;
1469  }
1470  if (match(TOKEN_ASTERISK) || check(TOKEN_POW)) {
1471  if (match(TOKEN_POW)) {
1472  if (hasCollectors == 2) {
1473  error("Duplicate ** in parameter list.");
1474  return 1;
1475  }
1476  hasCollectors = 2;
1477  state->current->codeobject->obj.flags |= KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS;
1478  } else {
1479  if (hasCollectors) {
1480  error("Syntax error.");
1481  return 1;
1482  }
1483  hasCollectors = 1;
1484  if (check(TOKEN_COMMA)) {
1485  continue;
1486  }
1487  state->current->codeobject->obj.flags |= KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS;
1488  }
1489  /* Collect a name, specifically "args" or "kwargs" are commont */
1490  ssize_t paramConstant = parseVariable(state,
1491  (hasCollectors == 1) ? "Expected parameter name after '*'." : "Expected parameter name after '**'.");
1492  if (state->parser.hadError) return 1;
1493  defineVariable(state, paramConstant);
1494  KrkToken name = state->parser.previous;
1495  if (!(state->current->optionsFlags & OPTIONS_FLAG_NO_IMPLICIT_SELF) && isMethod(type) && identifiersEqual(&name,&self)) {
1496  errorAtCurrent("Argument name 'self' in a method signature is reserved for the implicit first argument.");
1497  return 1;
1498  }
1499  if (type != TYPE_LAMBDA && check(TOKEN_COLON)) {
1500  match(TOKEN_COLON);
1501  typeHint(state, name);
1502  }
1503  /* Make that a valid local for this function */
1504  size_t myLocal = state->current->localCount - 1;
1505  EMIT_OPERAND_OP(OP_GET_LOCAL, myLocal);
1506  /* Check if it's equal to the unset-kwarg-sentinel value */
1507  int jumpIndex = emitJump(OP_TEST_ARG);
1508  /* And if it is, set it to the appropriate type */
1509  beginScope(state);
1510  if (hasCollectors == 1) EMIT_OPERAND_OP(OP_MAKE_LIST,0);
1511  else EMIT_OPERAND_OP(OP_MAKE_DICT,0);
1512  EMIT_OPERAND_OP(OP_SET_LOCAL_POP, myLocal);
1513  endScope(state);
1514  /* Otherwise pop the comparison. */
1515  patchJump(jumpIndex);
1516  continue;
1517  }
1518  if (hasCollectors == 2) {
1519  error("arguments follow catch-all keyword collector");
1520  break;
1521  }
1522  ssize_t paramConstant = parseVariable(state, "Expected parameter name.");
1523  if (state->parser.hadError) return 1;
1524  hideLocal(state);
1525  if (type != TYPE_LAMBDA && check(TOKEN_COLON)) {
1526  KrkToken name = state->parser.previous;
1527  match(TOKEN_COLON);
1528  typeHint(state, name);
1529  }
1530  argumentDefinition(state, hasCollectors);
1531  defineVariable(state, paramConstant);
1532  } while (match(TOKEN_COMMA));
1533 
1534  return 0;
1535 }
1536 
1537 static void function(struct GlobalState * state, FunctionType type, size_t blockWidth) {
1538  Compiler compiler;
1539  initCompiler(state, &compiler, type);
1540  compiler.codeobject->chunk.filename = compiler.enclosing->codeobject->chunk.filename;
1541 
1542  beginScope(state);
1543 
1544  consume(TOKEN_LEFT_PAREN, "Expected start of parameter list after function name.");
1545  startEatingWhitespace();
1546  if (!check(TOKEN_RIGHT_PAREN)) {
1547  if (argumentList(state, type)) goto _bail;
1548  }
1549  stopEatingWhitespace();
1550  consume(TOKEN_RIGHT_PAREN, "Expected end of parameter list.");
1551 
1552  if (match(TOKEN_ARROW)) {
1553  typeHint(state, syntheticToken("return"));
1554  }
1555 
1556  consume(TOKEN_COLON, "Expected colon after function signature.");
1557  block(state, blockWidth,"def");
1558 _bail: (void)0;
1559  functionPrologue(state, &compiler);
1560 }
1561 
1562 static void classBody(struct GlobalState * state, size_t blockWidth) {
1563  if (match(TOKEN_EOL)) {
1564  return;
1565  }
1566 
1567  if (check(TOKEN_AT)) {
1568  /* '@decorator' which should be attached to a method. */
1569  decorator(state, 0, TYPE_METHOD);
1570  } else if (match(TOKEN_IDENTIFIER)) {
1571  /* Class field */
1572  size_t ind = identifierConstant(state, &state->parser.previous);
1573 
1574  if (check(TOKEN_COLON)) {
1575  /* Type annotation for field */
1576  KrkToken name = state->parser.previous;
1577  match(TOKEN_COLON);
1578  /* Get __annotations__ from class */
1579  KrkToken annotations = syntheticToken("__annotations__");
1580  size_t ind = identifierConstant(state, &annotations);
1581  if (!state->currentClass->hasAnnotations) {
1582  EMIT_OPERAND_OP(OP_MAKE_DICT, 0);
1583  EMIT_OPERAND_OP(OP_SET_NAME, ind);
1584  state->currentClass->hasAnnotations = 1;
1585  } else {
1586  EMIT_OPERAND_OP(OP_GET_NAME, ind);
1587  }
1588  emitConstant(OBJECT_VAL(krk_copyString(name.start, name.length)));
1589  parsePrecedence(state, PREC_TERNARY);
1590  emitBytes(OP_INVOKE_SETTER, OP_POP);
1591 
1592  /* A class field with a type hint can be valueless */
1593  if (match(TOKEN_EOL) || match(TOKEN_EOF)) return;
1594  }
1595 
1596  consume(TOKEN_EQUAL, "Class field must have value.");
1597 
1598  /* Value */
1599  parsePrecedence(state, PREC_COMMA);
1600 
1601  rememberClassProperty(state, ind);
1602  EMIT_OPERAND_OP(OP_SET_NAME, ind);
1603  emitByte(OP_POP);
1604 
1605  if (!match(TOKEN_EOL) && !match(TOKEN_EOF)) {
1606  errorAtCurrent("Expected end of line after class attribute declaration");
1607  }
1608  } else if (match(TOKEN_PASS)) {
1609  /* `pass` is just a general empty statement */
1610  consume(TOKEN_EOL, "Expected end of line after 'pass' in class body.");
1611  } else {
1612  /* Must be a function of some sort */
1613  FunctionType type = TYPE_METHOD;
1614  if (match(TOKEN_ASYNC)) {
1615  type = TYPE_COROUTINE_METHOD;
1616  consume(TOKEN_DEF, "Expected 'def' after 'async'");
1617  } else if (!match(TOKEN_DEF)) {
1618  error("Expected method, decorator, or class variable.");
1619  }
1620  consume(TOKEN_IDENTIFIER, "Expected method name after 'def'");
1621  size_t ind = identifierConstant(state, &state->parser.previous);
1622 
1623  static struct CompilerSpecialMethod { const char * name; int type; } compilerSpecialMethods[] = {
1624  {"__init__", TYPE_INIT},
1625  {"__class_getitem__", TYPE_CLASSMETHOD},
1626  {"__init_subclass__", TYPE_CLASSMETHOD},
1627  {"__new__", TYPE_STATIC},
1628  {NULL,0}
1629  };
1630 
1631  for (struct CompilerSpecialMethod * method = compilerSpecialMethods; method->name; method++) {
1632  if (state->parser.previous.length == strlen(method->name) && memcmp(state->parser.previous.start, method->name, strlen(method->name)) == 0) {
1633  if (type == TYPE_COROUTINE_METHOD) {
1634  error("'%s' can not be a coroutine",method->name);
1635  return;
1636  }
1637  type = method->type;
1638  }
1639  }
1640 
1641  function(state, type, blockWidth);
1642  rememberClassProperty(state, ind);
1643  EMIT_OPERAND_OP(OP_SET_NAME, ind);
1644  emitByte(OP_POP);
1645  }
1646 }
1647 
1648 #define ATTACH_PROPERTY(propName,how,propValue) do { \
1649  KrkToken val_tok = syntheticToken(propValue); \
1650  size_t val_ind = nonidentifierTokenConstant(state, &val_tok); \
1651  EMIT_OPERAND_OP(how, val_ind); \
1652  KrkToken name_tok = syntheticToken(propName); \
1653  size_t name_ind = identifierConstant(state, &name_tok); \
1654  EMIT_OPERAND_OP(OP_SET_NAME, name_ind); \
1655  emitByte(OP_POP); \
1656 } while (0)
1657 
1658 static size_t addUpvalue(struct GlobalState * state, Compiler * compiler, ssize_t index, int isLocal, KrkToken name);
1659 static KrkToken classDeclaration(struct GlobalState * state) {
1660  size_t blockWidth = (state->parser.previous.type == TOKEN_INDENTATION) ? state->parser.previous.length : 0;
1661  advance(); /* Collect the `class` */
1662 
1663  consume(TOKEN_IDENTIFIER, "Expected class name after 'class'.");
1664 
1665  KrkToken buildClass = syntheticToken("__build_class__");
1666  size_t ind = identifierConstant(state, &buildClass);
1667  EMIT_OPERAND_OP(OP_GET_GLOBAL, ind);
1668 
1669  Compiler subcompiler;
1670  initCompiler(state, &subcompiler, TYPE_CLASS);
1671  subcompiler.codeobject->chunk.filename = subcompiler.enclosing->codeobject->chunk.filename;
1672 
1673  beginScope(state);
1674 
1675  KrkToken classNameToken = state->parser.previous;
1676  assert(addUpvalue(state, state->current, 0, 4, classNameToken) == 0);
1677 
1678  ClassCompiler classCompiler;
1679  classCompiler.name = state->parser.previous;
1680  classCompiler.enclosing = state->currentClass;
1681  state->currentClass = &classCompiler;
1682  classCompiler.hasAnnotations = 0;
1683 
1684  RewindState parameters = {recordChunk(currentChunk()), krk_tellScanner(&state->scanner), state->parser};
1685 
1686  /* Class parameters */
1687  if (match(TOKEN_LEFT_PAREN)) {
1688  int parenDepth = 0;
1689  while (!check(TOKEN_EOF)) {
1690  if (check(TOKEN_RIGHT_PAREN) && parenDepth == 0) {
1691  advance();
1692  break;
1693  } else if (match(TOKEN_LEFT_BRACE)) {
1694  parenDepth++;
1695  } else if (match(TOKEN_RIGHT_BRACE)) {
1696  parenDepth--;
1697  } else {
1698  advance();
1699  }
1700  }
1701  }
1702 
1703  beginScope(state);
1704 
1705  consume(TOKEN_COLON, "Expected ':' after class.");
1706 
1707  /* Set Class.__module__ to the value of __name__, which is the string
1708  * name of the current module. */
1709  ATTACH_PROPERTY("__module__", OP_GET_GLOBAL, "__name__");
1710  ATTACH_PROPERTY("__qualname__", OP_CONSTANT, calculateQualName(state));
1711 
1712  if (match(TOKEN_EOL)) {
1713  if (check(TOKEN_INDENTATION)) {
1714  size_t currentIndentation = state->parser.current.length;
1715  if (currentIndentation <= blockWidth) {
1716  errorAtCurrent("Unexpected indentation level for class");
1717  }
1718  advance();
1719  if (match(TOKEN_STRING) || match(TOKEN_BIG_STRING)) {
1720  string(state, EXPR_NORMAL, NULL);
1721  KrkToken doc = syntheticToken("__doc__");
1722  size_t ind = identifierConstant(state, &doc);
1723  EMIT_OPERAND_OP(OP_SET_NAME, ind);
1724  emitByte(OP_POP);
1725  consume(TOKEN_EOL,"Garbage after docstring defintion");
1726  if (!check(TOKEN_INDENTATION) || state->parser.current.length != currentIndentation) {
1727  goto _pop_class;
1728  }
1729  advance();
1730  }
1731  classBody(state, currentIndentation);
1732  while (check(TOKEN_INDENTATION)) {
1733  if (state->parser.current.length < currentIndentation) break;
1734  advance(); /* Pass the indentation */
1735  classBody(state, currentIndentation);
1736  }
1737  /* Exit from block */
1738  }
1739  } /* else empty class (and at end of file?) we'll allow it for now... */
1740 _pop_class:
1741  state->currentClass = state->currentClass->enclosing;
1742  KrkCodeObject * makeclass = endCompiler(state);
1743  size_t indFunc = krk_addConstant(currentChunk(), OBJECT_VAL(makeclass));
1744  EMIT_OPERAND_OP(OP_CLOSURE, indFunc);
1745  doUpvalues(state, &subcompiler, makeclass);
1746  freeCompiler(&subcompiler);
1747 
1748  RewindState afterFunction = {recordChunk(currentChunk()), krk_tellScanner(&state->scanner), state->parser};
1749 
1750  size_t nameInd = nonidentifierTokenConstant(state, &classNameToken);
1751  EMIT_OPERAND_OP(OP_CONSTANT, nameInd);
1752 
1753  krk_rewindScanner(&state->scanner, parameters.oldScanner);
1754  state->parser = parameters.oldParser;
1755 
1756  if (match(TOKEN_LEFT_PAREN)) {
1757  call(state, EXPR_CLASS_PARAMETERS, NULL);
1758  } else {
1759  emitBytes(OP_CALL, 2);
1760  }
1761 
1762  krk_rewindScanner(&state->scanner, afterFunction.oldScanner);
1763  state->parser = afterFunction.oldParser;
1764 
1765  return classCompiler.name;
1766 }
1767 
1768 static void lambda(struct GlobalState * state, int exprType, RewindState *rewind) {
1769  Compiler lambdaCompiler;
1770  state->parser.previous = syntheticToken("<lambda>");
1771  initCompiler(state, &lambdaCompiler, TYPE_LAMBDA);
1772  lambdaCompiler.codeobject->chunk.filename = lambdaCompiler.enclosing->codeobject->chunk.filename;
1773  beginScope(state);
1774 
1775  if (!check(TOKEN_COLON)) {
1776  if (argumentList(state, TYPE_LAMBDA)) goto _bail;
1777  }
1778 
1779  consume(TOKEN_COLON, "Expected ':' after lambda arguments");
1780  expression(state);
1781 
1782 _bail:
1783  functionPrologue(state, &lambdaCompiler);
1784 
1785  invalidTarget(state, exprType, "lambda");
1786 }
1787 
1788 static void defDeclaration(struct GlobalState * state) {
1789  size_t blockWidth = (state->parser.previous.type == TOKEN_INDENTATION) ? state->parser.previous.length : 0;
1790  advance(); /* Collect the `def` */
1791 
1792  ssize_t global = parseVariable(state, "Expected function name after 'def'.");
1793  if (state->parser.hadError) return;
1794  markInitialized(state);
1795  function(state, TYPE_FUNCTION, blockWidth);
1796  if (state->parser.hadError) return;
1797  defineVariable(state, global);
1798 }
1799 
1800 static void asyncDeclaration(struct GlobalState * state, int declarationLevel) {
1801  size_t blockWidth = (state->parser.previous.type == TOKEN_INDENTATION) ? state->parser.previous.length : 0;
1802  advance(); /* 'async' */
1803 
1804  if (match(TOKEN_DEF)) {
1805  if (!declarationLevel) {
1806  error("'async def' not valid here");
1807  return;
1808  }
1809  ssize_t global = parseVariable(state, "Expected coroutine name after 'async def'");
1810  if (state->parser.hadError) return;
1811  markInitialized(state);
1812  function(state, TYPE_COROUTINE, blockWidth);
1813  if (state->parser.hadError) return;
1814  defineVariable(state, global);
1815  } else if (match(TOKEN_FOR)) {
1816  if (!isCoroutine(state->current->type)) {
1817  error("'async for' outside of async function");
1818  return;
1819  }
1820  error("'async for' unsupported (GH-12)");
1821  return;
1822  } else if (match(TOKEN_WITH)) {
1823  if (!isCoroutine(state->current->type)) {
1824  error("'async with' outside of async function");
1825  return;
1826  }
1827  error("'async with' unsupported (GH-12)");
1828  return;
1829  } else {
1830  errorAtCurrent("Expected 'def' after 'async'.");
1831  return;
1832  }
1833 }
1834 
1835 static KrkToken decorator(struct GlobalState * state, size_t level, FunctionType type) {
1836  int inType = type;
1837  size_t blockWidth = (state->parser.previous.type == TOKEN_INDENTATION) ? state->parser.previous.length : 0;
1838  advance(); /* Collect the `@` */
1839 
1840  KrkToken funcName = {0};
1841 
1842  KrkToken at_staticmethod = syntheticToken("staticmethod");
1843  KrkToken at_classmethod = syntheticToken("classmethod");
1844 
1845  if (type == TYPE_METHOD) {
1846  if (identifiersEqual(&at_staticmethod, &state->parser.current)) type = TYPE_STATIC;
1847  if (identifiersEqual(&at_classmethod, &state->parser.current)) type = TYPE_CLASSMETHOD;
1848  }
1849 
1850  expression(state);
1851 
1852  consume(TOKEN_EOL, "Expected end of line after decorator.");
1853  if (blockWidth) {
1854  consume(TOKEN_INDENTATION, "Expected next line after decorator to have same indentation.");
1855  if (state->parser.previous.length != blockWidth) error("Expected next line after decorator to have same indentation.");
1856  }
1857 
1858  if (check(TOKEN_DEF)) {
1859  /* We already checked for block level */
1860  advance();
1861  consume(TOKEN_IDENTIFIER, "Expected function name after 'def'");
1862  funcName = state->parser.previous;
1863  if (type == TYPE_METHOD && funcName.length == 8 && !memcmp(funcName.start,"__init__",8)) {
1864  type = TYPE_INIT;
1865  }
1866  function(state, type, blockWidth);
1867  } else if (match(TOKEN_ASYNC)) {
1868  if (!match(TOKEN_DEF)) {
1869  errorAtCurrent("Expected 'def' after 'async' with decorator, not '%*.s'",
1870  (int)state->parser.current.length, state->parser.current.start);
1871  }
1872  consume(TOKEN_IDENTIFIER, "Expected coroutine name after 'def'.");
1873  funcName = state->parser.previous;
1874  function(state, type == TYPE_METHOD ? TYPE_COROUTINE_METHOD : TYPE_COROUTINE, blockWidth);
1875  } else if (check(TOKEN_AT)) {
1876  funcName = decorator(state, level+1, type);
1877  } else if (check(TOKEN_CLASS)) {
1878  if (type != TYPE_FUNCTION) {
1879  error("Invalid decorator applied to class");
1880  return funcName;
1881  }
1882  funcName = classDeclaration(state);
1883  } else {
1884  error("Expected a function declaration or another decorator.");
1885  return funcName;
1886  }
1887 
1888  emitBytes(OP_CALL, 1);
1889 
1890  if (level == 0) {
1891  if (inType == TYPE_FUNCTION) {
1892  state->parser.previous = funcName;
1893  declareVariable(state);
1894  size_t ind = (state->current->scopeDepth > 0) ? 0 : identifierConstant(state, &funcName);
1895  defineVariable(state, ind);
1896  } else {
1897  size_t ind = identifierConstant(state, &funcName);
1898  rememberClassProperty(state, ind);
1899  EMIT_OPERAND_OP(OP_SET_NAME, ind);
1900  emitByte(OP_POP);
1901  }
1902  }
1903 
1904  return funcName;
1905 }
1906 
1907 static void emitLoop(struct GlobalState * state, int loopStart, uint8_t loopType) {
1908 
1909  /* Patch continue statements to point to here, before the loop operation (yes that's silly) */
1910  while (state->current->continueCount > 0 && state->current->continues[state->current->continueCount-1].offset > loopStart) {
1911  patchJump(state->current->continues[state->current->continueCount-1].offset);
1912  state->current->continueCount--;
1913  }
1914 
1915  emitByte(loopType);
1916 
1917  int offset = currentChunk()->count - loopStart + ((loopType == OP_LOOP_ITER) ? -1 : 2);
1918  if (offset > 0xFFFF) error("Loop jump offset is too large for opcode.");
1919  emitBytes(offset >> 8, offset);
1920 
1921  /* Patch break statements */
1922 }
1923 
1924 static void withStatement(struct GlobalState * state) {
1925  /* We only need this for block() */
1926  size_t blockWidth = (state->parser.previous.type == TOKEN_INDENTATION) ? state->parser.previous.length : 0;
1927  KrkToken myPrevious = state->parser.previous;
1928 
1929  /* Collect the with token that started this statement */
1930  advance();
1931 
1932  beginScope(state);
1933  expression(state);
1934 
1935  if (match(TOKEN_AS)) {
1936  consume(TOKEN_IDENTIFIER, "Expected variable name after 'as'");
1937  size_t ind = identifierConstant(state, &state->parser.previous);
1938  declareVariable(state);
1939  defineVariable(state, ind);
1940  } else {
1941  /* Otherwise we want an unnamed local */
1942  anonymousLocal(state);
1943  }
1944 
1945  /* Storage for return / exception */
1946  anonymousLocal(state);
1947 
1948  /* Handler object */
1949  anonymousLocal(state);
1950  int withJump = emitJump(OP_PUSH_WITH);
1951 
1952  if (check(TOKEN_COMMA)) {
1953  state->parser.previous = myPrevious;
1954  withStatement(state); /* Keep nesting */
1955  } else {
1956  consume(TOKEN_COLON, "Expected ',' or ':' after 'with' statement");
1957 
1958  beginScope(state);
1959  block(state,blockWidth,"with");
1960  endScope(state);
1961  }
1962 
1963  patchJump(withJump);
1964  emitByte(OP_CLEANUP_WITH);
1965 
1966  /* Scope exit pops context manager */
1967  endScope(state);
1968 }
1969 
1970 static void ifStatement(struct GlobalState * state) {
1971  /* Figure out what block level contains us so we can match our partner else */
1972  size_t blockWidth = (state->parser.previous.type == TOKEN_INDENTATION) ? state->parser.previous.length : 0;
1973  KrkToken myPrevious = state->parser.previous;
1974 
1975  /* Collect the if token that started this statement */
1976  advance();
1977 
1978  /* Collect condition expression */
1979  expression(state);
1980 
1981  /* if EXPR: */
1982  consume(TOKEN_COLON, "Expected ':' after 'if' condition.");
1983 
1984  if (state->parser.hadError) return;
1985 
1986  int thenJump = emitJump(OP_POP_JUMP_IF_FALSE);
1987 
1988  /* Start a new scope and enter a block */
1989  beginScope(state);
1990  block(state,blockWidth,"if");
1991  endScope(state);
1992 
1993  if (state->parser.hadError) return;
1994 
1995  int elseJump = emitJump(OP_JUMP);
1996  patchJump(thenJump);
1997 
1998  /* See if we have a matching else block */
1999  if (blockWidth == 0 || (check(TOKEN_INDENTATION) && (state->parser.current.length == blockWidth))) {
2000  /* This is complicated */
2001  KrkToken previous;
2002  if (blockWidth) {
2003  previous = state->parser.previous;
2004  advance();
2005  }
2006  if (match(TOKEN_ELSE) || check(TOKEN_ELIF)) {
2007  if (state->parser.current.type == TOKEN_ELIF || check(TOKEN_IF)) {
2008  state->parser.previous = myPrevious;
2009  ifStatement(state); /* Keep nesting */
2010  } else {
2011  consume(TOKEN_COLON, "Expected ':' after 'else'.");
2012  beginScope(state);
2013  block(state,blockWidth,"else");
2014  endScope(state);
2015  }
2016  } else if (!check(TOKEN_EOF) && !check(TOKEN_EOL)) {
2017  if (blockWidth) {
2018  krk_ungetToken(&state->scanner, state->parser.current);
2019  state->parser.current = state->parser.previous;
2020  state->parser.previous = previous;
2021  }
2022  } else {
2023  advance(); /* Ignore this blank indentation line */
2024  }
2025  }
2026 
2027  patchJump(elseJump);
2028 }
2029 
2030 static void patchBreaks(struct GlobalState * state, int loopStart) {
2031  /* Patch break statements to go here, after the loop operation and operand. */
2032  while (state->current->breakCount > 0 && state->current->breaks[state->current->breakCount-1].offset > loopStart) {
2033  patchJump(state->current->breaks[state->current->breakCount-1].offset);
2034  state->current->breakCount--;
2035  }
2036 }
2037 
2038 static void breakStatement(struct GlobalState * state) {
2039  if (state->current->breakSpace < state->current->breakCount + 1) {
2040  size_t old = state->current->breakSpace;
2041  state->current->breakSpace = GROW_CAPACITY(old);
2042  state->current->breaks = GROW_ARRAY(struct LoopExit,state->current->breaks,old,state->current->breakSpace);
2043  }
2044 
2045  if (state->current->loopLocalCount != state->current->localCount) {
2046  EMIT_OPERAND_OP(OP_EXIT_LOOP, state->current->loopLocalCount);
2047  }
2048 
2049  state->current->breaks[state->current->breakCount++] = (struct LoopExit){emitJump(OP_JUMP),state->parser.previous};
2050 }
2051 
2052 static void continueStatement(struct GlobalState * state) {
2053  if (state->current->continueSpace < state->current->continueCount + 1) {
2054  size_t old = state->current->continueSpace;
2055  state->current->continueSpace = GROW_CAPACITY(old);
2056  state->current->continues = GROW_ARRAY(struct LoopExit,state->current->continues,old,state->current->continueSpace);
2057  }
2058 
2059  if (state->current->loopLocalCount != state->current->localCount) {
2060  EMIT_OPERAND_OP(OP_EXIT_LOOP, state->current->loopLocalCount);
2061  }
2062 
2063  state->current->continues[state->current->continueCount++] = (struct LoopExit){emitJump(OP_JUMP),state->parser.previous};
2064 }
2065 
2066 static void optionalElse(struct GlobalState * state, size_t blockWidth) {
2067  KrkScanner scannerBefore = krk_tellScanner(&state->scanner);
2068  Parser parserBefore = state->parser;
2069  if (blockWidth == 0 || (check(TOKEN_INDENTATION) && (state->parser.current.length == blockWidth))) {
2070  if (blockWidth) advance();
2071  if (match(TOKEN_ELSE)) {
2072  consume(TOKEN_COLON, "Expected ':' after 'else'.");
2073  beginScope(state);
2074  block(state,blockWidth,"else");
2075  endScope(state);
2076  } else {
2077  krk_rewindScanner(&state->scanner, scannerBefore);
2078  state->parser = parserBefore;
2079  }
2080  }
2081 }
2082 
2083 static void whileStatement(struct GlobalState * state) {
2084  size_t blockWidth = (state->parser.previous.type == TOKEN_INDENTATION) ? state->parser.previous.length : 0;
2085  advance();
2086 
2087  int loopStart = currentChunk()->count;
2088  int exitJump = 0;
2089 
2090  /* Identify two common infinite loops and optimize them (True and 1) */
2091  RewindState rewind = {recordChunk(currentChunk()), krk_tellScanner(&state->scanner), state->parser};
2092  if (!(match(TOKEN_TRUE) && match(TOKEN_COLON)) &&
2093  !(match(TOKEN_NUMBER) && (state->parser.previous.length == 1 && *state->parser.previous.start == '1') && match(TOKEN_COLON))) {
2094  /* We did not match a common infinite loop, roll back... */
2095  krk_rewindScanner(&state->scanner, rewind.oldScanner);
2096  state->parser = rewind.oldParser;
2097 
2098  /* Otherwise, compile a real loop condition. */
2099  expression(state);
2100  consume(TOKEN_COLON, "Expected ':' after 'while' condition.");
2101 
2102  exitJump = emitJump(OP_JUMP_IF_FALSE_OR_POP);
2103  }
2104 
2105  int oldLocalCount = state->current->loopLocalCount;
2106  state->current->loopLocalCount = state->current->localCount;
2107  beginScope(state);
2108  block(state,blockWidth,"while");
2109  endScope(state);
2110 
2111  state->current->loopLocalCount = oldLocalCount;
2112  emitLoop(state, loopStart, OP_LOOP);
2113 
2114  if (exitJump) {
2115  patchJump(exitJump);
2116  emitByte(OP_POP);
2117  }
2118 
2119  /* else: block must still be compiled even if we optimized
2120  * out the loop condition check... */
2121  optionalElse(state, blockWidth);
2122 
2123  patchBreaks(state, loopStart);
2124 }
2125 
2126 static void forStatement(struct GlobalState * state) {
2127  /* I'm not sure if I want this to be more like Python or C/Lox/etc. */
2128  size_t blockWidth = (state->parser.previous.type == TOKEN_INDENTATION) ? state->parser.previous.length : 0;
2129  advance();
2130 
2131  /* For now this is going to be kinda broken */
2132  beginScope(state);
2133 
2134  ssize_t loopInd = state->current->localCount;
2135  int sawComma = 0;
2136  ssize_t varCount = 0;
2137  int matchedEquals = 0;
2138 
2139  if (!check(TOKEN_IDENTIFIER)) {
2140  errorAtCurrent("Empty variable list in 'for'");
2141  return;
2142  }
2143 
2144  do {
2145  if (!check(TOKEN_IDENTIFIER)) break;
2146  ssize_t ind = parseVariable(state, "Expected name for loop iterator.");
2147  if (state->parser.hadError) return;
2148  if (match(TOKEN_EQUAL)) {
2149  matchedEquals = 1;
2150  expression(state);
2151  } else {
2152  emitByte(OP_NONE);
2153  }
2154  defineVariable(state, ind);
2155  varCount++;
2156  if (check(TOKEN_COMMA)) sawComma = 1;
2157  } while (match(TOKEN_COMMA));
2158 
2159  int loopStart;
2160  int exitJump;
2161  int isIter = 0;
2162 
2163  if (!matchedEquals && match(TOKEN_IN)) {
2164 
2165  beginScope(state);
2166  expression(state);
2167  endScope(state);
2168 
2169  anonymousLocal(state);
2170  emitByte(OP_INVOKE_ITER);
2171  loopStart = currentChunk()->count;
2172  exitJump = emitJump(OP_CALL_ITER);
2173 
2174  if (varCount > 1 || sawComma) {
2175  EMIT_OPERAND_OP(OP_UNPACK, varCount);
2176  for (ssize_t i = loopInd + varCount - 1; i >= loopInd; i--) {
2177  EMIT_OPERAND_OP(OP_SET_LOCAL_POP, i);
2178  }
2179  } else {
2180  EMIT_OPERAND_OP(OP_SET_LOCAL_POP, loopInd);
2181  }
2182 
2183  isIter = 1;
2184 
2185  } else {
2186  consume(TOKEN_SEMICOLON,"Expected ';' after C-style loop initializer.");
2187  loopStart = currentChunk()->count;
2188 
2189  beginScope(state);
2190  expression(state); /* condition */
2191  endScope(state);
2192  exitJump = emitJump(OP_JUMP_IF_FALSE_OR_POP);
2193 
2194  if (check(TOKEN_SEMICOLON)) {
2195  advance();
2196  int bodyJump = emitJump(OP_JUMP);
2197  int incrementStart = currentChunk()->count;
2198  beginScope(state);
2199  do {
2200  expressionStatement(state);
2201  } while (match(TOKEN_COMMA));
2202  endScope(state);
2203 
2204  emitLoop(state, loopStart, OP_LOOP);
2205  loopStart = incrementStart;
2206  patchJump(bodyJump);
2207  }
2208  }
2209 
2210  consume(TOKEN_COLON,"Expected ':' after loop conditions.");
2211 
2212  int oldLocalCount = state->current->loopLocalCount;
2213  state->current->loopLocalCount = state->current->localCount;
2214  beginScope(state);
2215  block(state,blockWidth,"for");
2216  endScope(state);
2217 
2218  state->current->loopLocalCount = oldLocalCount;
2219  emitLoop(state, loopStart, isIter ? OP_LOOP_ITER : OP_LOOP);
2220  patchJump(exitJump);
2221  emitByte(OP_POP);
2222  optionalElse(state, blockWidth);
2223  patchBreaks(state, loopStart);
2224  endScope(state);
2225 }
2226 
2227 static void returnStatement(struct GlobalState * state) {
2228  if (check(TOKEN_EOL) || check(TOKEN_EOF)) {
2229  emitReturn(state);
2230  } else {
2231  if (state->current->type == TYPE_INIT) {
2232  error("__init__ may not return a value.");
2233  }
2234  parsePrecedence(state, PREC_ASSIGNMENT);
2235  emitByte(OP_RETURN);
2236  }
2237 }
2238 
2239 static void tryStatement(struct GlobalState * state) {
2240  size_t blockWidth = (state->parser.previous.type == TOKEN_INDENTATION) ? state->parser.previous.length : 0;
2241  advance();
2242  consume(TOKEN_COLON, "Expected ':' after 'try'.");
2243 
2244  /* Make sure we are in a local scope so this ends up on the stack */
2245  beginScope(state);
2246  int tryJump = emitJump(OP_PUSH_TRY);
2247 
2248  size_t exceptionObject = anonymousLocal(state);
2249  anonymousLocal(state); /* Try */
2250 
2251  beginScope(state);
2252  block(state,blockWidth,"try");
2253  endScope(state);
2254 
2255  if (state->parser.hadError) return;
2256 
2257 #define EXIT_JUMP_MAX 64
2258  int exitJumps = 2;
2259  int exitJumpOffsets[EXIT_JUMP_MAX] = {0};
2260 
2261  /* Jump possibly to `else` */
2262  exitJumpOffsets[0] = emitJump(OP_JUMP);
2263 
2264  /* Except entry point; ENTER_EXCEPT jumps to `finally` or continues to
2265  * first `except` expression test; may end up redundant if there is only an 'else'. */
2266  patchJump(tryJump);
2267  exitJumpOffsets[1] = emitJump(OP_ENTER_EXCEPT);
2268 
2269  int firstJump = 0;
2270  int nextJump = -1;
2271 
2272 _anotherExcept:
2273  if (state->parser.hadError) return;
2274  if (blockWidth == 0 || (check(TOKEN_INDENTATION) && (state->parser.current.length == blockWidth))) {
2275  KrkToken previous;
2276  if (blockWidth) {
2277  previous = state->parser.previous;
2278  advance();
2279  }
2280  if (exitJumps && !firstJump && match(TOKEN_EXCEPT)) {
2281  if (nextJump != -1) {
2282  patchJump(nextJump);
2283  }
2284  /* Match filter expression (should be class or tuple) */
2285  if (!check(TOKEN_COLON) && !check(TOKEN_AS)) {
2286  expression(state);
2287  } else {
2288  emitByte(OP_NONE);
2289  }
2290  nextJump = emitJump(OP_FILTER_EXCEPT);
2291 
2292  /* Match 'as' to rename exception */
2293  size_t nameInd = 0;
2294  if (match(TOKEN_AS)) {
2295  consume(TOKEN_IDENTIFIER, "Expected identifier after 'as'.");
2296  state->current->locals[exceptionObject].name = state->parser.previous;
2297  /* `renameLocal` only introduces names for scoped debugging */
2298  nameInd = renameLocal(state, exceptionObject, state->parser.previous);
2299  } else {
2300  state->current->locals[exceptionObject].name = syntheticToken("");
2301  }
2302 
2303  consume(TOKEN_COLON, "Expected ':' after 'except'.");
2304  beginScope(state);
2305  block(state,blockWidth,"except");
2306  endScope(state);
2307 
2308  /* Remove scoped name */
2309  if (nameInd) state->current->codeobject->localNames[nameInd].deathday = (size_t)currentChunk()->count;
2310 
2311  if (exitJumps < EXIT_JUMP_MAX) {
2312  exitJumpOffsets[exitJumps++] = emitJump(OP_JUMP);
2313  } else {
2314  error("Too many 'except' clauses.");
2315  return;
2316  }
2317 
2318  goto _anotherExcept;
2319  } else if (firstJump != 1 && match(TOKEN_ELSE)) {
2320  consume(TOKEN_COLON, "Expected ':' after 'else'.");
2321  patchJump(exitJumpOffsets[0]);
2322  firstJump = 1;
2323  emitByte(OP_TRY_ELSE);
2324  state->current->locals[exceptionObject].name = syntheticToken("");
2325  beginScope(state);
2326  block(state, blockWidth, "else");
2327  endScope(state);
2328  if (nextJump == -1) {
2329  /* If there were no except: blocks, we need to make sure that the
2330  * 'try' handler goes directly to the finally, so that 'break'/'continue'
2331  * within the 'try' does not run this 'else' step. */
2332  patchJump(tryJump);
2333  }
2334  goto _anotherExcept;
2335  } else if (match(TOKEN_FINALLY)) {
2336  consume(TOKEN_COLON, "Expected ':' after 'finally'.");
2337  for (int i = firstJump; i < exitJumps; ++i) {
2338  patchJump(exitJumpOffsets[i]);
2339  }
2340  if (nextJump != -1) {
2341  patchJump(nextJump);
2342  }
2343  emitByte(OP_BEGIN_FINALLY);
2344  exitJumps = 0;
2345  state->current->locals[exceptionObject].name = syntheticToken("");
2346  beginScope(state);
2347  block(state,blockWidth,"finally");
2348  endScope(state);
2349  nextJump = -2;
2350  emitByte(OP_END_FINALLY);
2351  } else if (!check(TOKEN_EOL) && !check(TOKEN_EOF)) {
2352  krk_ungetToken(&state->scanner, state->parser.current);
2353  state->parser.current = state->parser.previous;
2354  if (blockWidth) {
2355  state->parser.previous = previous;
2356  }
2357  } else {
2358  advance(); /* Ignore this blank indentation line */
2359  }
2360  }
2361 
2362  for (int i = firstJump; i < exitJumps; ++i) {
2363  patchJump(exitJumpOffsets[i]);
2364  }
2365 
2366  if (nextJump >= 0) {
2367  patchJump(nextJump);
2368  emitByte(OP_BEGIN_FINALLY);
2369  emitByte(OP_END_FINALLY);
2370  }
2371 
2372  endScope(state); /* will pop the exception handler */
2373 }
2374 
2375 static void raiseStatement(struct GlobalState * state) {
2376  parsePrecedence(state, PREC_ASSIGNMENT);
2377 
2378  if (match(TOKEN_FROM)) {
2379  parsePrecedence(state, PREC_ASSIGNMENT);
2380  emitByte(OP_RAISE_FROM);
2381  } else {
2382  emitByte(OP_RAISE);
2383  }
2384 }
2385 
2386 static size_t importModule(struct GlobalState * state, KrkToken * startOfName, int leadingDots) {
2387  size_t ind = 0;
2388  struct StringBuilder sb = {0};
2389 
2390  for (int i = 0; i < leadingDots; ++i) {
2391  pushStringBuilder(&sb, '.');
2392  }
2393 
2394  if (!(leadingDots && check(TOKEN_IMPORT))) {
2395  consume(TOKEN_IDENTIFIER, "Expected module name after 'import'.");
2396  if (state->parser.hadError) goto _freeImportName;
2397  pushStringBuilderStr(&sb, state->parser.previous.start, state->parser.previous.length);
2398 
2399  while (match(TOKEN_DOT)) {
2400  pushStringBuilderStr(&sb, state->parser.previous.start, state->parser.previous.length);
2401  consume(TOKEN_IDENTIFIER, "Expected module path element after '.'");
2402  if (state->parser.hadError) goto _freeImportName;
2403  pushStringBuilderStr(&sb, state->parser.previous.start, state->parser.previous.length);
2404  }
2405  }
2406 
2407  startOfName->start = sb.bytes;
2408  startOfName->length = sb.length;
2409 
2410  ind = identifierConstant(state, startOfName);
2411  EMIT_OPERAND_OP(OP_IMPORT, ind);
2412 
2413 _freeImportName:
2414  discardStringBuilder(&sb);
2415  return ind;
2416 }
2417 
2418 static void importStatement(struct GlobalState * state) {
2419  do {
2420  KrkToken firstName = state->parser.current;
2421  KrkToken startOfName = {0};
2422  size_t ind = importModule(state, &startOfName, 0);
2423  if (match(TOKEN_AS)) {
2424  consume(TOKEN_IDENTIFIER, "Expected identifier after 'as'.");
2425  ind = identifierConstant(state, &state->parser.previous);
2426  } else if (startOfName.length != firstName.length) {
2434  emitByte(OP_POP);
2435  state->parser.previous = firstName;
2436  ind = identifierConstant(state, &firstName);
2437  EMIT_OPERAND_OP(OP_IMPORT, ind);
2438  }
2439  declareVariable(state);
2440  defineVariable(state, ind);
2441  } while (match(TOKEN_COMMA));
2442 }
2443 
2444 static void optionsImport(struct GlobalState * state) {
2445  int expectCloseParen = 0;
2446 
2447  KrkToken compile_time_builtins = syntheticToken("compile_time_builtins");
2448  KrkToken no_implicit_self = syntheticToken("no_implicit_self");
2449 
2450  advance();
2451  consume(TOKEN_IMPORT, "__options__ is not a package\n");
2452 
2453  if (match(TOKEN_LEFT_PAREN)) {
2454  expectCloseParen = 1;
2455  startEatingWhitespace();
2456  }
2457 
2458  do {
2459  consume(TOKEN_IDENTIFIER, "Expected member name");
2460 
2461  /* Okay, what is it? */
2462  if (identifiersEqual(&state->parser.previous, &compile_time_builtins)) {
2463  state->current->optionsFlags |= OPTIONS_FLAG_COMPILE_TIME_BUILTINS;
2464  } else if (identifiersEqual(&state->parser.previous, &no_implicit_self)) {
2465  state->current->optionsFlags |= OPTIONS_FLAG_NO_IMPLICIT_SELF;
2466  } else {
2467  error("'%.*s' is not a recognized __options__ import",
2468  (int)state->parser.previous.length, state->parser.previous.start);
2469  break;
2470  }
2471 
2472  if (check(TOKEN_AS)) {
2473  errorAtCurrent("__options__ imports can not be given names");
2474  break;
2475  }
2476 
2477  } while (match(TOKEN_COMMA) && !check(TOKEN_RIGHT_PAREN));
2478 
2479  if (expectCloseParen) {
2480  stopEatingWhitespace();
2481  consume(TOKEN_RIGHT_PAREN, "Expected ')' after import list started with '('");
2482  }
2483 }
2484 
2485 static void fromImportStatement(struct GlobalState * state) {
2486  int expectCloseParen = 0;
2487  KrkToken startOfName = {0};
2488  int leadingDots = 0;
2489 
2490  KrkToken options = syntheticToken("__options__");
2491  if (check(TOKEN_IDENTIFIER) && identifiersEqual(&state->parser.current, &options)) {
2492  /* from __options__ import ... */
2493  optionsImport(state);
2494  return;
2495  }
2496 
2497  while (match(TOKEN_DOT)) {
2498  leadingDots++;
2499  }
2500 
2501  importModule(state, &startOfName, leadingDots);
2502  consume(TOKEN_IMPORT, "Expected 'import' after module name");
2503  if (match(TOKEN_LEFT_PAREN)) {
2504  expectCloseParen = 1;
2505  startEatingWhitespace();
2506  }
2507  do {
2508  consume(TOKEN_IDENTIFIER, "Expected member name");
2509  size_t member = identifierConstant(state, &state->parser.previous);
2510  emitBytes(OP_DUP, 0); /* Duplicate the package object so we can GET_PROPERTY on it? */
2511  EMIT_OPERAND_OP(OP_IMPORT_FROM, member);
2512  if (match(TOKEN_AS)) {
2513  consume(TOKEN_IDENTIFIER, "Expected identifier after 'as'");
2514  member = identifierConstant(state, &state->parser.previous);
2515  }
2516  if (state->current->scopeDepth) {
2517  /* Swaps the original module and the new possible local so it can be in the right place */
2518  emitByte(OP_SWAP);
2519  }
2520  declareVariable(state);
2521  defineVariable(state, member);
2522  } while (match(TOKEN_COMMA) && !check(TOKEN_RIGHT_PAREN));
2523  if (expectCloseParen) {
2524  stopEatingWhitespace();
2525  consume(TOKEN_RIGHT_PAREN, "Expected ')' after import list started with '('");
2526  }
2527  emitByte(OP_POP); /* Pop the remaining copy of the module. */
2528 }
2529 
2530 static void delStatement(struct GlobalState * state) {
2531  do {
2532  state->current->delSatisfied = 0;
2533  parsePrecedence(state, PREC_DEL_TARGET);
2534  if (!state->current->delSatisfied) {
2535  errorAtCurrent("Invalid del target");
2536  }
2537  } while (match(TOKEN_COMMA));
2538 }
2539 
2540 static void assertStatement(struct GlobalState * state) {
2541  expression(state);
2542  int elseJump = emitJump(OP_JUMP_IF_TRUE_OR_POP);
2543 
2544  KrkToken assertionError = syntheticToken("AssertionError");
2545  size_t ind = identifierConstant(state, &assertionError);
2546  EMIT_OPERAND_OP(OP_GET_GLOBAL, ind);
2547  int args = 0;
2548 
2549  if (match(TOKEN_COMMA)) {
2550  expression(state);
2551  args = 1;
2552  }
2553 
2554  EMIT_OPERAND_OP(OP_CALL, args);
2555  emitByte(OP_RAISE);
2556 
2557  patchJump(elseJump);
2558  emitByte(OP_POP);
2559 }
2560 
2561 static void errorAfterStatement(struct GlobalState * state) {
2562  switch (state->parser.current.type) {
2563  case TOKEN_RIGHT_BRACE:
2564  case TOKEN_RIGHT_PAREN:
2565  case TOKEN_RIGHT_SQUARE:
2566  errorAtCurrent("Unmatched '%.*s'",
2567  (int)state->parser.current.length, state->parser.current.start);
2568  break;
2569  case TOKEN_IDENTIFIER:
2570  errorAtCurrent("Unexpected %.*s after statement.",10,"identifier");
2571  break;
2572  case TOKEN_STRING:
2573  case TOKEN_BIG_STRING:
2574  errorAtCurrent("Unexpected %.*s after statement.",6,"string");
2575  break;
2576  default:
2577  errorAtCurrent("Unexpected %.*s after statement.",
2578  (int)state->parser.current.length, state->parser.current.start);
2579  }
2580 }
2581 
2582 static void simpleStatement(struct GlobalState * state) {
2583 _anotherSimpleStatement:
2584  if (match(TOKEN_RAISE)) {
2585  raiseStatement(state);
2586  } else if (match(TOKEN_RETURN)) {
2587  returnStatement(state);
2588  } else if (match(TOKEN_IMPORT)) {
2589  importStatement(state);
2590  } else if (match(TOKEN_FROM)) {
2591  fromImportStatement(state);
2592  } else if (match(TOKEN_BREAK)) {
2593  breakStatement(state);
2594  } else if (match(TOKEN_CONTINUE)) {
2595  continueStatement(state);
2596  } else if (match(TOKEN_DEL)) {
2597  delStatement(state);
2598  } else if (match(TOKEN_ASSERT)) {
2599  assertStatement(state);
2600  } else if (match(TOKEN_PASS)) {
2601  /* Do nothing. */
2602  } else if (match(TOKEN_LET)) {
2603  letDeclaration(state);
2604  } else {
2605  expressionStatement(state);
2606  }
2607  if (match(TOKEN_SEMICOLON)) goto _anotherSimpleStatement;
2608  if (!match(TOKEN_EOL) && !match(TOKEN_EOF)) {
2609  errorAfterStatement(state);
2610  }
2611 }
2612 
2613 static void statement(struct GlobalState * state) {
2614  if (match(TOKEN_EOL) || match(TOKEN_EOF)) {
2615  return; /* Meaningless blank line */
2616  }
2617 
2618  if (check(TOKEN_IF)) {
2619  ifStatement(state);
2620  } else if (check(TOKEN_WHILE)) {
2621  whileStatement(state);
2622  } else if (check(TOKEN_FOR)) {
2623  forStatement(state);
2624  } else if (check(TOKEN_ASYNC)) {
2625  asyncDeclaration(state, 0);
2626  } else if (check(TOKEN_TRY)) {
2627  tryStatement(state);
2628  } else if (check(TOKEN_WITH)) {
2629  withStatement(state);
2630  } else {
2631  /* These statements don't eat line feeds, so we need expect to see another one. */
2632  simpleStatement(state);
2633  }
2634 }
2635 
2636 static void yield(struct GlobalState * state, int exprType, RewindState *rewind) {
2637  if (state->current->type == TYPE_MODULE ||
2638  state->current->type == TYPE_INIT ||
2639  state->current->type == TYPE_CLASS) {
2640  error("'yield' outside function");
2641  return;
2642  }
2643  state->current->codeobject->obj.flags |= KRK_OBJ_FLAGS_CODEOBJECT_IS_GENERATOR;
2644  if (match(TOKEN_FROM)) {
2645  parsePrecedence(state, PREC_ASSIGNMENT);
2646  emitByte(OP_INVOKE_ITER);
2647  emitByte(OP_NONE);
2648  size_t loopContinue = currentChunk()->count;
2649  size_t exitJump = emitJump(OP_YIELD_FROM);
2650  emitByte(OP_YIELD);
2651  emitLoop(state, loopContinue, OP_LOOP);
2652  patchJump(exitJump);
2653  } else if (check(TOKEN_EOL) || check(TOKEN_EOF) || check(TOKEN_RIGHT_PAREN) || check(TOKEN_RIGHT_BRACE)) {
2654  emitByte(OP_NONE);
2655  emitByte(OP_YIELD);
2656  } else {
2657  parsePrecedence(state, PREC_ASSIGNMENT);
2658  emitByte(OP_YIELD);
2659  }
2660  invalidTarget(state, exprType, "yield");
2661 }
2662 
2663 static void await(struct GlobalState * state, int exprType, RewindState *rewind) {
2664  if (!isCoroutine(state->current->type)) {
2665  error("'await' outside async function");
2666  return;
2667  }
2668 
2669  parsePrecedence(state, PREC_ASSIGNMENT);
2670  emitByte(OP_INVOKE_AWAIT);
2671  emitByte(OP_NONE);
2672  size_t loopContinue = currentChunk()->count;
2673  size_t exitJump = emitJump(OP_YIELD_FROM);
2674  emitByte(OP_YIELD);
2675  emitLoop(state, loopContinue, OP_LOOP);
2676  patchJump(exitJump);
2677  invalidTarget(state, exprType, "await");
2678 }
2679 
2680 static void unot_(struct GlobalState * state, int exprType, RewindState *rewind) {
2681  parsePrecedence(state, PREC_NOT);
2682  emitByte(OP_NOT);
2683  invalidTarget(state, exprType, "operator");
2684 }
2685 
2686 static void unary(struct GlobalState * state, int exprType, RewindState *rewind) {
2687  KrkTokenType operatorType = state->parser.previous.type;
2688  parsePrecedence(state, PREC_FACTOR);
2689  invalidTarget(state, exprType, "operator");
2690  switch (operatorType) {
2691  case TOKEN_PLUS: emitByte(OP_POS); break;
2692  case TOKEN_MINUS: emitByte(OP_NEGATE); break;
2693  case TOKEN_TILDE: emitByte(OP_BITNEGATE); break;
2694  case TOKEN_BANG: emitByte(OP_NOT); break;
2695  default: return;
2696  }
2697 }
2698 
2699 static int isHex(int c) {
2700  return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
2701 }
2702 
2703 static int _pushHex(struct GlobalState * state, int isBytes, struct StringBuilder * sb, const char *c, const char *end, size_t n, char type) {
2704  char tmpbuf[10] = {0};
2705  for (size_t i = 0; i < n; ++i) {
2706  if (c + i + 2 == end || !isHex(c[i+2])) {
2707  error("truncated \\%c escape", type);
2708  return 1;
2709  }
2710  tmpbuf[i] = c[i+2];
2711  }
2712  unsigned long value = strtoul(tmpbuf, NULL, 16);
2713  if (value >= 0x110000) {
2714  error("invalid codepoint in \\%c escape", type);
2715  return 1;
2716  }
2717  if (isBytes) {
2718  krk_pushStringBuilder(sb, value);
2719  } else {
2720  unsigned char bytes[5] = {0};
2721  size_t len = krk_codepointToBytes(value, bytes);
2722  krk_pushStringBuilderStr(sb, (char*)bytes, len);
2723  }
2724  return 0;
2725 }
2726 
2727 static void string(struct GlobalState * state, int exprType, RewindState *rewind) {
2728  struct StringBuilder sb = {0};
2729 #define PUSH_CHAR(c) krk_pushStringBuilder(&sb, c)
2730 #define PUSH_HEX(n, type) _pushHex(state, isBytes, &sb, c, end, n, type)
2731 
2732  int isBytes = (state->parser.previous.type == TOKEN_PREFIX_B);
2733  int isFormat = (state->parser.previous.type == TOKEN_PREFIX_F);
2734  int isRaw = (state->parser.previous.type == TOKEN_PREFIX_R);
2735 
2736  const char * lineBefore = krk_tellScanner(&state->scanner).linePtr;
2737  size_t lineNo = krk_tellScanner(&state->scanner).line;
2738 
2739  if ((isBytes || isFormat || isRaw) && !(match(TOKEN_STRING) || match(TOKEN_BIG_STRING))) {
2740  error("Expected string after prefix? (Internal error - scanner should not have produced this.)");
2741  return;
2742  }
2743 
2744  int formatElements = 0;
2745 
2746  /* This should capture everything but the quotes. */
2747  do {
2748  if (isRaw) {
2749  for (size_t i = 0; i < state->parser.previous.length - (state->parser.previous.type == TOKEN_BIG_STRING ? 6 : 2); ++i) {
2750  PUSH_CHAR(state->parser.previous.start[(state->parser.previous.type == TOKEN_BIG_STRING ? 3 : 1) + i]);
2751  }
2752  goto _nextStr;
2753  }
2754  int type = state->parser.previous.type == TOKEN_BIG_STRING ? 3 : 1;
2755  const char * c = state->parser.previous.start + type;
2756  const char * end = state->parser.previous.start + state->parser.previous.length - type;
2757  while (c < end) {
2758  if (*c == '\\') {
2759  switch (c[1]) {
2760  case '\\': PUSH_CHAR('\\'); break;
2761  case '\'': PUSH_CHAR('\''); break;
2762  case '\"': PUSH_CHAR('\"'); break;
2763  case 'a': PUSH_CHAR('\a'); break;
2764  case 'b': PUSH_CHAR('\b'); break;
2765  case 'f': PUSH_CHAR('\f'); break;
2766  case 'n': PUSH_CHAR('\n'); break;
2767  case 'r': PUSH_CHAR('\r'); break;
2768  case 't': PUSH_CHAR('\t'); break;
2769  case 'v': PUSH_CHAR('\v'); break;
2770  case '[': PUSH_CHAR('\033'); break;
2771  case 'x': {
2772  PUSH_HEX(2,'x');
2773  c += 2;
2774  } break;
2775  case 'u': {
2776  if (isBytes) {
2777  PUSH_CHAR(c[0]);
2778  PUSH_CHAR(c[1]);
2779  } else {
2780  PUSH_HEX(4,'u');
2781  c += 4;
2782  }
2783  } break;
2784  case 'U': {
2785  if (isBytes) {
2786  PUSH_CHAR(c[0]);
2787  PUSH_CHAR(c[1]);
2788  } else {
2789  PUSH_HEX(8,'U');
2790  c += 8;
2791  }
2792  } break;
2793  case '\n': break;
2794  default:
2795  if (c[1] >= '0' && c[1] <= '7') {
2796  int out = c[1] - '0';
2797  if (c + 2 != end && (c[2] >= '0' && c[2] <= '7')) {
2798  out <<= 3;
2799  out += c[2] - '0';
2800  c++;
2801  if (c + 1 != end && (c[2] >= '0' && c[2] <= '7')) {
2802  out <<= 3;
2803  out += c[2] - '0';
2804  c++;
2805  }
2806  }
2807  if (isBytes) {
2808  out = out % 256;
2809  PUSH_CHAR(out);
2810  } else {
2811  unsigned char bytes[5] = {0};
2812  size_t len = krk_codepointToBytes(out, bytes);
2813  for (size_t i = 0; i < len; i++) PUSH_CHAR(bytes[i]);
2814  }
2815  } else {
2816  PUSH_CHAR(c[0]);
2817  c++;
2818  continue;
2819  }
2820  }
2821  c += 2;
2822  } else if (isFormat && *c == '}') {
2823  if (c[1] != '}') {
2824  error("single '}' not allowed in f-string");
2825  goto _cleanupError;
2826  }
2827  PUSH_CHAR('}');
2828  c += 2;
2829  continue;
2830  } else if (isFormat && *c == '{') {
2831  if (c[1] == '{') {
2832  PUSH_CHAR('{');
2833  c += 2;
2834  continue;
2835  }
2836  if (sb.length) { /* Make sure there's a string for coersion reasons */
2837  emitConstant(krk_finishStringBuilder(&sb));
2838  formatElements++;
2839  }
2840  const char * start = c+1;
2841  KrkScanner beforeExpression = krk_tellScanner(&state->scanner);
2842  Parser parserBefore = state->parser;
2843  KrkScanner inner = (KrkScanner){.start=c+1, .cur=c+1, .linePtr=lineBefore, .line=lineNo, .startOfLine = 0, .hasUnget = 0};
2844  krk_rewindScanner(&state->scanner, inner);
2845  advance();
2846  parsePrecedence(state, PREC_COMMA); /* allow unparen'd tuples, but not assignments, as expressions in f-strings */
2847  if (state->parser.hadError) goto _cleanupError;
2848  inner = krk_tellScanner(&state->scanner); /* To figure out how far to advance c */
2849  krk_rewindScanner(&state->scanner, beforeExpression); /* To get us back to where we were with a string token */
2850  state->parser = parserBefore;
2851  c = inner.start;
2852 
2853  int formatType = 0;
2854 
2855  while (*c == ' ') c++;
2856  if (*c == '=') {
2857  c++;
2858  while (*c == ' ') c++;
2859  emitConstant(OBJECT_VAL(krk_copyString(start,c-start)));
2860  formatElements++;
2861  formatType |= FORMAT_OP_EQ;
2862  }
2863 
2864  if (*c == '!') {
2865  c++;
2866  /* Conversion specifiers, must only be one */
2867  if (*c == 'r') {
2868  formatType |= FORMAT_OP_REPR;
2869  } else if (*c == 's') {
2870  formatType |= FORMAT_OP_STR;
2871  } else {
2872  error("Unsupported conversion flag '%c' for f-string expression.", *c);
2873  goto _cleanupError;
2874  }
2875  c++;
2876  }
2877 
2878  if (*c == ':') {
2879  /* TODO format specs */
2880  const char * formatStart = c+1;
2881  c++;
2882  while (c < end && *c != '}') c++;
2883  emitConstant(OBJECT_VAL(krk_copyString(formatStart,c-formatStart)));
2884  formatType |= FORMAT_OP_FORMAT;
2885  }
2886 
2887  /* Default to !r if '=' was present but neither was specified. */
2888  if (!(formatType & (FORMAT_OP_FORMAT | FORMAT_OP_STR)) && (formatType & FORMAT_OP_EQ)) {
2889  formatType |= FORMAT_OP_REPR;
2890  }
2891 
2892  EMIT_OPERAND_OP(OP_FORMAT_VALUE, formatType);
2893 
2894  if (*c != '}') {
2895  error("Expected closing '}' after expression in f-string");
2896  goto _cleanupError;
2897  }
2898 
2899  formatElements++;
2900  c++;
2901  } else {
2902  if (*(unsigned char*)c > 127 && isBytes) {
2903  error("bytes literal can only contain ASCII characters");
2904  goto _cleanupError;
2905  }
2906  PUSH_CHAR(*c);
2907  c++;
2908  }
2909  }
2910 
2911 _nextStr:
2912  (void)0;
2913  isRaw = 0;
2914  isFormat = 0;
2915  if (!isBytes) {
2916  if (match(TOKEN_PREFIX_F)) {
2917  isFormat = 1;
2918  } else if (match(TOKEN_PREFIX_R)) {
2919  isRaw = 1;
2920  }
2921  }
2922  } while ((!isBytes || match(TOKEN_PREFIX_B)) && (match(TOKEN_STRING) || match(TOKEN_BIG_STRING)));
2923  if (isBytes && (match(TOKEN_STRING) || match(TOKEN_BIG_STRING))) {
2924  error("Can not mix bytes and string literals");
2925  goto _cleanupError;
2926  }
2927  if (isBytes) {
2928  emitConstant(krk_finishStringBuilderBytes(&sb));
2929  return;
2930  }
2931  if (sb.length || !formatElements) {
2932  emitConstant(krk_finishStringBuilder(&sb));
2933  formatElements++;
2934  }
2935  if (formatElements != 1) {
2936  EMIT_OPERAND_OP(OP_MAKE_STRING, formatElements);
2937  }
2938 _cleanupError:
2940 #undef PUSH_CHAR
2941 }
2942 
2943 static size_t addUpvalue(struct GlobalState * state, Compiler * compiler, ssize_t index, int isLocal, KrkToken name) {
2944  size_t upvalueCount = compiler->codeobject->upvalueCount;
2945  for (size_t i = 0; i < upvalueCount; ++i) {
2946  Upvalue * upvalue = &compiler->upvalues[i];
2947  if ((ssize_t)upvalue->index == index && upvalue->isLocal == isLocal) {
2948  return i;
2949  }
2950  }
2951  if (upvalueCount + 1 > compiler->upvaluesSpace) {
2952  size_t old = compiler->upvaluesSpace;
2953  compiler->upvaluesSpace = GROW_CAPACITY(old);
2954  compiler->upvalues = GROW_ARRAY(Upvalue,compiler->upvalues,old,compiler->upvaluesSpace);
2955  }
2956  compiler->upvalues[upvalueCount].isLocal = isLocal;
2957  compiler->upvalues[upvalueCount].index = index;
2958  compiler->upvalues[upvalueCount].name = name;
2959  return compiler->codeobject->upvalueCount++;
2960 }
2961 
2962 static ssize_t resolveUpvalue(struct GlobalState * state, Compiler * compiler, KrkToken * name) {
2963  size_t upvalueCount = compiler->codeobject->upvalueCount;
2964  for (size_t i = 0; i < upvalueCount; ++i) {
2965  if (identifiersEqual(name, &compiler->upvalues[i].name)) {
2966  return i;
2967  }
2968  }
2969 
2970  if (compiler->enclosing == NULL) return -1;
2971 
2972  ssize_t local = resolveLocal(state, compiler->enclosing, name);
2973  if (local != -1) {
2974  compiler->enclosing->locals[local].isCaptured = 1;
2975  return addUpvalue(state, compiler, local, 1, *name);
2976  }
2977  ssize_t upvalue = resolveUpvalue(state, compiler->enclosing, name);
2978  if (upvalue != -1) {
2979  return addUpvalue(state, compiler, upvalue, 0, *name);
2980  }
2981  return -1;
2982 }
2983 
2984 #define OP_NONE_LONG -1
2985 #define DO_VARIABLE(opset,opget,opdel) do { \
2986  if (exprType == EXPR_ASSIGN_TARGET) { \
2987  if (matchComplexEnd(state)) { \
2988  EMIT_OPERAND_OP(opset, arg); \
2989  break; \
2990  } \
2991  exprType = EXPR_NORMAL; \
2992  } \
2993  if (exprType == EXPR_CAN_ASSIGN && match(TOKEN_EQUAL)) { \
2994  parsePrecedence(state, PREC_ASSIGNMENT); \
2995  EMIT_OPERAND_OP(opset, arg); \
2996  } else if (exprType == EXPR_CAN_ASSIGN && matchAssignment(state)) { \
2997  EMIT_OPERAND_OP(opget, arg); \
2998  assignmentValue(state); \
2999  EMIT_OPERAND_OP(opset, arg); \
3000  } else if (exprType == EXPR_DEL_TARGET && checkEndOfDel(state)) {\
3001  if (opdel == OP_NONE) { emitByte(OP_NONE); EMIT_OPERAND_OP(opset, arg); } \
3002  else { EMIT_OPERAND_OP(opdel, arg); } \
3003  } else { \
3004  EMIT_OPERAND_OP(opget, arg); \
3005  } } while (0)
3006 
3007 static void namedVariable(struct GlobalState * state, KrkToken name, int exprType) {
3008  if (state->current->type == TYPE_CLASS) {
3009  /* Only at the class body level, see if this is a class property. */
3010  struct IndexWithNext * properties = state->current->properties;
3011  while (properties) {
3012  KrkString * constant = AS_STRING(currentChunk()->constants.values[properties->ind]);
3013  if (constant->length == name.length && !memcmp(constant->chars, name.start, name.length)) {
3014  ssize_t arg = properties->ind;
3015  DO_VARIABLE(OP_SET_NAME, OP_GET_NAME, OP_NONE);
3016  return;
3017  }
3018  properties = properties->next;
3019  }
3020  }
3021  ssize_t arg = resolveLocal(state, state->current, &name);
3022  if (arg != -1) {
3023  DO_VARIABLE(OP_SET_LOCAL, OP_GET_LOCAL, OP_NONE);
3024  } else if ((arg = resolveUpvalue(state, state->current, &name)) != -1) {
3025  DO_VARIABLE(OP_SET_UPVALUE, OP_GET_UPVALUE, OP_NONE);
3026  } else {
3027  if ((state->current->optionsFlags & OPTIONS_FLAG_COMPILE_TIME_BUILTINS) && *name.start != '_') {
3028  KrkValue value;
3029  if (krk_tableGet_fast(&vm.builtins->fields, krk_copyString(name.start, name.length), &value)) {
3030  if ((exprType == EXPR_ASSIGN_TARGET && matchComplexEnd(state)) ||
3031  (exprType == EXPR_CAN_ASSIGN && match(TOKEN_EQUAL)) ||
3032  (exprType == EXPR_CAN_ASSIGN && matchAssignment(state))) {
3033  error("Can not assign to '%.*s' when 'compile_time_builtins' is enabled.",
3034  (int)name.length, name.start);
3035  } else if (exprType == EXPR_DEL_TARGET && checkEndOfDel(state)) {
3036  error("Can not delete '%.*s' when 'compile_time_builtins' is enabled.",
3037  (int)name.length, name.start);
3038  } else {
3039  emitConstant(value);
3040  }
3041  return;
3042  }
3043  }
3044  arg = identifierConstant(state, &name);
3045  DO_VARIABLE(OP_SET_GLOBAL, OP_GET_GLOBAL, OP_DEL_GLOBAL);
3046  }
3047 }
3048 #undef DO_VARIABLE
3049 
3050 static void variable(struct GlobalState * state, int exprType, RewindState *rewind) {
3051  namedVariable(state, state->parser.previous, exprType);
3052 }
3053 
3054 static int isClassOrStaticMethod(FunctionType type) {
3055  return (type == TYPE_STATIC || type == TYPE_CLASSMETHOD);
3056 }
3057 
3058 static void super_(struct GlobalState * state, int exprType, RewindState *rewind) {
3059  consume(TOKEN_LEFT_PAREN, "Expected 'super' to be called.");
3060 
3061  /* Argument time */
3062  if (match(TOKEN_RIGHT_PAREN)) {
3063  if (!isMethod(state->current->type) && !isClassOrStaticMethod(state->current->type)) {
3064  error("super() outside of a method body requires arguments");
3065  return;
3066  }
3067  if (!state->current->codeobject->potentialPositionals) {
3068  error("super() is not valid in a function with no arguments");
3069  return;
3070  }
3071  namedVariable(state, state->currentClass->name, 0);
3072  EMIT_OPERAND_OP(OP_GET_LOCAL, 0);
3073  } else {
3074  expression(state);
3075  if (match(TOKEN_COMMA)) {
3076  expression(state);
3077  } else {
3078  emitByte(OP_UNSET);
3079  }
3080  consume(TOKEN_RIGHT_PAREN, "Expected ')' after argument list");
3081  }
3082  consume(TOKEN_DOT, "Expected a field of 'super()' to be referenced.");
3083  consume(TOKEN_IDENTIFIER, "Expected a field name.");
3084  size_t ind = identifierConstant(state, &state->parser.previous);
3085  EMIT_OPERAND_OP(OP_GET_SUPER, ind);
3086 }
3087 
3088 static void comprehensionInner(struct GlobalState * state, KrkScanner scannerBefore, Parser parserBefore, void (*body)(struct GlobalState*,size_t), size_t arg) {
3089  ssize_t loopInd = state->current->localCount;
3090  ssize_t varCount = 0;
3091  int sawComma = 0;
3092  if (!check(TOKEN_IDENTIFIER)) {
3093  errorAtCurrent("Empty variable list in comprehension");
3094  return;
3095  }
3096  do {
3097  if (!check(TOKEN_IDENTIFIER)) break;
3098  defineVariable(state, parseVariable(state, "Expected name for iteration variable."));
3099  if (state->parser.hadError) return;
3100  emitByte(OP_NONE);
3101  defineVariable(state, loopInd);
3102  varCount++;
3103  if (check(TOKEN_COMMA)) sawComma = 1;
3104  } while (match(TOKEN_COMMA));
3105 
3106  consume(TOKEN_IN, "Only iterator loops (for ... in ...) are allowed in generator expressions.");
3107 
3108  beginScope(state);
3109  parsePrecedence(state, PREC_OR); /* Otherwise we can get trapped on a ternary */
3110  endScope(state);
3111 
3112  anonymousLocal(state);
3113  emitByte(OP_INVOKE_ITER);
3114  int loopStart = currentChunk()->count;
3115  int exitJump = emitJump(OP_CALL_ITER);
3116 
3117  if (varCount > 1 || sawComma) {
3118  EMIT_OPERAND_OP(OP_UNPACK, varCount);
3119  for (ssize_t i = loopInd + varCount - 1; i >= loopInd; i--) {
3120  EMIT_OPERAND_OP(OP_SET_LOCAL_POP, i);
3121  }
3122  } else {
3123  EMIT_OPERAND_OP(OP_SET_LOCAL_POP, loopInd);
3124  }
3125 
3126  if (match(TOKEN_IF)) {
3127  parsePrecedence(state, PREC_OR);
3128  int acceptJump = emitJump(OP_JUMP_IF_TRUE_OR_POP);
3129  emitLoop(state, loopStart, OP_LOOP);
3130  patchJump(acceptJump);
3131  emitByte(OP_POP); /* Pop condition */
3132  }
3133 
3134  beginScope(state);
3135  if (match(TOKEN_FOR)) {
3136  comprehensionInner(state, scannerBefore, parserBefore, body, arg);
3137  } else {
3138  KrkScanner scannerAfter = krk_tellScanner(&state->scanner);
3139  Parser parserAfter = state->parser;
3140  krk_rewindScanner(&state->scanner, scannerBefore);
3141  state->parser = parserBefore;
3142 
3143  body(state, arg);
3144 
3145  krk_rewindScanner(&state->scanner, scannerAfter);
3146  state->parser = parserAfter;
3147  }
3148  endScope(state);
3149 
3150  emitLoop(state, loopStart, OP_LOOP_ITER);
3151  patchJump(exitJump);
3152  emitByte(OP_POP);
3153 }
3154 
3155 static void yieldInner(struct GlobalState * state, size_t arg) {
3156  (void)arg;
3157  expression(state);
3158  emitBytes(OP_YIELD, OP_POP);
3159 }
3160 
3170 static void generatorExpression(struct GlobalState * state, KrkScanner scannerBefore, Parser parserBefore, void (*body)(struct GlobalState*,size_t)) {
3171  state->parser.previous = syntheticToken("<genexpr>");
3172  Compiler subcompiler;
3173  initCompiler(state, &subcompiler, TYPE_FUNCTION);
3174  subcompiler.codeobject->chunk.filename = subcompiler.enclosing->codeobject->chunk.filename;
3175  subcompiler.codeobject->obj.flags |= KRK_OBJ_FLAGS_CODEOBJECT_IS_GENERATOR;
3176 
3177  beginScope(state);
3178  comprehensionInner(state, scannerBefore, parserBefore, body, 0);
3179  endScope(state);
3180 
3181  KrkCodeObject *subfunction = endCompiler(state);
3182  size_t indFunc = krk_addConstant(currentChunk(), OBJECT_VAL(subfunction));
3183  EMIT_OPERAND_OP(OP_CLOSURE, indFunc);
3184  doUpvalues(state, &subcompiler, subfunction);
3185  freeCompiler(&subcompiler);
3186  emitBytes(OP_CALL, 0);
3187 }
3188 
3199 static void comprehensionExpression(struct GlobalState * state, KrkScanner scannerBefore, Parser parserBefore, void (*body)(struct GlobalState *,size_t), int type) {
3200  Compiler subcompiler;
3201  initCompiler(state, &subcompiler, TYPE_LAMBDA);
3202  subcompiler.codeobject->chunk.filename = subcompiler.enclosing->codeobject->chunk.filename;
3203 
3204  beginScope(state);
3205 
3206  /* Build an empty collection to fill up. */
3207  emitBytes(type,0);
3208  size_t ind = anonymousLocal(state);
3209 
3210  beginScope(state);
3211  comprehensionInner(state, scannerBefore, parserBefore, body, ind);
3212  endScope(state);
3213 
3214  KrkCodeObject *subfunction = endCompiler(state);
3215  size_t indFunc = krk_addConstant(currentChunk(), OBJECT_VAL(subfunction));
3216  EMIT_OPERAND_OP(OP_CLOSURE, indFunc);
3217  doUpvalues(state, &subcompiler, subfunction);
3218  freeCompiler(&subcompiler);
3219  emitBytes(OP_CALL, 0);
3220 }
3221 
3222 static size_t finishStarComma(struct GlobalState * state, size_t arg, size_t * argBefore, size_t *argAfter) {
3223  *argBefore = arg;
3224  *argAfter = 1;
3225  EMIT_OPERAND_OP(OP_MAKE_LIST,arg);
3226  parsePrecedence(state, PREC_BITOR);
3227  emitByte(OP_LIST_EXTEND_TOP);
3228 
3229  if (arg == 0 && !check(TOKEN_COMMA)) {
3230  /* While we don't really need to, we disallow a lone @c *expr
3231  * or @c (*expr) without a trailing comma because Python does.
3232  * Catch that here specifically. */
3233  error("* expression not valid here");
3234  return 0;
3235  }
3236 
3237  arg++;
3238 
3239  while (match(TOKEN_COMMA)) {
3240  if (!getRule(state->parser.current.type)->prefix) break;
3241  if (match(TOKEN_ASTERISK)) {
3242  parsePrecedence(state, PREC_BITOR);
3243  emitByte(OP_LIST_EXTEND_TOP);
3244  } else {
3245  parsePrecedence(state, PREC_TERNARY);
3246  emitByte(OP_LIST_APPEND_TOP);
3247  (*argAfter)++;
3248  }
3249  arg++;
3250  }
3251 
3252 
3253  emitByte(OP_TUPLE_FROM_LIST);
3254  return arg;
3255 }
3256 
3264 static void parens(struct GlobalState * state, int exprType, RewindState *rewind) {
3265  /* Record parser state before processing contents. */
3266  ChunkRecorder before = recordChunk(currentChunk());
3267  KrkScanner scannerBefore = krk_tellScanner(&state->scanner);
3268  Parser parserBefore = state->parser;
3269 
3270  /*
3271  * Generator expressions are not valid assignment targets, nor are
3272  * an empty set of parentheses (empty tuple). A single target in
3273  * parens, or a list of targets can be assigned to.
3274  */
3275  int maybeValidAssignment = 0;
3276 
3277  size_t argCount = 0;
3278  size_t argAfter = 0;
3279  size_t argBefore = 0;
3280 
3281  /* Whitespace is ignored inside of parens */
3282  startEatingWhitespace();
3283 
3284  if (check(TOKEN_RIGHT_PAREN)) {
3285  /* Empty paren pair () is an empty tuple. */
3286  emitBytes(OP_TUPLE,0);
3287  } else if (match(TOKEN_ASTERISK)) {
3288  argCount = finishStarComma(state, 0, &argBefore, &argAfter);
3289  maybeValidAssignment = 1;
3290  } else {
3291  parsePrecedence(state, PREC_CAN_ASSIGN);
3292  maybeValidAssignment = 1;
3293  argCount = 1;
3294 
3295  if (match(TOKEN_FOR)) {
3296  /* Parse generator expression. */
3297  maybeValidAssignment = 0;
3298  rewindChunk(currentChunk(), before);
3299  generatorExpression(state, scannerBefore, parserBefore, yieldInner);
3300  } else if (match(TOKEN_COMMA)) {
3301  /* Parse as tuple literal. */
3302  if (!check(TOKEN_RIGHT_PAREN)) {
3303  /* (expr,) is a valid single-element tuple, so we need to check for that. */
3304  do {
3305  if (match(TOKEN_ASTERISK)) {
3306  argCount = finishStarComma(state, argCount, &argBefore, &argAfter);
3307  goto _done;
3308  }
3309  expression(state);
3310  argCount++;
3311  } while (match(TOKEN_COMMA) && !check(TOKEN_RIGHT_PAREN));
3312  }
3313  EMIT_OPERAND_OP(OP_TUPLE, argCount);
3314  }
3315  }
3316 
3317 _done:
3318  stopEatingWhitespace();
3319 
3320  if (!match(TOKEN_RIGHT_PAREN)) {
3321  switch (state->parser.current.type) {
3322  case TOKEN_EQUAL: error("Assignment value expression must be enclosed in parentheses."); break;
3323  default: error("Expected ')' at end of parenthesized expression."); break;
3324  }
3325  }
3326 
3327  if (exprType == EXPR_CAN_ASSIGN && match(TOKEN_EQUAL)) {
3328  if (!argCount) {
3329  error("Can not assign to empty target list.");
3330  } else if (!maybeValidAssignment) {
3331  error("Can not assign to generator expression.");
3332  } else {
3333  complexAssignment(state, before, scannerBefore, parserBefore, argCount, 1, argBefore, argAfter);
3334  }
3335  } else if (exprType == EXPR_ASSIGN_TARGET && (check(TOKEN_EQUAL) || check(TOKEN_COMMA) || check(TOKEN_RIGHT_PAREN))) {
3336  if (!argCount) {
3337  error("Can not assign to empty target list.");
3338  } else if (!maybeValidAssignment) {
3339  error("Can not assign to generator expression.");
3340  } else {
3341  rewindChunk(currentChunk(), before);
3342  complexAssignmentTargets(state, scannerBefore, parserBefore, argCount, 2, argBefore, argAfter);
3343  if (!matchComplexEnd(state)) {
3344  errorAtCurrent("Unexpected end of nested target list");
3345  }
3346  }
3347  }
3348 }
3349 
3355 static void listInner(struct GlobalState * state, size_t arg) {
3356  expression(state);
3357  EMIT_OPERAND_OP(OP_LIST_APPEND, arg);
3358 }
3359 
3360 static void finishStarList(struct GlobalState * state, size_t arg) {
3361  EMIT_OPERAND_OP(OP_MAKE_LIST, arg);
3362 
3363  parsePrecedence(state, PREC_BITOR);
3364  emitByte(OP_LIST_EXTEND_TOP);
3365 
3366  while (match(TOKEN_COMMA) && !check(TOKEN_RIGHT_SQUARE)) {
3367  if (match(TOKEN_ASTERISK)) {
3368  parsePrecedence(state, PREC_BITOR);
3369  emitByte(OP_LIST_EXTEND_TOP);
3370  } else {
3371  expression(state);
3372  emitByte(OP_LIST_APPEND_TOP);
3373  }
3374  }
3375 
3376  stopEatingWhitespace();
3377 
3378  consume(TOKEN_RIGHT_SQUARE,"Expected ']' at end of list expression.");
3379 }
3380 
3386 static void list(struct GlobalState * state, int exprType, RewindState *rewind) {
3387  ChunkRecorder before = recordChunk(currentChunk());
3388 
3389  startEatingWhitespace();
3390 
3391  if (!check(TOKEN_RIGHT_SQUARE)) {
3392  KrkScanner scannerBefore = krk_tellScanner(&state->scanner);
3393  Parser parserBefore = state->parser;
3394  if (match(TOKEN_ASTERISK)) {
3395  finishStarList(state, 0);
3396  return;
3397  }
3398  expression(state);
3399 
3400  if (match(TOKEN_FOR)) {
3401  /* Roll back the earlier compiler */
3402  rewindChunk(currentChunk(), before);
3403  /* Nested fun times */
3404  state->parser.previous = syntheticToken("<listcomp>");
3405  comprehensionExpression(state, scannerBefore, parserBefore, listInner, OP_MAKE_LIST);
3406  } else {
3407  size_t argCount = 1;
3408  while (match(TOKEN_COMMA) && !check(TOKEN_RIGHT_SQUARE)) {
3409  if (match(TOKEN_ASTERISK)) {
3410  finishStarList(state, argCount);
3411  return;
3412  }
3413  expression(state);
3414  argCount++;
3415  }
3416  EMIT_OPERAND_OP(OP_MAKE_LIST, argCount);
3417  }
3418  } else {
3419  /* Empty list expression */
3420  EMIT_OPERAND_OP(OP_MAKE_LIST, 0);
3421  }
3422 
3423  stopEatingWhitespace();
3424 
3425  consume(TOKEN_RIGHT_SQUARE,"Expected ']' at end of list expression.");
3426 }
3427 
3431 static void dictInner(struct GlobalState * state, size_t arg) {
3432  expression(state); /* Key */
3433  consume(TOKEN_COLON, "Expected ':' after dict key.");
3434  expression(state); /* Value */
3435  EMIT_OPERAND_OP(OP_DICT_SET, arg);
3436 }
3437 
3441 static void setInner(struct GlobalState * state, size_t arg) {
3442  expression(state);
3443  EMIT_OPERAND_OP(OP_SET_ADD, arg);
3444 }
3445 
3446 static void finishStarSet(struct GlobalState * state, size_t args) {
3447  EMIT_OPERAND_OP(OP_MAKE_SET, args);
3448 
3449  parsePrecedence(state, PREC_BITOR);
3450  emitByte(OP_SET_UPDATE_TOP);
3451 
3452  while (match(TOKEN_COMMA) && !check(TOKEN_RIGHT_BRACE)) {
3453  if (match(TOKEN_ASTERISK)) {
3454  parsePrecedence(state, PREC_BITOR);
3455  emitByte(OP_SET_UPDATE_TOP);
3456  } else {
3457  expression(state);
3458  emitByte(OP_SET_ADD_TOP);
3459  }
3460  }
3461 
3462  stopEatingWhitespace();
3463  consume(TOKEN_RIGHT_BRACE,"Expected '}' at end of dict expression.");
3464 }
3465 
3466 static void finishStarDict(struct GlobalState * state, size_t args) {
3467  EMIT_OPERAND_OP(OP_MAKE_DICT, args);
3468 
3469  parsePrecedence(state, PREC_BITOR);
3470  emitByte(OP_DICT_UPDATE_TOP);
3471 
3472  while (match(TOKEN_COMMA) && !check(TOKEN_RIGHT_BRACE)) {
3473  if (match(TOKEN_POW)) {
3474  parsePrecedence(state, PREC_BITOR);
3475  emitByte(OP_DICT_UPDATE_TOP);
3476  } else {
3477  expression(state);
3478  consume(TOKEN_COLON, "Expected ':' after dict key.");
3479  expression(state);
3480  emitByte(OP_DICT_SET_TOP);
3481  }
3482  }
3483 
3484  stopEatingWhitespace();
3485  consume(TOKEN_RIGHT_BRACE,"Expected '}' at end of dict expression.");
3486 }
3487 
3499 static void dict(struct GlobalState * state, int exprType, RewindState *rewind) {
3500  ChunkRecorder before = recordChunk(currentChunk());
3501 
3502  startEatingWhitespace();
3503 
3504  if (!check(TOKEN_RIGHT_BRACE)) {
3505  KrkScanner scannerBefore = krk_tellScanner(&state->scanner);
3506  Parser parserBefore = state->parser;
3507 
3508  if (match(TOKEN_ASTERISK)) {
3509  finishStarSet(state, 0);
3510  return;
3511  } else if (match(TOKEN_POW)) {
3512  finishStarDict(state, 0);
3513  return;
3514  }
3515 
3516  expression(state);
3517  if (check(TOKEN_COMMA) || check(TOKEN_RIGHT_BRACE)) {
3518  /* One expression, must be a set literal. */
3519  size_t argCount = 1;
3520  while (match(TOKEN_COMMA) && !check(TOKEN_RIGHT_BRACE)) {
3521  if (match(TOKEN_ASTERISK)) {
3522  finishStarSet(state, argCount);
3523  return;
3524  }
3525  expression(state);
3526  argCount++;
3527  }
3528  EMIT_OPERAND_OP(OP_MAKE_SET, argCount);
3529  } else if (match(TOKEN_FOR)) {
3530  /* One expression followed by 'for': set comprehension. */
3531  rewindChunk(currentChunk(), before);
3532  state->parser.previous = syntheticToken("<setcomp>");
3533  comprehensionExpression(state, scannerBefore, parserBefore, setInner, OP_MAKE_SET);
3534  } else {
3535  /* Anything else must be a colon indicating a dictionary. */
3536  consume(TOKEN_COLON, "Expected ':' after dict key.");
3537  expression(state);
3538 
3539  if (match(TOKEN_FOR)) {
3540  /* Dictionary comprehension */
3541  rewindChunk(currentChunk(), before);
3542  state->parser.previous = syntheticToken("<dictcomp>");
3543  comprehensionExpression(state, scannerBefore, parserBefore, dictInner, OP_MAKE_DICT);
3544  } else {
3545  /*
3546  * The operand to MAKE_DICT is double the number of entries,
3547  * as it is the number of stack slots to consume to produce
3548  * the dict: one for each key, one for each value.
3549  */
3550  size_t argCount = 2;
3551  while (match(TOKEN_COMMA) && !check(TOKEN_RIGHT_BRACE)) {
3552  if (match(TOKEN_POW)) {
3553  finishStarDict(state, argCount);
3554  return;
3555  }
3556  expression(state);
3557  consume(TOKEN_COLON, "Expected ':' after dict key.");
3558  expression(state);
3559  argCount += 2;
3560  }
3561  EMIT_OPERAND_OP(OP_MAKE_DICT, argCount);
3562  }
3563  }
3564  } else {
3565  /* Empty braces, empty dictionary. */
3566  EMIT_OPERAND_OP(OP_MAKE_DICT, 0);
3567  }
3568 
3569  stopEatingWhitespace();
3570 
3571  consume(TOKEN_RIGHT_BRACE,"Expected '}' at end of dict expression.");
3572 }
3573 
3574 static void ternary(struct GlobalState * state, int exprType, RewindState *rewind) {
3575  Parser before = state->parser;
3576  rewindChunk(currentChunk(), rewind->before);
3577 
3578  parsePrecedence(state, PREC_OR);
3579 
3580  int thenJump = emitJump(OP_JUMP_IF_TRUE_OR_POP);
3581  consume(TOKEN_ELSE, "Expected 'else' after ternary condition");
3582 
3583  parsePrecedence(state, PREC_TERNARY);
3584 
3585  KrkScanner outScanner = krk_tellScanner(&state->scanner);
3586  Parser outParser = state->parser;
3587 
3588  int elseJump = emitJump(OP_JUMP);
3589  patchJump(thenJump);
3590  emitByte(OP_POP);
3591 
3592  krk_rewindScanner(&state->scanner, rewind->oldScanner);
3593  state->parser = rewind->oldParser;
3594  parsePrecedence(state, PREC_OR);
3595  patchJump(elseJump);
3596 
3597  if (!check(TOKEN_IF)) {
3598  state->parser = before;
3599  error("syntax error");
3600  }
3601 
3602  krk_rewindScanner(&state->scanner, outScanner);
3603  state->parser = outParser;
3604 }
3605 
3606 static void complexAssignmentTargets(struct GlobalState * state, KrkScanner oldScanner, Parser oldParser, size_t targetCount, int parenthesized, size_t argBefore, size_t argAfter) {
3607  emitBytes(OP_DUP, 0);
3608 
3609  if (argAfter) {
3610  if (argBefore > 255 || argAfter > 256) {
3611  error("Too many assignment targets");
3612  return;
3613  }
3614  EMIT_OPERAND_OP(OP_UNPACK_EX,((argBefore << 8) | (argAfter-1)));
3615  } else {
3616  EMIT_OPERAND_OP(OP_UNPACK,targetCount);
3617  }
3618  EMIT_OPERAND_OP(OP_REVERSE,targetCount);
3619 
3620  /* Rewind */
3621  krk_rewindScanner(&state->scanner, oldScanner);
3622  state->parser = oldParser;
3623 
3624  /* Parse assignment targets */
3625  size_t checkTargetCount = 0;
3626  int seenStar = 0;
3627  do {
3628  checkTargetCount++;
3629  if (match(TOKEN_ASTERISK)) {
3630  if (seenStar) {
3631  errorAtCurrent("multiple *expr in assignment");
3632  return;
3633  }
3634  seenStar = 1;
3635  }
3636  parsePrecedence(state, PREC_MUST_ASSIGN);
3637  emitByte(OP_POP);
3638 
3639  if (checkTargetCount == targetCount && state->parser.previous.type == TOKEN_COMMA) {
3640  if (!match(parenthesized ? TOKEN_RIGHT_PAREN : TOKEN_EQUAL)) {
3641  goto _errorAtCurrent;
3642  }
3643  }
3644 
3645  if (checkTargetCount == targetCount && parenthesized) {
3646  if (state->parser.previous.type != TOKEN_RIGHT_PAREN) {
3647  goto _errorAtCurrent;
3648  }
3649  }
3650 
3651  if (checkTargetCount == targetCount && parenthesized) {
3652  if (parenthesized == 1 && !match(TOKEN_EQUAL)) {
3653  goto _errorAtCurrent;
3654  }
3655  }
3656 
3657  if (checkTargetCount == targetCount) return;
3658 
3659  if (check(TOKEN_COMMA) || check(TOKEN_EQUAL) || check(TOKEN_RIGHT_PAREN)) {
3660  goto _errorAtCurrent;
3661  }
3662 
3663  } while (state->parser.previous.type != TOKEN_EQUAL && !state->parser.hadError);
3664 
3665 _errorAtCurrent:
3666  errorAtCurrent("Invalid complex assignment target");
3667 }
3668 
3669 static void complexAssignment(struct GlobalState * state, ChunkRecorder before, KrkScanner oldScanner, Parser oldParser, size_t targetCount, int parenthesized, size_t argBefore, size_t argAfter) {
3670 
3671  rewindChunk(currentChunk(), before);
3672  parsePrecedence(state, PREC_ASSIGNMENT);
3673 
3674  /* Store end state */
3675  KrkScanner outScanner = krk_tellScanner(&state->scanner);
3676  Parser outParser = state->parser;
3677 
3678  complexAssignmentTargets(state, oldScanner,oldParser,targetCount,parenthesized, argBefore, argAfter);
3679 
3680  /* Restore end state */
3681  krk_rewindScanner(&state->scanner, outScanner);
3682  state->parser = outParser;
3683 }
3684 
3685 static void comma(struct GlobalState * state, int exprType, RewindState *rewind) {
3686  size_t expressionCount = 1;
3687  size_t argBefore = 0;
3688  size_t argAfter = 0;
3689  do {
3690  if (!getRule(state->parser.current.type)->prefix) break;
3691  if (match(TOKEN_ASTERISK)) {
3692  expressionCount = finishStarComma(state, expressionCount, &argBefore, &argAfter);
3693  goto _maybeassign;
3694  return;
3695  }
3696  expressionCount++;
3697  parsePrecedence(state, PREC_TERNARY);
3698  } while (match(TOKEN_COMMA));
3699 
3700  EMIT_OPERAND_OP(OP_TUPLE,expressionCount);
3701 
3702 _maybeassign: (void)0;
3703  if (exprType == EXPR_CAN_ASSIGN && match(TOKEN_EQUAL)) {
3704  complexAssignment(state, rewind->before, rewind->oldScanner, rewind->oldParser, expressionCount, 0, argBefore, argAfter);
3705  }
3706 }
3707 
3708 static void pstar(struct GlobalState * state, int exprType, RewindState *rewind) {
3709  size_t argBefore = 0;
3710  size_t argAfter = 0;
3711  size_t totalArgs = finishStarComma(state,0, &argBefore, &argAfter);
3712  if (exprType == EXPR_CAN_ASSIGN && match(TOKEN_EQUAL)) {
3713  complexAssignment(state, rewind->before, rewind->oldScanner, rewind->oldParser, totalArgs, 0, argBefore, argAfter);
3714  }
3715 }
3716 
3717 static void call(struct GlobalState * state, int exprType, RewindState *rewind) {
3718  startEatingWhitespace();
3719  size_t argCount = 0, specialArgs = 0, keywordArgs = 0, seenKeywordUnpacking = 0;
3720  if (!check(TOKEN_RIGHT_PAREN)) {
3721  size_t chunkBefore = currentChunk()->count;
3722  KrkScanner scannerBefore = krk_tellScanner(&state->scanner);
3723  Parser parserBefore = state->parser;
3724  do {
3725  if (check(TOKEN_RIGHT_PAREN)) break;
3726  if (match(TOKEN_ASTERISK) || check(TOKEN_POW)) {
3727  specialArgs++;
3728  if (match(TOKEN_POW)) {
3729  seenKeywordUnpacking = 1;
3730  emitBytes(OP_EXPAND_ARGS, 2); /* creates a KWARGS_DICT */
3731  expression(state); /* Expect dict */
3732  continue;
3733  } else {
3734  if (seenKeywordUnpacking) {
3735  error("Iterable expansion follows keyword argument unpacking.");
3736  return;
3737  }
3738  emitBytes(OP_EXPAND_ARGS, 1); /* creates a KWARGS_LIST */
3739  expression(state);
3740  continue;
3741  }
3742  }
3743  if (match(TOKEN_IDENTIFIER)) {
3744  KrkToken argName = state->parser.previous;
3745  if (check(TOKEN_EQUAL)) {
3746  /* This is a keyword argument. */
3747  advance();
3748  /* Output the name */
3749  size_t ind = identifierConstant(state, &argName);
3750  EMIT_OPERAND_OP(OP_CONSTANT, ind);
3751  expression(state);
3752  keywordArgs++;
3753  specialArgs++;
3754  continue;
3755  } else {
3756  /*
3757  * This is a regular argument that happened to start with an identifier,
3758  * roll it back so we can process it that way.
3759  */
3760  krk_ungetToken(&state->scanner, state->parser.current);
3761  state->parser.current = argName;
3762  }
3763  } else if (seenKeywordUnpacking) {
3764  error("Positional argument follows keyword argument unpacking");
3765  return;
3766  } else if (keywordArgs) {
3767  error("Positional argument follows keyword argument");
3768  return;
3769  }
3770  if (specialArgs) {
3771  emitBytes(OP_EXPAND_ARGS, 0); /* creates a KWARGS_SINGLE */
3772  expression(state);
3773  specialArgs++;
3774  continue;
3775  }
3776  expression(state);
3777  if (argCount == 0 && match(TOKEN_FOR)) {
3778  currentChunk()->count = chunkBefore;
3779  generatorExpression(state, scannerBefore, parserBefore, yieldInner);
3780  argCount = 1;
3781  if (match(TOKEN_COMMA)) {
3782  error("Generator expression must be parenthesized");
3783  return;
3784  }
3785  break;
3786  }
3787  argCount++;
3788  } while (match(TOKEN_COMMA));
3789  }
3790  stopEatingWhitespace();
3791  consume(TOKEN_RIGHT_PAREN, "Expected ')' after arguments.");
3792  if (specialArgs) {
3793  /*
3794  * Creates a sentinel at the top of the stack to tell the CALL instruction
3795  * how many keyword arguments are at the top of the stack. This value
3796  * triggers special handling in the CALL that processes the keyword arguments,
3797  * which is relatively slow, so only use keyword arguments if you have to!
3798  */
3799  EMIT_OPERAND_OP(OP_KWARGS, specialArgs);
3800  /*
3801  * We added two elements - name and value - for each keyword arg,
3802  * plus the sentinel object that will show up at the end after the
3803  * OP_KWARGS instruction complets, so make sure we have the
3804  * right depth into the stack when we execute CALL
3805  */
3806  argCount += 1 /* for the sentinel */ + 2 * specialArgs;
3807  }
3808 
3809  if (exprType == EXPR_METHOD_CALL) {
3810  EMIT_OPERAND_OP(OP_CALL_METHOD, argCount);
3811  } else if (exprType == EXPR_CLASS_PARAMETERS) {
3812  EMIT_OPERAND_OP(OP_CALL, (argCount + 2));
3813  } else {
3814  EMIT_OPERAND_OP(OP_CALL, argCount);
3815  }
3816 
3817  invalidTarget(state, exprType, "function call");
3818 }
3819 
3820 static void and_(struct GlobalState * state, int exprType, RewindState *rewind) {
3821  int endJump = emitJump(OP_JUMP_IF_FALSE_OR_POP);
3822  parsePrecedence(state, PREC_AND);
3823  patchJump(endJump);
3824  invalidTarget(state, exprType, "operator");
3825 }
3826 
3827 static void or_(struct GlobalState * state, int exprType, RewindState *rewind) {
3828  int endJump = emitJump(OP_JUMP_IF_TRUE_OR_POP);
3829  parsePrecedence(state, PREC_OR);
3830  patchJump(endJump);
3831  invalidTarget(state, exprType, "operator");
3832 }
3833 
3834 static void parsePrecedence(struct GlobalState * state, Precedence precedence) {
3835  RewindState rewind = {recordChunk(currentChunk()), krk_tellScanner(&state->scanner), state->parser};
3836 
3837  advance();
3838  ParseFn prefixRule = getRule(state->parser.previous.type)->prefix;
3839 
3840  /* Only allow *expr parsing where we would allow comma expressions,
3841  * otherwise pretend this prefix rule doesn't exist. */
3842  if (prefixRule == pstar && precedence > PREC_COMMA) prefixRule = NULL;
3843 
3844  if (prefixRule == NULL) {
3845  switch (state->parser.previous.type) {
3846  case TOKEN_RIGHT_BRACE:
3847  case TOKEN_RIGHT_PAREN:
3848  case TOKEN_RIGHT_SQUARE:
3849  error("Unmatched '%.*s'",
3850  (int)state->parser.previous.length, state->parser.previous.start);
3851  break;
3852  case TOKEN_EOL:
3853  /* TODO: This should definitely be tripping the REPL to ask for more input. */
3854  error("Unexpected end of line");
3855  break;
3856  case TOKEN_EOF:
3857  error("Unexpected end of input");
3858  break;
3859  default:
3860  error("'%.*s' does not start an expression",
3861  (int)state->parser.previous.length, state->parser.previous.start);
3862  }
3863  return;
3864  }
3865  int exprType = 0;
3866  if (precedence <= PREC_ASSIGNMENT || precedence == PREC_CAN_ASSIGN) exprType = EXPR_CAN_ASSIGN;
3867  if (precedence == PREC_MUST_ASSIGN) exprType = EXPR_ASSIGN_TARGET;
3868  if (precedence == PREC_DEL_TARGET) exprType = EXPR_DEL_TARGET;
3869  prefixRule(state, exprType, &rewind);
3870  while (precedence <= getRule(state->parser.current.type)->precedence) {
3871  if (state->parser.hadError) {
3872  skipToEnd();
3873  return;
3874  }
3875 
3876  if (exprType == EXPR_ASSIGN_TARGET && (state->parser.previous.type == TOKEN_COMMA ||
3877  state->parser.previous.type == TOKEN_EQUAL)) break;
3878  advance();
3879  ParseFn infixRule = getRule(state->parser.previous.type)->infix;
3880  infixRule(state, exprType, &rewind);
3881  }
3882 
3883  if (exprType == EXPR_CAN_ASSIGN && matchAssignment(state)) {
3884  error("Invalid assignment target");
3885  }
3886 }
3887 
3888 
3889 static int maybeSingleExpression(struct GlobalState * state) {
3890  /* We're only going to use this to reset if we found a string, and it turns out
3891  * not to be a docstring. */
3892  RewindState rewind = {recordChunk(currentChunk()), krk_tellScanner(&state->scanner), state->parser};
3893 
3901  if (check(TOKEN_STRING) || check(TOKEN_BIG_STRING)) {
3902  advance();
3903  if (match(TOKEN_EOL)) {
3904  /* We found just a string on the first line, but is it the only line?
3905  * We should treat that as a regular string expression, eg. in a repl. */
3906  int isEof = check(TOKEN_EOF);
3907  /* Regardless, restore the scanner/parser so we can actually parse the string. */
3908  krk_rewindScanner(&state->scanner, rewind.oldScanner);
3909  state->parser = rewind.oldParser;
3910  advance();
3911  /* Parse the string. */
3912  string(state, EXPR_NORMAL, NULL);
3913  /* If we did see end of input, it's a simple string expression. */
3914  if (isEof) return 1;
3915  /* Otherwise, it's a docstring, and there's more code following it.
3916  * Emit the instructions to assign the docstring to the current globals. */
3917  KrkToken doc = syntheticToken("__doc__");
3918  size_t ind = identifierConstant(state, &doc);
3919  EMIT_OPERAND_OP(OP_DEFINE_GLOBAL, ind);
3920  return 0;
3921  } else {
3922  /* There was something other than a line feed after the string token,
3923  * rewind so we can parse as an expression next. */
3924  krk_rewindScanner(&state->scanner, rewind.oldScanner);
3925  state->parser = rewind.oldParser;
3926  }
3927  }
3928 
3929  /* Try to parse one single expression */
3930  ParseRule * rule = getRule(state->parser.current.type);
3931  if (rule->prefix) {
3932  parsePrecedence(state, PREC_ASSIGNMENT);
3933 
3934  /* Semicolon after expression statement, finish this one and continue
3935  * parsing only more simple statements, as we would normally. */
3936  if (match(TOKEN_SEMICOLON)) {
3937  emitByte(OP_POP);
3938  simpleStatement(state);
3939  return 0;
3940  }
3941 
3942  /* Expression statement that isn't the end of the input, finish it
3943  * and let the declaration loop handle the rest. */
3944  if (match(TOKEN_EOL) && !check(TOKEN_EOF)) {
3945  emitByte(OP_POP);
3946  return 0;
3947  }
3948 
3949  /* End of input after expression, must be just the single expression;
3950  * using check rather than match makes the return emit on the same
3951  * line, which produces cleaner disassembly when -d tracing is enabled. */
3952  if (check(TOKEN_EOF))
3953  return 1;
3954 
3955  /* Must be an error. */
3956  errorAfterStatement(state);
3957  return 0;
3958  }
3959 
3960  return 0;
3961 }
3962 
3963 _noexport
3964 void _createAndBind_compilerClass(void) {
3965  KrkClass * CompilerState = ADD_BASE_CLASS(KRK_BASE_CLASS(CompilerState), "CompilerState", KRK_BASE_CLASS(object));
3966  CompilerState->allocSize = sizeof(struct GlobalState);
3967  CompilerState->_ongcscan = _GlobalState_gcscan;
3968  CompilerState->_ongcsweep = _GlobalState_gcsweep;
3969  CompilerState->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
3970  krk_finalizeClass(CompilerState);
3971 }
3972 
3986 KrkCodeObject * krk_compile(const char * src, char * fileName) {
3987  struct GlobalState * state = (void*)krk_newInstance(KRK_BASE_CLASS(CompilerState));
3988  krk_push(OBJECT_VAL(state));
3989 
3990  /* Point a new scanner at the source. */
3991  state->scanner = krk_initScanner(src);
3992 
3993  /* Reset parser state. */
3994  memset(&state->parser, 0, sizeof(state->parser));
3995 
3996  /* Start compiling a new function. */
3997  Compiler compiler;
3998  initCompiler(state, &compiler, TYPE_MODULE);
3999  compiler.codeobject->chunk.filename = krk_copyString(fileName, strlen(fileName));
4000  compiler.codeobject->name = krk_copyString("<module>",8);
4001 
4002  /* Start reading tokens from the scanner... */
4003  advance();
4004 
4005  /* The first line of an input may be a doc string. */
4006  if (maybeSingleExpression(state)) {
4007  state->current->type = TYPE_LAMBDA;
4008  } else {
4009  /* Parse top-level declarations... */
4010  while (!match(TOKEN_EOF)) {
4011  declaration(state);
4012 
4013  /* Skip over redundant whitespace */
4014  if (check(TOKEN_EOL) || check(TOKEN_INDENTATION) || check(TOKEN_EOF)) {
4015  advance();
4016  }
4017  }
4018  }
4019 
4020  KrkCodeObject * function = endCompiler(state);
4021  freeCompiler(&compiler);
4022 
4023  /*
4024  * We'll always get something out of endCompiler even if it
4025  * wasn't fully compiled, so be sure to check for a syntax
4026  * error and return NULL
4027  */
4028  if (state->parser.hadError) function = NULL;
4029 
4030  krk_pop();
4031  return function;
4032 }
4033 
4034 #define RULE(token, a, b, c) [TOKEN_ ## token] = {a, b, c}
4035 
4047  RULE(DOT, NULL, dot, PREC_PRIMARY),
4048  RULE(LEFT_PAREN, parens, call, PREC_PRIMARY),
4049  RULE(LEFT_SQUARE, list, getitem, PREC_PRIMARY),
4050  RULE(LEFT_BRACE, dict, NULL, PREC_NONE),
4051  RULE(RIGHT_PAREN, NULL, NULL, PREC_NONE),
4052  RULE(RIGHT_SQUARE, NULL, NULL, PREC_NONE),
4053  RULE(RIGHT_BRACE, NULL, NULL, PREC_NONE),
4054  RULE(COLON, NULL, NULL, PREC_NONE),
4055  RULE(SEMICOLON, NULL, NULL, PREC_NONE),
4056  RULE(EQUAL, NULL, NULL, PREC_NONE),
4057  RULE(WALRUS, NULL, NULL, PREC_NONE),
4058  RULE(PLUS_EQUAL, NULL, NULL, PREC_NONE),
4059  RULE(MINUS_EQUAL, NULL, NULL, PREC_NONE),
4060  RULE(PLUS_PLUS, NULL, NULL, PREC_NONE),
4061  RULE(MINUS_MINUS, NULL, NULL, PREC_NONE),
4062  RULE(CARET_EQUAL, NULL, NULL, PREC_NONE),
4063  RULE(PIPE_EQUAL, NULL, NULL, PREC_NONE),
4064  RULE(LSHIFT_EQUAL, NULL, NULL, PREC_NONE),
4065  RULE(RSHIFT_EQUAL, NULL, NULL, PREC_NONE),
4066  RULE(AMP_EQUAL, NULL, NULL, PREC_NONE),
4067  RULE(SOLIDUS_EQUAL, NULL, NULL, PREC_NONE),
4068  RULE(DSOLIDUS_EQUAL,NULL, NULL, PREC_NONE),
4069  RULE(ASTERISK_EQUAL,NULL, NULL, PREC_NONE),
4070  RULE(MODULO_EQUAL, NULL, NULL, PREC_NONE),
4071  RULE(AT_EQUAL, NULL, NULL, PREC_NONE),
4072  RULE(POW_EQUAL, NULL, NULL, PREC_NONE),
4073  RULE(ARROW, NULL, NULL, PREC_NONE),
4074  RULE(MINUS, unary, binary, PREC_SUM),
4075  RULE(PLUS, unary, binary, PREC_SUM),
4076  RULE(TILDE, unary, NULL, PREC_NONE),
4077  RULE(BANG, unary, NULL, PREC_NONE),
4078  RULE(SOLIDUS, NULL, binary, PREC_TERM),
4079  RULE(DOUBLE_SOLIDUS,NULL, binary, PREC_TERM),
4080  RULE(ASTERISK, pstar, binary, PREC_TERM),
4081  RULE(MODULO, NULL, binary, PREC_TERM),
4082  RULE(AT, NULL, binary, PREC_TERM),
4083  RULE(POW, NULL, binary, PREC_EXPONENT),
4084  RULE(PIPE, NULL, binary, PREC_BITOR),
4085  RULE(CARET, NULL, binary, PREC_BITXOR),
4086  RULE(AMPERSAND, NULL, binary, PREC_BITAND),
4087  RULE(LEFT_SHIFT, NULL, binary, PREC_SHIFT),
4088  RULE(RIGHT_SHIFT, NULL, binary, PREC_SHIFT),
4089  RULE(BANG_EQUAL, NULL, compare, PREC_COMPARISON),
4090  RULE(EQUAL_EQUAL, NULL, compare, PREC_COMPARISON),
4091  RULE(GREATER, NULL, compare, PREC_COMPARISON),
4092  RULE(GREATER_EQUAL, NULL, compare, PREC_COMPARISON),
4093  RULE(LESS, NULL, compare, PREC_COMPARISON),
4094  RULE(LESS_EQUAL, NULL, compare, PREC_COMPARISON),
4095  RULE(IN, NULL, compare, PREC_COMPARISON),
4096  RULE(IS, NULL, compare, PREC_COMPARISON),
4097  RULE(NOT, unot_, compare, PREC_COMPARISON),
4098  RULE(IDENTIFIER, variable, NULL, PREC_NONE),
4099  RULE(STRING, string, NULL, PREC_NONE),
4100  RULE(BIG_STRING, string, NULL, PREC_NONE),
4101  RULE(PREFIX_B, string, NULL, PREC_NONE),
4102  RULE(PREFIX_F, string, NULL, PREC_NONE),
4103  RULE(PREFIX_R, string, NULL, PREC_NONE),
4104  RULE(NUMBER, number, NULL, PREC_NONE),
4105  RULE(AND, NULL, and_, PREC_AND),
4106  RULE(OR, NULL, or_, PREC_OR),
4107  RULE(FALSE, literal, NULL, PREC_NONE),
4108  RULE(NONE, literal, NULL, PREC_NONE),
4109  RULE(TRUE, literal, NULL, PREC_NONE),
4110  RULE(YIELD, yield, NULL, PREC_NONE),
4111  RULE(AWAIT, await, NULL, PREC_NONE),
4112  RULE(LAMBDA, lambda, NULL, PREC_NONE),
4113  RULE(SUPER, super_, NULL, PREC_NONE),
4114  RULE(CLASS, NULL, NULL, PREC_NONE),
4115  RULE(ELSE, NULL, NULL, PREC_NONE),
4116  RULE(FOR, NULL, NULL, PREC_NONE),
4117  RULE(DEF, NULL, NULL, PREC_NONE),
4118  RULE(DEL, NULL, NULL, PREC_NONE),
4119  RULE(LET, NULL, NULL, PREC_NONE),
4120  RULE(RETURN, NULL, NULL, PREC_NONE),
4121  RULE(WHILE, NULL, NULL, PREC_NONE),
4122  RULE(BREAK, NULL, NULL, PREC_NONE),
4123  RULE(CONTINUE, NULL, NULL, PREC_NONE),
4124  RULE(IMPORT, NULL, NULL, PREC_NONE),
4125  RULE(RAISE, NULL, NULL, PREC_NONE),
4126  RULE(ASYNC, NULL, NULL, PREC_NONE),
4127  RULE(PASS, NULL, NULL, PREC_NONE),
4128  RULE(ASSERT, NULL, NULL, PREC_NONE),
4129  RULE(FINALLY, NULL, NULL, PREC_NONE),
4130  RULE(ELIF, NULL, NULL, PREC_NONE),
4131  RULE(TRY, NULL, NULL, PREC_NONE),
4132  RULE(EXCEPT, NULL, NULL, PREC_NONE),
4133  RULE(AS, NULL, NULL, PREC_NONE),
4134  RULE(FROM, NULL, NULL, PREC_NONE),
4135  RULE(WITH, NULL, NULL, PREC_NONE),
4136 
4137  RULE(COMMA, NULL, comma, PREC_COMMA),
4138  RULE(IF, NULL, ternary, PREC_TERNARY),
4139 
4140  RULE(INDENTATION, NULL, NULL, PREC_NONE),
4141  RULE(ERROR, NULL, NULL, PREC_NONE),
4142  RULE(EOL, NULL, NULL, PREC_NONE),
4143  RULE(EOF, NULL, NULL, PREC_NONE),
4144  RULE(RETRY, NULL, NULL, PREC_NONE),
4145 };
4146 
4147 static ParseRule * getRule(KrkTokenType type) {
4148  return &krk_parseRules[type];
4149 }
4150 
ParseRule krk_parseRules[]
Parse rules table.
Definition: compiler.c:4046
FunctionType
Function compilation type.
Definition: compiler.c:160
@ TYPE_COROUTINE_METHOD
Definition: compiler.c:170
@ TYPE_INIT
Definition: compiler.c:164
@ TYPE_COROUTINE
Definition: compiler.c:169
@ TYPE_MODULE
Definition: compiler.c:162
@ TYPE_STATIC
Definition: compiler.c:166
@ TYPE_CLASSMETHOD
Definition: compiler.c:168
@ TYPE_LAMBDA
Definition: compiler.c:165
@ TYPE_METHOD
Definition: compiler.c:163
@ TYPE_CLASS
Definition: compiler.c:167
@ TYPE_FUNCTION
Definition: compiler.c:161
ExpressionType
Expression type.
Definition: compiler.c:97
@ EXPR_METHOD_CALL
Definition: compiler.c:102
@ EXPR_NORMAL
Definition: compiler.c:98
@ EXPR_ASSIGN_TARGET
Definition: compiler.c:100
@ EXPR_DEL_TARGET
Definition: compiler.c:101
@ EXPR_CAN_ASSIGN
Definition: compiler.c:99
struct Compiler Compiler
Subcompiler state.
struct RewindState RewindState
Compiler emit and parse state prior to this expression.
Precedence
Parse precedence ladder.
Definition: compiler.c:69
@ PREC_TERNARY
Definition: compiler.c:76
@ PREC_CAN_ASSIGN
Definition: compiler.c:74
@ PREC_BITXOR
Definition: compiler.c:82
@ PREC_SUM
Definition: compiler.c:85
@ PREC_DEL_TARGET
Definition: compiler.c:75
@ PREC_SHIFT
Definition: compiler.c:84
@ PREC_OR
Definition: compiler.c:77
@ PREC_FACTOR
Definition: compiler.c:87
@ PREC_ASSIGNMENT
Definition: compiler.c:71
@ PREC_PRIMARY
Definition: compiler.c:89
@ PREC_EXPONENT
Definition: compiler.c:88
@ PREC_MUST_ASSIGN
Definition: compiler.c:73
@ PREC_COMPARISON
Definition: compiler.c:80
@ PREC_COMMA
Definition: compiler.c:72
@ PREC_NOT
Definition: compiler.c:79
@ PREC_BITOR
Definition: compiler.c:81
@ PREC_BITAND
Definition: compiler.c:83
@ PREC_TERM
Definition: compiler.c:86
@ PREC_AND
Definition: compiler.c:78
struct ClassCompiler ClassCompiler
Class compilation context.
KrkCodeObject * krk_compile(const char *src, char *fileName)
Compile a source string to bytecode.
Definition: compiler.c:3986
void(* ParseFn)(struct GlobalState *, int, struct RewindState *)
Subexpression parser function.
Definition: compiler.c:116
struct ChunkRecorder ChunkRecorder
Bytecode emitter backtracking breadcrumb.
Exported methods for the source compiler.
Functions for debugging bytecode execution.
void krk_disassembleCodeObject(FILE *f, KrkCodeObject *func, const char *name)
Print a disassembly of 'func' to the stream 'f'.
Definition: debug.c:60
Top-level header with configuration macros.
Functions for dealing with garbage collection and memory allocation.
void krk_markObject(KrkObj *object)
During a GC scan cycle, mark an object as used.
Definition: memory.c:316
Struct definitions for core object types.
Internal header.
Definitions used by the token scanner.
void krk_ungetToken(KrkScanner *, KrkToken token)
Push a token back to the scanner to be reprocessed.
Definition: scanner.c:278
KrkToken krk_scanToken(KrkScanner *)
Read the next token from the scanner.
Definition: scanner.c:294
KrkScanner krk_initScanner(const char *src)
Initialize the compiler to scan tokens from 'src'.
Definition: scanner.c:10
KrkScanner krk_tellScanner(KrkScanner *)
Retreive a copy of the current scanner state.
Definition: scanner.c:286
void krk_rewindScanner(KrkScanner *, KrkScanner to)
Rewind the scanner to a previous state.
Definition: scanner.c:290
Bytecode emitter backtracking breadcrumb.
Definition: compiler.c:258
size_t count
Offset into the bytecode.
Definition: compiler.c:259
size_t constants
Number of constants in the constants table.
Definition: compiler.c:261
size_t lines
Offset into the line map.
Definition: compiler.c:260
Class compilation context.
Definition: compiler.c:240
struct ClassCompiler * enclosing
Enclosing class scope.
Definition: compiler.c:241
int hasAnnotations
Flag indicating if an annotation dictionary has been attached to this class.
Definition: compiler.c:243
KrkToken name
Name of the current class.
Definition: compiler.c:242
Subcompiler state.
Definition: compiler.c:199
size_t continueCount
Number of continue statements.
Definition: compiler.c:214
size_t localNameCapacity
How much space is available in the codeobject's local names table.
Definition: compiler.c:218
struct IndexWithNext * properties
Linked list of class property constant indices.
Definition: compiler.c:220
FunctionType type
Type of function being compiled.
Definition: compiler.c:202
size_t continueSpace
Space in continues array.
Definition: compiler.c:215
size_t optionsFlags
Special options imports; similar to future in Python.
Definition: compiler.c:226
size_t localsSpace
Space in the locals array.
Definition: compiler.c:205
int delSatisfied
Flag indicating if a 'del' target has been completed.
Definition: compiler.c:224
struct Compiler * enclosed
Subcompiler we are enclosing, need for type annotation compilation.
Definition: compiler.c:221
size_t loopLocalCount
Tracks how many locals to pop off the stack when exiting a loop.
Definition: compiler.c:210
size_t localCount
Total number of local variables.
Definition: compiler.c:204
size_t scopeDepth
Depth of nested scope blocks.
Definition: compiler.c:203
size_t breakSpace
Space in breaks array.
Definition: compiler.c:212
size_t upvaluesSpace
Space in the upvalues array.
Definition: compiler.c:207
Local * locals
Array of local variable references.
Definition: compiler.c:206
struct LoopExit * continues
Array of loop exit instruction indices for continue statements.
Definition: compiler.c:216
struct LoopExit * breaks
Array of loop exit instruction indices for break statements.
Definition: compiler.c:213
size_t annotationCount
Number of type annotations found while compiling function signature.
Definition: compiler.c:222
KrkCodeObject * codeobject
Bytecode emitter.
Definition: compiler.c:201
size_t breakCount
Number of break statements.
Definition: compiler.c:211
struct Compiler * enclosing
Enclosing function compiler, or NULL for a module.
Definition: compiler.c:200
Upvalue * upvalues
Array of upvalue references. Count is stored in the codeobject.
Definition: compiler.c:208
int unnamedArgs
Number of positional arguments that will not be assignable through keywords.
Definition: compiler.c:227
KrkScanner scanner
Scanner state.
Definition: compiler.c:278
Parser parser
Parser state.
Definition: compiler.c:277
ClassCompiler * currentClass
Current in-progress class definition (or NULL)
Definition: compiler.c:280
Compiler * current
Current compiler (in-progress code object) state.
Definition: compiler.c:279
KrkInstance inst
Base instance.
Definition: compiler.c:276
Linked list of indices.
Definition: compiler.c:180
size_t ind
Index of an identifier constant.
Definition: compiler.c:181
struct IndexWithNext * next
Linked list next pointer.
Definition: compiler.c:182
Opcode chunk of a code object.
Definition: chunk.h:36
size_t krk_writeConstant(KrkChunk *chunk, KrkValue value, size_t line)
Add a new constant and write an instruction for it.
Definition: chunk.c:68
size_t krk_addConstant(KrkChunk *chunk, KrkValue value)
Add a new constant value to an opcode chunk.
Definition: chunk.c:49
void krk_writeChunk(KrkChunk *chunk, uint8_t byte, size_t line)
Append a byte to an opcode chunk.
Definition: chunk.c:30
Type object.
Definition: object.h:189
KrkCleanupCallback _ongcsweep
C function to call when the garbage collector is discarding an instance of this class.
Definition: object.h:198
KrkCleanupCallback _ongcscan
C function to call when the garbage collector visits an instance of this class in the scan phase.
Definition: object.h:197
size_t allocSize
Size to allocate when creating instances of this class.
Definition: object.h:196
KrkObj obj
Base.
Definition: object.h:190
void krk_finalizeClass(KrkClass *_class)
Finalize a class by collecting pointers to core methods.
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
size_t upvalueCount
Number of upvalues this function collects as a closure.
Definition: object.h:150
KrkLocalEntry * localNames
Stores the names of local variables used in the function, for debugging.
Definition: object.h:158
unsigned short keywordArgs
Arity of keyword (default) arguments.
Definition: object.h:147
unsigned short requiredArgs
Arity of required (non-default) arguments.
Definition: object.h:146
KrkString * docstring
Docstring attached to the function.
Definition: object.h:153
KrkObj obj
Base.
Definition: object.h:145
KrkCodeObject * krk_newCodeObject(void)
Create a new, uninitialized code object.
Definition: object.c:261
size_t localNameCount
Number of entries in localNames.
Definition: object.h:157
KrkString * name
Name of the function.
Definition: object.h:152
KrkString * qualname
The dotted name of the function.
Definition: object.h:159
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
Metadata on a local variable name in a function.
Definition: object.h:129
size_t birthday
Instruction offset that this local name became valid on.
Definition: object.h:131
KrkString * name
Name of the local.
Definition: object.h:133
size_t id
Local ID as used by opcodes; offset from the frame's stack base.
Definition: object.h:130
size_t deathday
Instruction offset that this local name becomes invalid on.
Definition: object.h:132
The most basic object type.
Definition: object.h:41
uint16_t flags
General object flags, mostly related to garbage collection.
Definition: object.h:43
Token scanner state.
Definition: scanner.h:138
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
char * chars
UTF8 canonical data.
Definition: object.h:97
size_t length
String length in bytes.
Definition: object.h:95
size_t krk_codepointToBytes(krk_integer_type value, unsigned char *out)
Convert an integer codepoint to a UTF-8 byte representation.
Definition: object.c:37
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
void krk_attachNamedValue(KrkTable *table, const char name[], KrkValue obj)
Attach a value to an attribute table.
Definition: vm.c:825
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:189
KrkValue currentException
Definition: vm.h:173
int flags
Definition: vm.h:174
KrkInstance * module
Definition: vm.h:172
A token from the scanner.
Definition: scanner.h:122
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.
Local variable reference.
Definition: compiler.c:137
KrkToken name
Token that provided the name for this variable.
Definition: compiler.c:138
ssize_t depth
Stack depth, or -1 if uninitialized.
Definition: compiler.c:139
char isCaptured
Flag indicating if the variable is captured by a closure.
Definition: compiler.c:140
Tracks 'break' and 'continue' statements.
Definition: compiler.c:188
KrkToken token
Token for this exit statement, so its location can be printed in an error message.
Definition: compiler.c:190
int offset
Offset of the jump expression to patch.
Definition: compiler.c:189
Parse rule table entry.
Definition: compiler.c:124
ParseFn infix
Parse function to call when this token appears after an expression.
Definition: compiler.c:126
Precedence precedence
Precedence ordering for Pratt parsing, Precedence.
Definition: compiler.c:127
ParseFn prefix
Parse function to call when this token appears at the start of an expression.
Definition: compiler.c:125
Token parser state.
Definition: compiler.c:56
KrkToken previous
Last token matched, consumed, or advanced over.
Definition: compiler.c:58
KrkToken current
Token to be parsed.
Definition: compiler.c:57
unsigned int eatingWhitespace
Depth of whitespace-ignoring parse functions.
Definition: compiler.c:60
char hadError
Flag indicating if the parser encountered an error.
Definition: compiler.c:59
Compiler emit and parse state prior to this expression.
Definition: compiler.c:269
ChunkRecorder before
Bytecode and constant table output offsets.
Definition: compiler.c:270
Parser oldParser
Previous/current tokens.
Definition: compiler.c:272
KrkScanner oldScanner
Scanner cursor state.
Definition: compiler.c:271
Inline flexible string array.
Definition: util.h:150
Closure upvalue reference.
Definition: compiler.c:148
char isLocal
Flag indicating if Kuroko Language Reference is a local or upvalue index.
Definition: compiler.c:150
KrkToken name
Name for direct lookup. Mainly for non-automatically-populated upvalue cells.
Definition: compiler.c:151
size_t index
Enclosing local index or upvalue index.
Definition: compiler.c:149
Utilities for creating native bindings.
void krk_pushStringBuilderStr(struct StringBuilder *sb, const char *str, size_t len)
Append a string to the end of a string builder.
Definition: obj_str.c:1059
KrkValue krk_finishStringBuilderBytes(struct StringBuilder *sb)
Finalize a string builder in a bytes object.
Definition: obj_str.c:1085
KrkValue krk_discardStringBuilder(struct StringBuilder *sb)
Discard the contents of a string builder.
Definition: obj_str.c:1091
KrkValue krk_finishStringBuilder(struct StringBuilder *sb)
Finalize a string builder into a string object.
Definition: obj_str.c:1079
void krk_pushStringBuilder(struct StringBuilder *sb, char c)
Add a character to the end of a string builder.
Definition: obj_str.c:1050
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