mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-03-04 13:15:55 +08:00
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:
parent
0cfdfa7415
commit
82919a690e
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
21
src/libs/thirdparty/term/LICENSE
vendored
21
src/libs/thirdparty/term/LICENSE
vendored
@ -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.
|
1027
src/libs/thirdparty/term/term.h
vendored
1027
src/libs/thirdparty/term/term.h
vendored
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user