Garbage collection bugs fixed

- Objects that weren't pushed to PKVM's temp reference were fixed
- vm->bytes_allocated was modified after the re-calculation of garbage
  collection fixed.
This commit is contained in:
Thakee Nathees 2022-05-25 02:24:35 +05:30
parent 0cfdfa7415
commit 82919a690e
9 changed files with 112 additions and 1359 deletions

View File

@ -2734,9 +2734,12 @@ static void compileFunction(Compiler* compiler, FuncType fn_type) {
if (compiler->parser.has_syntax_error) return;
// The function will register itself in the owner's constant pool and it's
// GC root so we don't need to push it to temp references.
int fn_index;
Function* func = newFunction(compiler->parser.vm, name, name_length,
compiler->module, false, NULL, &fn_index);
func->is_method = (fn_type == FUNC_METHOD || fn_type == FUNC_CONSTRUCTOR);
checkMaxConstantsReached(compiler, fn_index);

View File

@ -124,6 +124,7 @@ PKVM* pkNewVM(PkConfiguration* config) {
vm->working_set = (Object**)vm->config.realloc_fn(
NULL, sizeof(Object*) * vm->working_set_capacity, NULL);
vm->next_gc = INITIAL_GC_SIZE;
vm->collecting_garbage = false;
vm->min_heap_size = MIN_HEAP_SIZE;
vm->heap_fill_percent = HEAP_FILL_PERCENT;
@ -179,7 +180,12 @@ void pkSetUserData(PKVM* vm, void* user_data) {
PkHandle* pkNewModule(PKVM* vm, const char* name) {
CHECK_ARG_NULL(name);
Module* module = newModuleInternal(vm, name);
return vmNewHandle(vm, VAR_OBJ(module));
vmPushTempRef(vm, &module->_super); // module.
PkHandle* handle = vmNewHandle(vm, VAR_OBJ(module));
vmPopTempRef(vm); // module.
return handle;
}
void pkRegisterModule(PKVM* vm, PkHandle* module) {
@ -219,7 +225,10 @@ PkHandle* pkNewClass(PKVM* vm, const char* name,
class_->new_fn = new_fn;
class_->delete_fn = delete_fn;
return vmNewHandle(vm, VAR_OBJ(class_));
vmPushTempRef(vm, &class_->_super); // class_.
PkHandle* handle = vmNewHandle(vm, VAR_OBJ(class_));
vmPopTempRef(vm); // class_.
return handle;
}
void pkClassAddMethod(PKVM* vm, PkHandle* cls,
@ -237,6 +246,8 @@ void pkClassAddMethod(PKVM* vm, PkHandle* cls,
Function* fn = newFunction(vm, name, (int)strlen(name),
class_->owner, true, NULL, NULL);
vmPushTempRef(vm, &fn->_super); // fn.
fn->arity = arity;
fn->is_method = true;
fn->native = fptr;
@ -246,15 +257,19 @@ void pkClassAddMethod(PKVM* vm, PkHandle* cls,
// won't be garbage collected (class handle has reference to the module).
Closure* method = newClosure(vm, fn);
vmPopTempRef(vm); // fn.
vmPushTempRef(vm, &method->_super); // method.
{
if (strcmp(name, CTOR_NAME) == 0) {
class_->ctor = method;
if (strcmp(name, CTOR_NAME) == 0) {
class_->ctor = method;
} else {
vmPushTempRef(vm, &method->_super); // method.
pkClosureBufferWrite(&class_->methods, vm, method);
vmPopTempRef(vm); // method.
} else {
vmPushTempRef(vm, &method->_super); // method.
pkClosureBufferWrite(&class_->methods, vm, method);
vmPopTempRef(vm); // method.
}
}
vmPopTempRef(vm); // method.
}
void pkReleaseHandle(PKVM* vm, PkHandle* handle) {
@ -766,7 +781,11 @@ bool pkSetAttribute(PKVM* vm, int instance, const char* name, int value) {
VALIDATE_SLOT_INDEX(instance);
VALIDATE_SLOT_INDEX(value);
varSetAttrib(vm, SLOT(instance), newString(vm, name), SLOT(value));
String* sname = newString(vm, name);
vmPushTempRef(vm, &sname->_super); // sname.
varSetAttrib(vm, SLOT(instance), sname, SLOT(value));
vmPopTempRef(vm); // sname.
return !VM_HAS_ERROR(vm);
}
@ -777,12 +796,19 @@ bool pkGetAttribute(PKVM* vm, int instance, const char* name,
VALIDATE_SLOT_INDEX(instance);
VALIDATE_SLOT_INDEX(index);
SET_SLOT(index, varGetAttrib(vm, SLOT(instance), newString(vm, name)));
String* sname = newString(vm, name);
vmPushTempRef(vm, &sname->_super); // sname.
SET_SLOT(index, varGetAttrib(vm, SLOT(instance), sname));
vmPopTempRef(vm); // sname.
return !VM_HAS_ERROR(vm);
}
static Var _newInstance(PKVM* vm, Class* cls, int argc, Var* argv) {
Var instance = preConstructSelf(vm, cls);
if (VM_HAS_ERROR(vm)) return VAR_NULL;
if (IS_OBJ(instance)) vmPushTempRef(vm, AS_OBJ(instance)); // instance.
Closure* ctor = cls->ctor;
while (ctor == NULL) {
@ -792,6 +818,7 @@ static Var _newInstance(PKVM* vm, Class* cls, int argc, Var* argv) {
}
if (ctor != NULL) vmCallMethod(vm, instance, ctor, argc, argv, NULL);
if (IS_OBJ(instance)) vmPopTempRef(vm); // instance.
return instance;
}
@ -861,8 +888,12 @@ bool pkCallMethod(PKVM* vm, int instance, const char* method,
if (ret >= 0) VALIDATE_SLOT_INDEX(ret);
bool is_method = false;
Var callable = getMethod(vm, SLOT(instance), newString(vm, method),
String* smethod = newString(vm, method);
vmPushTempRef(vm, &smethod->_super); // smethod.
Var callable = getMethod(vm, SLOT(instance), smethod,
&is_method);
vmPopTempRef(vm); // smethod.
if (VM_HAS_ERROR(vm)) return false;
// Calls a class == construct.

View File

@ -149,7 +149,9 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
markObject(vm, &func->owner->_super);
if (!func->is_native) {
// If a garbage collection is triggered when allocating a name string
// for this function, it's [fn] property will be NULL.
if (!func->is_native && func->fn != NULL) {
Fn* fn = func->fn;
vm->bytes_allocated += sizeof(Fn);
@ -293,14 +295,14 @@ String* newStringVaArgs(PKVM* vm, const char* fmt, va_list args) {
List* newList(PKVM* vm, uint32_t size) {
List* list = ALLOCATE(vm, List);
vmPushTempRef(vm, &list->_super);
vmPushTempRef(vm, &list->_super); // list.
varInitObject(&list->_super, vm, OBJ_LIST);
pkVarBufferInit(&list->elements);
if (size > 0) {
pkVarBufferFill(&list->elements, vm, VAR_NULL, size);
list->elements.count = 0;
}
vmPopTempRef(vm);
vmPopTempRef(vm); // list.
return list;
}
@ -323,13 +325,9 @@ Range* newRange(PKVM* vm, double from, double to) {
Module* newModule(PKVM* vm) {
Module* module = ALLOCATE(vm, Module);
memset(module, 0, sizeof(Module));
varInitObject(&module->_super, vm, OBJ_MODULE);
module->path = NULL;
module->name = NULL;
module->initialized = false;
module->body = NULL;
pkVarBufferInit(&module->globals);
pkUintBufferInit(&module->global_names);
pkVarBufferInit(&module->constants);
@ -343,6 +341,7 @@ Function* newFunction(PKVM* vm, const char* name, int length,
int* fn_index) {
Function* func = ALLOCATE(vm, Function);
memset(func, 0, sizeof(Function));
varInitObject(&func->_super, vm, OBJ_FUNC);
vmPushTempRef(vm, &func->_super); // func
@ -388,10 +387,7 @@ Closure* newClosure(PKVM* vm, Function* fn) {
varInitObject(&closure->_super, vm, OBJ_CLOSURE);
closure->fn = fn;
for (int i = 0; i < fn->upvalue_count; i++) {
closure->upvalues[i] = NULL;
}
memset(closure->upvalues, 0, sizeof(Upvalue*) * fn->upvalue_count);
return closure;
}
@ -410,9 +406,10 @@ Fiber* newFiber(PKVM* vm, Closure* closure) {
ASSERT(closure == NULL || closure->fn->arity >= -1, OOPS);
Fiber* fiber = ALLOCATE(vm, Fiber);
ASSERT(fiber != NULL, "Out of memory");
// Not sure why this memset is needed here. If it doesn't then remove it.
// If a garbage collection is triggered here, and the fiber isn't fully
// constructed -> it's fields are not intialized yet, would cause a crash
// so we need to memset here.
memset(fiber, 0, sizeof(Fiber));
varInitObject(&fiber->_super, vm, OBJ_FIBER);
@ -476,6 +473,12 @@ Class* newClass(PKVM* vm, const char* name, int length,
const char* docstring, int* cls_index) {
Class* cls = ALLOCATE(vm, Class);
// If the garbage collection trigged bellow while allocating for
// [cls->name] or other properties, the calss is in the root (temp ref)
// and it's property [cls->name] is un initialized, which cause a crash.
memset(cls, 0, sizeof(Class));
varInitObject(&cls->_super, vm, OBJ_CLASS);
vmPushTempRef(vm, &cls->_super); // class.
@ -483,12 +486,7 @@ Class* newClass(PKVM* vm, const char* name, int length,
pkClosureBufferInit(&cls->methods);
cls->class_of = PK_INSTANCE;
cls->owner = NULL;
cls->super_class = super;
cls->docstring = NULL;
cls->ctor = NULL;
cls->new_fn = NULL;
cls->delete_fn = NULL;
// Builtin types doesn't belongs to a module.
if (module != NULL) {
@ -510,36 +508,38 @@ Instance* newInstance(PKVM* vm, Class* cls) {
"class with newInstance() function.");
Instance* inst = ALLOCATE(vm, Instance);
memset(inst, 0, sizeof(Instance));
varInitObject(&inst->_super, vm, OBJ_INST);
vmPushTempRef(vm, &inst->_super); // inst.
inst->cls = cls;
inst->attribs = newMap(vm);
if (cls->new_fn != NULL) {
inst->native = cls->new_fn(vm);
} else {
inst->native = NULL;
}
inst->attribs = newMap(vm);
vmPopTempRef(vm); // inst.
return inst;
}
List* rangeAsList(PKVM* vm, Range* self) {
List* list;
if (self->from < self->to) {
list = newList(vm, (uint32_t)(self->to - self->from));
List* list = newList(vm, (uint32_t)(self->to - self->from));
vmPushTempRef(vm, &list->_super); // list.
for (double i = self->from; i < self->to; i++) {
pkVarBufferWrite(&list->elements, vm, VAR_NUM(i));
}
return list;
vmPopTempRef(vm); // list.
} else {
list = newList(vm, 0);
return list;
}
return list;
return newList(vm, 0);
}
String* stringLower(PKVM* vm, String* self) {

View File

@ -27,10 +27,24 @@ void* vmRealloc(PKVM* vm, void* memory, size_t old_size, size_t new_size) {
// Track the total allocated memory of the VM to trigger the GC.
// if vmRealloc is called for freeing, the old_size would be 0 since
// deallocated bytes are traced by garbage collector.
vm->bytes_allocated += new_size - old_size;
//
// If we're running a garbage collection, VM's byte allocated will be
// re-calculated at vmCollectGarbage() which is equal to the remaining
// objects after clening the garbage. And clearing a garbage will
// recursively invoke this function so we shouldn't modify it.
if (!vm->collecting_garbage) {
vm->bytes_allocated += new_size - old_size;
}
// If we're garbage collecting no new allocation is allowed.
ASSERT(!vm->collecting_garbage || new_size == 0,
"No new allocation is allowed while garbage collection is running.");
if (new_size > 0 && vm->bytes_allocated > vm->next_gc) {
ASSERT(vm->collecting_garbage == false, OOPS);
vm->collecting_garbage = true;
vmCollectGarbage(vm);
vm->collecting_garbage = false;
}
#if TRACE_MEMORY
@ -99,10 +113,6 @@ Module* vmGetModule(PKVM* vm, String* key) {
void vmCollectGarbage(PKVM* vm) {
// Reset VM's bytes_allocated value and count it again so that we don't
// required to know the size of each object that'll be freeing.
vm->bytes_allocated = 0;
// Mark builtin functions.
for (int i = 0; i < vm->builtins_count; i++) {
markObject(vm, &vm->builtins_funcs[i]->_super);
@ -139,11 +149,23 @@ void vmCollectGarbage(PKVM* vm) {
markObject(vm, &vm->fiber->_super);
}
// Reset VM's bytes_allocated value and count it again so that we don't
// required to know the size of each object that'll be freeing.
vm->bytes_allocated = 0;
// Pop the marked objects from the working set and push all of it's
// referenced objects. This will repeat till no more objects left in the
// working set.
popMarkedObjects(vm);
// Now [vm->bytes_allocated] is equal to the number of bytes allocated for
// the root objects which are marked above. Since we're garbage collecting
// freeObject() shouldn't modify vm->bytes_allocated. We ensure this by
// copying the value to [bytes_allocated] and check after freeing.
#ifdef DEBUG
size_t bytes_allocated = vm->bytes_allocated;
#endif
// Now sweep all the un-marked objects in then link list and remove them
// from the chain.
@ -166,6 +188,10 @@ void vmCollectGarbage(PKVM* vm) {
}
}
#ifdef DEBUG
ASSERT(bytes_allocated = vm->bytes_allocated, OOPS);
#endif
// Next GC heap size will be change depends on the byte we've left with now,
// and the [heap_fill_percent].
vm->next_gc = vm->bytes_allocated + (
@ -937,7 +963,9 @@ L_vm_main_loop:
ASSERT_INDEX(index, module->constants.count);
ASSERT(IS_OBJ_TYPE(module->constants.data[index], OBJ_FUNC), OOPS);
Function* fn = (Function*)AS_OBJ(module->constants.data[index]);
Closure* closure = newClosure(vm, fn);
vmPushTempRef(vm, &closure->_super); // closure.
// Capture the vaupes.
for (int i = 0; i < fn->upvalue_count; i++) {
@ -954,6 +982,8 @@ L_vm_main_loop:
}
PUSH(VAR_OBJ(closure));
vmPopTempRef(vm); // closure.
DISPATCH();
}

View File

@ -69,6 +69,10 @@ struct PKVM {
// The number of bytes that'll trigger the next GC.
size_t next_gc;
// True if PKVM is running a garbage collection, and no new allocation is
// allowed in this phase.
bool collecting_garbage;
// Minimum size the heap could get.
size_t min_heap_size;

View File

@ -1,259 +0,0 @@
/*
* Copyright (c) 2020-2022 Thakee Nathees
* Copyright (c) 2021-2022 Pocketlang Contributors
* Distributed Under The MIT License
*/
#ifndef PK_AMALGAMATED
#include "libs.h"
#endif
#define TERM_IMPLEMENT
#include "thirdparty/term/term.h" //<< AMALG_INLINE >>
#undef TERM_IMPLEMENT
// A reference to the event class, to check is instance of.
static PkHandle* _cls_term_event = NULL;
static void _setSlotVector(PKVM* vm, int slot, int tmp, double x, double y) {
if (!pkImportModule(vm, "types", slot)) return;
if (!pkGetAttribute(vm, slot, "Vector", slot)) return;
if (!pkNewInstance(vm, slot, slot, 0, 0)) return;
pkSetSlotNumber(vm, tmp, x);
if (!pkSetAttribute(vm, slot, "x", tmp)) return;
pkSetSlotNumber(vm, tmp, y);
if (!pkSetAttribute(vm, slot, "y", tmp)) return;
}
void* _termEventNew(PKVM* vm) {
term_Event* event = pkRealloc(vm, NULL, sizeof(term_Event));
event->type = TERM_ET_UNKNOWN;
return event;
}
void _termEventDelete(PKVM* vm, void* event) {
pkRealloc(vm, event, 0);
}
void _termEventGetter(PKVM* vm) {
const char* name;
if (!pkValidateSlotString(vm, 1, &name, NULL)) return;
term_Event* event = pkGetSelf(vm);
if (strcmp(name, "type") == 0) {
pkSetSlotNumber(vm, 0, (double)event->type);
} else if (strcmp(name, "keycode") == 0) {
pkSetSlotNumber(vm, 0, (double)event->key.code);
} else if (strcmp(name, "ascii") == 0) {
pkSetSlotNumber(vm, 0, (double)event->key.ascii);
} else if (strcmp(name, "modifiers") == 0) {
if (event->type == TERM_ET_KEY_DOWN) {
pkSetSlotNumber(vm, 0, (double)event->key.modifiers);
} else {
pkSetSlotNumber(vm, 0, (double)event->mouse.modifiers);
}
} else if (strcmp(name, "button") == 0) {
pkSetSlotNumber(vm, 0, (double)event->mouse.button);
} else if (strcmp(name, "pos") == 0) {
pkReserveSlots(vm, 2);
_setSlotVector(vm, 0, 1, event->mouse.pos.x, event->mouse.pos.y);
} else if (strcmp(name, "scroll") == 0) {
pkSetSlotBool(vm, 0, event->mouse.scroll);
}
}
void _registerEnums(PKVM* vm, PkHandle* term) {
pkReserveSlots(vm, 1);
pkSetSlotHandle(vm, 0, term);
pkSetSlotNumber(vm, 1, TERM_KEY_UNKNOWN); pkSetAttribute(vm, 0, "KEY_UNKNOWN", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_0); pkSetAttribute(vm, 0, "KEY_0", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_1); pkSetAttribute(vm, 0, "KEY_1", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_2); pkSetAttribute(vm, 0, "KEY_2", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_3); pkSetAttribute(vm, 0, "KEY_3", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_4); pkSetAttribute(vm, 0, "KEY_4", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_5); pkSetAttribute(vm, 0, "KEY_5", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_6); pkSetAttribute(vm, 0, "KEY_6", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_7); pkSetAttribute(vm, 0, "KEY_7", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_8); pkSetAttribute(vm, 0, "KEY_8", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_9); pkSetAttribute(vm, 0, "KEY_9", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_A); pkSetAttribute(vm, 0, "KEY_A", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_B); pkSetAttribute(vm, 0, "KEY_B", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_C); pkSetAttribute(vm, 0, "KEY_C", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_D); pkSetAttribute(vm, 0, "KEY_D", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_E); pkSetAttribute(vm, 0, "KEY_E", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F); pkSetAttribute(vm, 0, "KEY_F", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_G); pkSetAttribute(vm, 0, "KEY_G", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_H); pkSetAttribute(vm, 0, "KEY_H", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_I); pkSetAttribute(vm, 0, "KEY_I", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_J); pkSetAttribute(vm, 0, "KEY_J", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_K); pkSetAttribute(vm, 0, "KEY_K", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_L); pkSetAttribute(vm, 0, "KEY_L", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_M); pkSetAttribute(vm, 0, "KEY_M", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_N); pkSetAttribute(vm, 0, "KEY_N", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_O); pkSetAttribute(vm, 0, "KEY_O", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_P); pkSetAttribute(vm, 0, "KEY_P", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_Q); pkSetAttribute(vm, 0, "KEY_Q", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_R); pkSetAttribute(vm, 0, "KEY_R", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_S); pkSetAttribute(vm, 0, "KEY_S", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_T); pkSetAttribute(vm, 0, "KEY_T", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_U); pkSetAttribute(vm, 0, "KEY_U", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_V); pkSetAttribute(vm, 0, "KEY_V", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_W); pkSetAttribute(vm, 0, "KEY_W", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_X); pkSetAttribute(vm, 0, "KEY_X", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_Y); pkSetAttribute(vm, 0, "KEY_Y", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_Z); pkSetAttribute(vm, 0, "KEY_Z", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_ESC); pkSetAttribute(vm, 0, "KEY_ESC", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_ENTER); pkSetAttribute(vm, 0, "KEY_ENTER", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_SPACE); pkSetAttribute(vm, 0, "KEY_SPACE", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_HOME); pkSetAttribute(vm, 0, "KEY_HOME", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_END); pkSetAttribute(vm, 0, "KEY_END", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_PAGEUP); pkSetAttribute(vm, 0, "KEY_PAGEUP", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_PAGEDOWN); pkSetAttribute(vm, 0, "KEY_PAGEDOWN", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_LEFT); pkSetAttribute(vm, 0, "KEY_LEFT", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_UP); pkSetAttribute(vm, 0, "KEY_UP", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_RIGHT); pkSetAttribute(vm, 0, "KEY_RIGHT", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_DOWN); pkSetAttribute(vm, 0, "KEY_DOWN", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_INSERT); pkSetAttribute(vm, 0, "KEY_INSERT", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_DELETE); pkSetAttribute(vm, 0, "KEY_DELETE", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_BACKSPACE); pkSetAttribute(vm, 0, "KEY_BACKSPACE", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_TAB); pkSetAttribute(vm, 0, "KEY_TAB", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F1); pkSetAttribute(vm, 0, "KEY_F1", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F2); pkSetAttribute(vm, 0, "KEY_F2", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F3); pkSetAttribute(vm, 0, "KEY_F3", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F4); pkSetAttribute(vm, 0, "KEY_F4", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F5); pkSetAttribute(vm, 0, "KEY_F5", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F6); pkSetAttribute(vm, 0, "KEY_F6", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F7); pkSetAttribute(vm, 0, "KEY_F7", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F8); pkSetAttribute(vm, 0, "KEY_F8", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F9); pkSetAttribute(vm, 0, "KEY_F9", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F10); pkSetAttribute(vm, 0, "KEY_F10", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F11); pkSetAttribute(vm, 0, "KEY_F11", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F12); pkSetAttribute(vm, 0, "KEY_F12", 1);
pkSetSlotNumber(vm, 1, TERM_MB_UNKNOWN); pkSetAttribute(vm, 0, "BUTTON_UNKNOWN", 1);
pkSetSlotNumber(vm, 1, TERM_MB_LEFT); pkSetAttribute(vm, 0, "BUTTON_LEFT", 1);
pkSetSlotNumber(vm, 1, TERM_MB_MIDDLE); pkSetAttribute(vm, 0, "BUTTON_MIDDLE", 1);
pkSetSlotNumber(vm, 1, TERM_MB_RIGHT); pkSetAttribute(vm, 0, "BUTTON_RIGHT", 1);
pkSetSlotNumber(vm, 1, TERM_MD_NONE); pkSetAttribute(vm, 0, "MD_NONE", 1);
pkSetSlotNumber(vm, 1, TERM_MD_CTRL); pkSetAttribute(vm, 0, "MD_CTRL", 1);
pkSetSlotNumber(vm, 1, TERM_MD_ALT); pkSetAttribute(vm, 0, "MD_ALT", 1);
pkSetSlotNumber(vm, 1, TERM_MD_SHIFT); pkSetAttribute(vm, 0, "MD_SHIFT", 1);
pkSetSlotNumber(vm, 1, TERM_ET_UNKNOWN); pkSetAttribute(vm, 0, "EVENT_UNKNOWN", 1);
pkSetSlotNumber(vm, 1, TERM_ET_KEY_DOWN); pkSetAttribute(vm, 0, "EVENT_KEY_DOWN", 1);
pkSetSlotNumber(vm, 1, TERM_ET_RESIZE); pkSetAttribute(vm, 0, "EVENT_RESIZE", 1);
pkSetSlotNumber(vm, 1, TERM_ET_DOUBLE_CLICK); pkSetAttribute(vm, 0, "EVENT_DOUBLE_CLICK", 1);
pkSetSlotNumber(vm, 1, TERM_ET_MOUSE_DOWN); pkSetAttribute(vm, 0, "EVENT_MOUSE_DOWN", 1);
pkSetSlotNumber(vm, 1, TERM_ET_MOUSE_UP); pkSetAttribute(vm, 0, "EVENT_MOUSE_UP", 1);
pkSetSlotNumber(vm, 1, TERM_ET_MOUSE_MOVE); pkSetAttribute(vm, 0, "EVENT_MOUSE_MOVE", 1);
pkSetSlotNumber(vm, 1, TERM_ET_MOUSE_DRAG); pkSetAttribute(vm, 0, "EVENT_MOUSE_DRAG", 1);
pkSetSlotNumber(vm, 1, TERM_ET_MOUSE_SCROLL); pkSetAttribute(vm, 0, "EVENT_MOUSE_SCROLL", 1);
}
void _termInit(PKVM* vm) {
bool capture_events;
if (!pkValidateSlotBool(vm, 1, &capture_events)) return;
term_init(capture_events);
}
void _termCleanup(PKVM* vm) {
term_cleanup();
}
void _termIsatty(PKVM* vm) {
pkSetSlotBool(vm, 0, term_isatty());
}
void _termNewScreenBuffer(PKVM* vm) {
term_new_screen_buffer();
}
void _termRestoreScreenBuffer(PKVM* vm) {
term_restore_screen_buffer();
}
void _termGetSize(PKVM* vm) {
pkReserveSlots(vm, 2);
term_Vec size = term_getsize();
_setSlotVector(vm, 0, 1, size.x, size.y);
}
void _termGetPosition(PKVM* vm) {
pkReserveSlots(vm, 2);
term_Vec pos = term_getposition();
_setSlotVector(vm, 0, 1, pos.x, pos.y);
}
void _termSetPosition(PKVM* vm) {
double x, y;
int argc = pkGetArgc(vm);
if (!pkCheckArgcRange(vm, argc, 1, 2)) return;
if (argc == 1) {
pkReserveSlots(vm, 3);
if (!pkGetAttribute(vm, 1, "x", 2)) return;
if (!pkValidateSlotNumber(vm, 2, &x)) return;
if (!pkGetAttribute(vm, 1, "y", 2)) return;
if (!pkValidateSlotNumber(vm, 2, &y)) return;
} else {
if (!pkValidateSlotNumber(vm, 1, &x)) return;
if (!pkValidateSlotNumber(vm, 2, &y)) return;
}
term_Vec pos = term_vec((int)x, (int)y);
term_setposition(pos);
}
void _termReadEvent(PKVM* vm) {
pkReserveSlots(vm, 3);
pkSetSlotHandle(vm, 2, _cls_term_event);
if (!pkValidateSlotInstanceOf(vm, 1, 2)) return;
term_Event* event = pkGetSlotNativeInstance(vm, 1);
pkSetSlotBool(vm, 0, term_read_event(event));
}
/*****************************************************************************/
/* MODULE REGISTER */
/*****************************************************************************/
void registerModuleTerm(PKVM* vm) {
PkHandle* term = pkNewModule(vm, "term");
_registerEnums(vm, term);
pkModuleAddFunction(vm, term, "init", _termInit, 1);
pkModuleAddFunction(vm, term, "cleanup", _termCleanup, 0);
pkModuleAddFunction(vm, term, "isatty", _termIsatty, 0);
pkModuleAddFunction(vm, term, "new_screen_buffer", _termNewScreenBuffer, 0);
pkModuleAddFunction(vm, term, "restore_screen_buffer", _termRestoreScreenBuffer, 0);
pkModuleAddFunction(vm, term, "getsize", _termGetSize, 0);
pkModuleAddFunction(vm, term, "getposition", _termGetPosition, 0);
pkModuleAddFunction(vm, term, "setposition", _termSetPosition, -1);
pkModuleAddFunction(vm, term, "read_event", _termReadEvent, 1);
_cls_term_event = pkNewClass(vm, "Event", NULL, term, _termEventNew, _termEventDelete);
pkClassAddMethod(vm, _cls_term_event, "@getter", _termEventGetter, 1);
pkRegisterModule(vm, term);
pkReleaseHandle(vm, term);
}
void cleanupModuleTerm(PKVM* vm) {
if (_cls_term_event) pkReleaseHandle(vm, _cls_term_event);
}

View File

@ -17,11 +17,6 @@ void registerModuleIO(PKVM* vm);
void registerModulePath(PKVM* vm);
void registerModuleDummy(PKVM* vm);
// Additional libraries.
void registerModuleTerm(PKVM* vm);
void cleanupModuleTerm(PKVM* vm);
// Registers the modules.
void registerLibs(PKVM* vm) {
registerModuleMath(vm);
@ -30,11 +25,8 @@ void registerLibs(PKVM* vm) {
registerModuleIO(vm);
registerModulePath(vm);
registerModuleDummy(vm);
registerModuleTerm(vm);
}
// Cleanup the modules.
void cleanupLibs(PKVM* vm) {
cleanupModuleTerm(vm);
}

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2022 Thakee Nathees
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

File diff suppressed because it is too large Load Diff