10 #include "opcode_enum.h"
12 #ifndef KRK_DISABLE_DEBUG
26 fprintf(file,
"[%c", frame->
slots == i ?
'*' :
' ');
31 size_t relative = i - f->
slots;
53 if (i == frame->
slots) {
63 fprintf(f,
"<%s(", name);
70 if (func->
obj.
flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) {
80 if (func->
obj.
flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS) {
83 fprintf(f,
") from %s>\n", chunk->filename->
chars);
84 for (
size_t offset = 0; offset < chunk->count;) {
89 static inline const char * opcodeClean(
const char * opc) {
93 static int isJumpTarget(
KrkCodeObject * func,
size_t startPoint) {
97 #define SIMPLE(opc) case opc: size = 1; break;
98 #define CONSTANT(opc,more) case opc: { size_t constant __attribute__((unused)) = chunk->code[offset + 1]; size = 2; more; break; } \
99 case opc ## _LONG: { size_t constant __attribute__((unused)) = (chunk->code[offset + 1] << 16) | \
100 (chunk->code[offset + 2] << 8) | (chunk->code[offset + 3]); size = 4; more; break; }
101 #define OPERANDB(opc,more) case opc: { size = 2; more; break; }
102 #define OPERAND(opc,more) OPERANDB(opc,more) \
103 case opc ## _LONG: { size = 4; more; break; }
104 #define JUMP(opc,sign) case opc: { uint16_t jump = (chunk->code[offset + 1] << 8) | (chunk->code[offset + 2]); \
105 if ((size_t)(offset + 3 sign jump) == startPoint) return 1; \
107 #define CLOSURE_MORE \
108 KrkCodeObject * function = AS_codeobject(chunk->constants.values[constant]); \
109 for (size_t j = 0; j < function->upvalueCount; ++j) { \
110 int isLocal = chunk->code[offset++ + size]; \
116 #define EXPAND_ARGS_MORE
118 #define FORMAT_VALUE_MORE
120 while (offset < chunk->count) {
121 uint8_t opcode = chunk->code[offset];
136 #undef EXPAND_ARGS_MORE
137 #undef FORMAT_VALUE_MORE
140 #define OPARGS FILE * f, const char * fullName, size_t * size, size_t * offset, KrkCodeObject * func, KrkChunk * chunk
141 #define OPARG_VALS f,fullName,size,offset,func,chunk
143 static void _print_opcode(OPARGS) {
144 fprintf(f,
"%-16s ", opcodeClean(fullName));
147 static void _simple(OPARGS) {
148 _print_opcode(OPARG_VALS);
153 static void _constant(OPARGS,
int isLong,
void (*more)(OPARGS,
size_t constant)) {
154 _print_opcode(OPARG_VALS);
155 size_t constant = isLong ? (chunk->code[*offset + 1] << 16) | (chunk->code[*offset + 2] << 8) | (chunk->code[*offset + 3]) : chunk->code[*offset + 1];
156 fprintf(f,
"%4d ", (
int)constant);
158 *size = isLong ? 4 : 2;
159 if (more) more(OPARG_VALS, constant);
162 static void _operand(OPARGS,
int isLong,
void (*more)(OPARGS,
size_t constant)) {
163 _print_opcode(OPARG_VALS);
164 uint32_t operand = isLong ? (chunk->code[*offset + 1] << 16) | (chunk->code[*offset + 2] << 8) | (chunk->code[*offset + 3]) : chunk->code[*offset + 1];
165 fprintf(f,
"%4d", (
int)operand);
166 *size = isLong ? 4 : 2;
167 if (more) more(OPARG_VALS, operand);
170 static void _jump(OPARGS,
int sign) {
171 _print_opcode(OPARG_VALS);
172 uint16_t jump = (chunk->code[*offset + 1] << 8) | (chunk->code[*offset + 2]);
173 fprintf(f,
"%4d (to %d)", (
int)jump, (
int)(*offset + 3 + sign * jump));
179 #define SIMPLE(opc) case opc: _simple(f,#opc,&size,&offset,func,chunk); break;
180 #define CONSTANT(opc,more) case opc: _constant(f,#opc,&size,&offset,func,chunk,0,more); break; \
181 case opc ## _LONG: _constant(f,#opc "_LONG",&size,&offset,func,chunk,1,more); break;
182 #define OPERAND(opc,more) case opc: _operand(f,#opc,&size,&offset,func,chunk,0,more); break; \
183 case opc ## _LONG: _operand(f,#opc "_LONG",&size,&offset,func,chunk,1,more); break;
184 #define JUMP(opc,sign) case opc: _jump(f,#opc,&size,&offset,func,chunk,sign 1); break;
186 #define CLOSURE_MORE _closure_more
188 static void _closure_more(OPARGS,
size_t constant) {
191 for (
size_t j = 0; j <
function->upvalueCount; ++j) {
192 int isLocal = chunk->code[(*offset)++ + *size];
193 int index = chunk->code[(*offset)++ + *size];
195 index = (index << 16) | (chunk->code[*offset + *size] << 8) | chunk->code[*offset + 1 + *size];
205 }
else if (isLocal & 4) {
206 fprintf(f,
"classcell");
207 }
else { fprintf(f,
"upvalue<%d>", index); }
208 if (j + 1 != function->upvalueCount) fprintf(f,
", ");
212 #define EXPAND_ARGS_MORE _expand_args_more
214 static void _expand_args_more(OPARGS,
size_t operand) {
215 fprintf(f,
" (%s)", operand == 0 ?
"singleton" : (operand == 1 ?
"list" :
"dict"));
218 #define FORMAT_VALUE_MORE _format_value_more
220 static void _format_value_more(OPARGS,
size_t operand) {
224 if (operand & FORMAT_OP_EQ) { fprintf(f,
"eq"); hasThing = 1; }
225 if (operand & FORMAT_OP_STR) { fprintf(f,
"%sstr", hasThing ?
", " :
""); hasThing = 1; }
226 if (operand & FORMAT_OP_REPR) { fprintf(f,
"%srepr", hasThing ?
", " :
""); hasThing = 1; }
227 if (operand & FORMAT_OP_FORMAT) { fprintf(f,
"%swith format", hasThing ?
", " :
""); }
232 #define LOCAL_MORE _local_more
233 static void _local_more(OPARGS,
size_t operand) {
237 if ((
short int) operand < func->potentialPositionals) {
239 }
else if ((
short int)operand < func->potentialPositionals + func->
keywordArgs + !!(func->
obj.
flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS)) {
240 fprintf(f,
", kwarg");
253 if (offset > 0) fprintf(f,
"\n");
256 if (isJumpTarget(func,offset)) {
261 fprintf(f,
"%4u ", (
unsigned int)offset);
262 uint8_t opcode = chunk->code[offset];
268 fprintf(f,
"Unknown opcode: %02x", opcode);
287 return offset + size;
296 #undef EXPAND_ARGS_MORE
297 #undef FORMAT_VALUE_MORE
304 uint8_t originalOpcode;
307 #define MAX_BREAKPOINTS 32
309 int breakpointsCount;
316 int repeatStack_bottom;
323 int index =
vm.dbgState->breakpointsCount;
324 if (
vm.dbgState->breakpointsCount == MAX_BREAKPOINTS) {
326 for (
int i = 0; i < MAX_BREAKPOINTS; ++i) {
327 if (
vm.dbgState->breakpoints[i].inFunction == NULL) {
332 if (index ==
vm.dbgState->breakpointsCount) {
336 index =
vm.dbgState->breakpointsCount++;
339 vm.dbgState->breakpoints[index].inFunction = target;
340 vm.dbgState->breakpoints[index].offset = offset;
341 vm.dbgState->breakpoints[index].originalOpcode = target->
chunk.code[offset];
342 vm.dbgState->breakpoints[index].flags = flags;
343 target->
chunk.code[offset] = OP_BREAKPOINT;
356 if (object->
type == KRK_OBJ_CODEOBJECT) {
358 if (filename == chunk->filename) {
367 object =
object->
next;
371 if (!target)
return -1;
376 for (
size_t i = 0; i < target->
chunk.linesCount; ++i) {
377 if (target->
chunk.lines[i].line > line)
break;
378 if (target->
chunk.lines[i].line == line) {
379 offset = target->
chunk.lines[i].startOffset;
382 offset = target->
chunk.lines[i].startOffset;
389 if (breakIndex < 0 || breakIndex >=
vm.dbgState->breakpointsCount ||
vm.dbgState->breakpoints[breakIndex].inFunction == NULL)
391 vm.dbgState->breakpoints[breakIndex].inFunction->chunk.code[
vm.dbgState->breakpoints[breakIndex].offset] = OP_BREAKPOINT;
394 KRK_Function(enablebreakpoint) {
395 CHECK_ARG(0,
int,krk_integer_type,breakIndex);
402 if (breakIndex < 0 || breakIndex >=
vm.dbgState->breakpointsCount ||
vm.dbgState->breakpoints[breakIndex].inFunction == NULL)
404 vm.dbgState->breakpoints[breakIndex].inFunction->chunk.code[
vm.dbgState->breakpoints[breakIndex].offset] =
405 vm.dbgState->breakpoints[breakIndex].originalOpcode;
406 if (breakIndex ==
vm.dbgState->repeatStack_top) {
407 vm.dbgState->repeatStack_top = -1;
411 KRK_Function(disablebreakpoint) {
412 CHECK_ARG(0,
int,krk_integer_type,breakIndex);
419 if (breakIndex < 0 || breakIndex >=
vm.dbgState->breakpointsCount ||
vm.dbgState->breakpoints[breakIndex].inFunction == NULL)
422 vm.dbgState->breakpoints[breakIndex].inFunction = NULL;
423 while (
vm.dbgState->breakpointsCount &&
vm.dbgState->breakpoints[
vm.dbgState->breakpointsCount-1].inFunction == NULL) {
424 vm.dbgState->breakpointsCount--;
428 KRK_Function(delbreakpoint) {
429 CHECK_ARG(0,
int,krk_integer_type,breakIndex);
435 KRK_Function(addbreakpoint) {
436 FUNCTION_TAKES_EXACTLY(2);
437 CHECK_ARG(1,
int,krk_integer_type,lineNo);
443 if (
krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S(
"flags")), &flagsValue)) {
444 if (!IS_INTEGER(flagsValue))
445 return TYPE_ERROR(
int,flagsValue);
446 flags = AS_INTEGER(flagsValue);
451 if (IS_STRING(argv[0])) {
455 if (IS_CLOSURE(argv[0])) {
456 target = AS_CLOSURE(argv[0])->function;
457 }
else if (IS_BOUND_METHOD(argv[0]) && IS_CLOSURE(OBJECT_VAL(AS_BOUND_METHOD(argv[0])->method))) {
458 target = AS_CLOSURE(OBJECT_VAL(AS_BOUND_METHOD(argv[0])->method))->function;
459 }
else if (IS_codeobject(argv[0])) {
460 target = AS_codeobject(argv[0]);
462 return TYPE_ERROR(
function or method or filename,argv[0]);
466 for (
size_t i = 0; i < target->
chunk.linesCount; ++i) {
467 if (target->
chunk.lines[i].line > (
size_t)lineNo)
break;
468 if (target->
chunk.lines[i].line == (
size_t)lineNo) {
469 last = target->
chunk.lines[i].startOffset;
472 last = target->
chunk.lines[i].startOffset;
480 return INTEGER_VAL(result);
518 if (!
vm.dbgState->debuggerHook)
521 if (
vm.dbgState->repeatStack_top != -1) {
526 vm.dbgState->repeatStack_top =
vm.dbgState->repeatStack_bottom;
527 vm.dbgState->repeatStack_bottom = -1;
529 if (!
vm.dbgState->thisWasForced) {
530 int result =
vm.dbgState->debuggerHook(frame);
532 case KRK_DEBUGGER_CONTINUE:
535 case KRK_DEBUGGER_ABORT:
538 case KRK_DEBUGGER_STEP:
541 case KRK_DEBUGGER_QUIT:
544 case KRK_DEBUGGER_RAISE:
551 vm.dbgState->thisWasForced = 0;
556 vm.dbgState->thisWasForced = 1;
564 if (
vm.dbgState->debuggerHook)
return 1;
565 vm.dbgState->debuggerHook = hook;
570 if (breakIndex < 0 || breakIndex >=
vm.dbgState->breakpointsCount)
572 if (
vm.dbgState->breakpoints[breakIndex].inFunction == NULL)
575 if (funcOut) *funcOut =
vm.dbgState->breakpoints[breakIndex].inFunction;
576 if (offsetOut) *offsetOut =
vm.dbgState->breakpoints[breakIndex].offset;
577 if (flagsOut) *flagsOut =
vm.dbgState->breakpoints[breakIndex].flags;
578 if (enabled) *enabled = (
vm.dbgState->breakpoints[breakIndex].inFunction->chunk.code[
vm.dbgState->breakpoints[breakIndex].offset] == OP_BREAKPOINT) || breakIndex ==
vm.dbgState->repeatStack_top;
588 size_t offset = (frame->
ip - 1) - callee->
chunk.code;
590 for (
int i = 0; i <
vm.dbgState->breakpointsCount; ++i) {
591 if (
vm.dbgState->breakpoints[i].inFunction == callee &&
vm.dbgState->breakpoints[i].offset == offset) {
604 callee->
chunk.code[offset] =
vm.dbgState->breakpoints[index].originalOpcode;
610 vm.dbgState->repeatStack_bottom = index;
623 FUNCTION_TAKES_EXACTLY(1);
625 if (IS_CLOSURE(argv[0])) {
628 }
else if (IS_codeobject(argv[0])) {
629 krk_disassembleCodeObject(stdout, AS_codeobject(argv[0]), AS_codeobject(argv[0])->name ? AS_codeobject(argv[0])->name->chars :
"<unnamed>");
630 }
else if (IS_BOUND_METHOD(argv[0])) {
631 if (AS_BOUND_METHOD(argv[0])->method->type == KRK_OBJ_CLOSURE) {
633 const char * methodName = func->
name ? func->
name->
chars :
"<unnamed>";
634 const char * typeName = IS_CLASS(AS_BOUND_METHOD(argv[0])->receiver) ? AS_CLASS(AS_BOUND_METHOD(argv[0])->receiver)->name->chars :
krk_typeName(AS_BOUND_METHOD(argv[0])->receiver);
635 size_t allocSize = strlen(methodName) + strlen(typeName) + 2;
636 char * tmp = malloc(allocSize);
637 snprintf(tmp, allocSize,
"%s.%s", typeName, methodName);
641 krk_runtimeError(
vm.exceptions->typeError,
"Can not disassemble built-in method of '%T'", AS_BOUND_METHOD(argv[0])->receiver);
643 }
else if (IS_CLASS(argv[0])) {
645 if (
krk_tableGet(&AS_CLASS(argv[0])->methods, OBJECT_VAL(S(
"__func__")), &code) && IS_CLOSURE(code)) {
651 krk_runtimeError(
vm.exceptions->typeError,
"Don't know how to disassemble '%T'", argv[0]);
657 KRK_Function(build) {
658 FUNCTION_TAKES_AT_LEAST(1);
659 FUNCTION_TAKES_AT_MOST(2);
661 char * fileName =
"<source>";
664 fileName = filename->chars;
674 if (c)
return OBJECT_VAL(c);
675 else return NONE_VAL();
679 #define SIMPLE(opc) case opc: size = 1; break;
680 #define CONSTANT(opc,more) case opc: { constant = chunk->code[offset + 1]; size = 2; more; break; } \
681 case opc ## _LONG: { constant = (chunk->code[offset + 1] << 16) | \
682 (chunk->code[offset + 2] << 8) | (chunk->code[offset + 3]); size = 4; more; break; }
683 #define OPERAND(opc,more) case opc: { operand = chunk->code[offset + 1]; size = 2; more; break; } \
684 case opc ## _LONG: { operand = (chunk->code[offset + 1] << 16) | \
685 (chunk->code[offset + 2] << 8) | (chunk->code[offset + 3]); size = 4; more; break; }
686 #define JUMP(opc,sign) case opc: { jump = 0 sign ((chunk->code[offset + 1] << 8) | (chunk->code[offset + 2])); \
688 #define CLOSURE_MORE \
689 KrkCodeObject * function = AS_codeobject(chunk->constants.values[constant]); \
690 size_t baseOffset = offset; \
691 for (size_t j = 0; j < function->upvalueCount; ++j) { \
692 int isLocal = chunk->code[baseOffset++ + size]; \
698 size += baseOffset - offset;
699 #define EXPAND_ARGS_MORE
700 #define FORMAT_VALUE_MORE
701 #define LOCAL_MORE local = operand;
708 while (offset < chunk->count) {
709 uint8_t opcode = chunk->code[offset];
711 ssize_t constant = -1;
713 ssize_t operand = -1;
723 if (constant != -1) {
725 }
else if (jump != 0) {
727 }
else if (local != -1) {
735 }
else if (operand != -1) {
752 KRK_Function(examine) {
753 FUNCTION_TAKES_EXACTLY(1);
755 return _examineInternal(func);
765 #undef EXPAND_ARGS_MORE
766 #undef FORMAT_VALUE_MORE
775 vm.dbgState->repeatStack_top = -1;
776 vm.dbgState->repeatStack_bottom = -1;
779 "@brief Provides tools for disassembling bytecode.\n\n"
780 "### Code Disassembly in Kuroko\n\n"
781 "The @c dis module contains functions for dealing with _code objects_ which "
782 "represent the compiled bytecode of a Kuroko function. The bytecode compilation "
783 "process is entirely static and bytecode analysis can be performed without calling "
784 "into the VM to run dynamic code.\n\n"
785 "### Debugger Breakpoints\n\n"
786 "Kuroko interpreters can provide a debugger hook through the C API's "
787 "@ref krk_debug_registerCallback() function. Breakpoints can be managed both "
788 "from the C API and from this module's @ref addbreakpoint, @ref delbreakpoint, "
789 "@ref enablebreakpoint, and @ref disablebreakpoint methods."
792 KRK_DOC(BIND_FUNC(module, dis),
793 "@brief Disassemble an object.\n"
795 "Dumps a disassembly of the bytecode in the code object associated with @p obj. "
796 "If @p obj can not be disassembled, a @ref TypeError is raised.");
798 KRK_DOC(BIND_FUNC(module, build),
799 "@brief Compile a string to a code object.\n"
800 "@arguments code\n\n"
801 "Compiles the string @p code and returns a code object. If a syntax "
802 "error is encountered, it will be raised.");
804 KRK_DOC(BIND_FUNC(module, examine),
805 "@brief Convert a code object to a list of instructions.\n"
806 "@arguments func\n\n"
807 "Examines the code object @p func and returns a list representation of its instructions. "
808 "Each instruction entry is a tuple of the opcode, total instruction size in bytes, and "
809 "the operand of the argument, either as an integer for jump offsets, the actual value for "
810 "constant operands, or the name of a local or global variable if available.");
812 KRK_DOC(BIND_FUNC(module, addbreakpoint),
813 "@brief Attach a breakpoint to a code object.\n"
814 "@arguments func, line\n\n"
815 "@p func may be a filename string, or a function, method, or code object. Returns "
816 "the new breakpoint index, or raises @ref Exception if a breakpoint code not be added.");
818 KRK_DOC(BIND_FUNC(module, delbreakpoint),
819 "@brief Delete a breakpoint.\n"
820 "@arguments handle\n\n"
821 "Delete the breakpoint specified by @p handle, disabling it if it was enabled. "
822 "May raise @ref IndexError if @p handle is not a valid breakpoint handle.");
824 KRK_DOC(BIND_FUNC(module, enablebreakpoint),
825 "@brief Enable a breakpoint.\n"
826 "@arguments handle\n\n"
827 "Enable the breakpoint specified by @p handle. May raise @ref IndexError if "
828 "@p handle is not a valid breakpoint handle.");
830 KRK_DOC(BIND_FUNC(module, disablebreakpoint),
831 "@brief Disable a breakpoint.\n"
832 "@arguments handle\n\n"
833 "Disable the breakpoint specified by @p handle. May raise @ref IndexError if "
834 "@p handle is not a valid breakpoint handle.");
839 #define OPCODE(opc) krk_attachNamedValue(&module->fields, #opc, INTEGER_VAL(opc));
840 #define SIMPLE(opc) OPCODE(opc)
841 #define CONSTANT(opc,more) OPCODE(opc) OPCODE(opc ## _LONG)
842 #define OPERAND(opc,more) OPCODE(opc) OPCODE(opc ## _LONG)
843 #define JUMP(opc,sign) OPCODE(opc)
KrkCodeObject * krk_compile(const char *src, char *fileName)
Compile a source string to bytecode.
Exported methods for the source compiler.
Functions for debugging bytecode execution.
#define KRK_BREAKPOINT_ONCE
int krk_debug_addBreakpointCodeOffset(KrkCodeObject *codeObject, size_t offset, int flags)
Add a breakpoint to the given code object.
void krk_debug_disableSingleStep(void)
Disable single stepping in the current thread.
int krk_debuggerHook(KrkCallFrame *frame)
Called by the VM on single step.
int krk_debug_examineBreakpoint(int breakIndex, KrkCodeObject **funcOut, size_t *offsetOut, int *flagsOut, int *enabledOut)
Retreive information on a breakpoint.
int(* KrkDebugCallback)(KrkCallFrame *frame)
Function pointer for a debugger hook. krk_debug_registerCallback()
int krk_debug_enableBreakpoint(int breakpointId)
Enable a breakpoint.
int krk_debugBreakpointHandler(void)
Called by the VM when a breakpoint is encountered.
void krk_debug_dumpTraceback(void)
Safely dump a traceback to stderr.
void krk_debug_enableSingleStep(void)
Enable single stepping in the current thread.
int krk_debug_removeBreakpoint(int breakpointId)
Remove a breakpoint from the breakpoint table.
int krk_debug_registerCallback(KrkDebugCallback hook)
Register a debugger callback.
int krk_debug_disableBreakpoint(int breakpointId)
Disable a breakpoint.
size_t krk_disassembleInstruction(FILE *f, KrkCodeObject *func, size_t offset)
Print a disassembly of a single opcode instruction.
int krk_debug_addBreakpointFileLine(KrkString *filename, size_t line, int flags)
Add a breakpoint to the given line of a file.
#define KRK_BREAKPOINT_REPEAT
void krk_disassembleCodeObject(FILE *f, KrkCodeObject *func, const char *name)
Print a disassembly of 'func' to the stream 'f'.
#define KRK_BREAKPOINT_NORMAL
void krk_debug_dumpStack(FILE *f, KrkCallFrame *frame)
Print the elements on the stack.
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
void krk_dumpTraceback(void)
If there is an active exception, print a traceback to stderr.
Represents a managed call state in a VM thread.
Opcode chunk of a code object.
size_t krk_lineNumber(KrkChunk *chunk, size_t offset)
Obtain the line number for a byte offset into a bytecode chunk.
KrkCodeObject * function
The codeobject containing the bytecode run when this function is called.
unsigned short potentialPositionals
Precalculated positional arguments for complex argument processing.
KrkChunk chunk
Bytecode data.
KrkLocalEntry * localNames
Stores the names of local variables used in the function, for debugging.
unsigned short keywordArgs
Arity of keyword (default) arguments.
size_t localNameCount
Number of entries in localNames.
KrkString * name
Name of the function.
unsigned short totalArguments
Total argument cells we can fill in complex argument processing.
KrkInstance * krk_newInstance(KrkClass *_class)
Create a new instance of the given class.
KrkTable fields
Attributes table.
KrkValue krk_list_of(int argc, const KrkValue argv[], int hasKw)
Create a list object.
size_t birthday
Instruction offset that this local name became valid on.
KrkString * name
Name of the local.
size_t id
Local ID as used by opcodes; offset from the frame's stack base.
size_t deathday
Instruction offset that this local name becomes invalid on.
The most basic object type.
uint16_t flags
General object flags, mostly related to garbage collection.
uint16_t type
Tag indicating core type.
struct KrkObj * next
Invasive linked list of all objects in the VM.
Immutable sequence of Unicode codepoints.
char * chars
UTF8 canonical data.
int krk_tableGet(KrkTable *table, KrkValue key, KrkValue *value)
Obtain the value associated with a key in a table.
void krk_attachNamedObject(KrkTable *table, const char name[], KrkObj *obj)
Attach an object to an attribute table.
void krk_attachNamedValue(KrkTable *table, const char name[], KrkValue obj)
Attach a value to an attribute table.
KrkValue currentException
Immutable sequence of arbitrary values.
KrkValueArray values
Stores the length, capacity, and actual values of the tuple.
KrkTuple * krk_newTuple(size_t length)
Create a new tuple.
void krk_writeValueArray(KrkValueArray *array, KrkValue value)
Add a value to a value array.
Stack reference or primative value.
const char * krk_typeName(KrkValue value)
Get the name of the type of a value.
void krk_printValueSafe(FILE *f, KrkValue value)
Print a value without calling the VM.
Utilities for creating native bindings.
#define KRK_DOC(thing, text)
Attach documentation to a thing of various types.
Core API for the bytecode virtual machine.
#define vm
Convenience macro for namespacing.
KrkValue krk_pop(void)
Pop the top of the stack.
threadLocal KrkThreadState krk_currentThread
Thread-local VM state.
void krk_module_init_dis(void)
Initialize the built-in 'dis' module.
void krk_push(KrkValue value)
Push a stack value.
KrkValue krk_peek(int distance)
Peek down from the top of the stack.