mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-05 20:26:53 +08:00
method buffer added to classes
and also allocation/de-allocation callbacks were added to newClass function and yet registering attribute getters and setters is to do.
This commit is contained in:
parent
776ea0ab87
commit
67ab2057c0
@ -188,8 +188,7 @@ int main(int argc, const char** argv) {
|
||||
user_data.repl_mode = false;
|
||||
pkSetUserData(vm, &user_data);
|
||||
|
||||
registerModulePath(vm);
|
||||
//REGISTER_ALL_MODULES(vm);
|
||||
REGISTER_ALL_MODULES(vm);
|
||||
|
||||
PkCompileOptions options = pkNewCompilerOptions();
|
||||
options.debug = debug;
|
||||
|
@ -6,6 +6,10 @@
|
||||
|
||||
#include "modules.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* FILE CLASS */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Str | If already exists | If does not exist |
|
||||
// -----+-------------------+-------------------|
|
||||
// 'r' | read from start | failure to open |
|
||||
@ -31,26 +35,21 @@ typedef struct {
|
||||
bool closed; // True if the file isn't closed yet.
|
||||
} File;
|
||||
|
||||
/*****************************************************************************/
|
||||
/* FILE OBJECT OPERATORS */
|
||||
/*****************************************************************************/
|
||||
|
||||
void fileGetAttrib(PKVM* vm, File* file, const char* attrib) {
|
||||
if (strcmp(attrib, "closed") == 0) {
|
||||
pkReturnBool(vm, file->closed);
|
||||
return;
|
||||
}
|
||||
void* _newFile() {
|
||||
File* file = NEW_OBJ(File);
|
||||
file->closed = true;
|
||||
file->mode = FMODE_NONE;
|
||||
file->fp = NULL;
|
||||
return file;
|
||||
}
|
||||
|
||||
bool fileSetAttrib(PKVM* vm, File* file, const char* attrib) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void fileClean(PKVM* vm, File* file) {
|
||||
void _deleteFile(void* ptr) {
|
||||
File* file = (File*)ptr;
|
||||
if (!file->closed) {
|
||||
if (fclose(file->fp) != 0) { /* TODO: error! */ }
|
||||
file->closed = true;
|
||||
}
|
||||
FREE_OBJ(file);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -171,7 +170,7 @@ static void _fileClose(PKVM* vm) {
|
||||
void registerModuleIO(PKVM* vm) {
|
||||
PkHandle* io = pkNewModule(vm, "io");
|
||||
|
||||
PkHandle* cls_file = pkNewClass(vm, NULL, io, "File");
|
||||
PkHandle* cls_file = pkNewClass(vm, "File", NULL, io, _newFile, _deleteFile);
|
||||
pkClassAddMethod(vm, cls_file, "open", _fileOpen, -1);
|
||||
pkClassAddMethod(vm, cls_file, "read", _fileRead, 0);
|
||||
pkClassAddMethod(vm, cls_file, "write", _fileWrite, 1);
|
||||
|
@ -127,6 +127,15 @@ typedef PkStringPtr (*pkResolvePathFn) (PKVM* vm, const char* from,
|
||||
// to indicate if it's failed to load the script.
|
||||
typedef PkStringPtr (*pkLoadScriptFn) (PKVM* vm, const char* path);
|
||||
|
||||
// A function callback to allocate and return a new instance of the registered
|
||||
// class. Which will be called when the instance is constructed. The returned/
|
||||
// data is expected to be alive till the delete callback occurs.
|
||||
typedef void* (*pkNewInstanceFn) ();
|
||||
|
||||
// A function callback to de-allocate the aloocated native instance of the
|
||||
// registered class.
|
||||
typedef void (*pkDeleteInstanceFn) (void*);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* POCKETLANG TYPES */
|
||||
/*****************************************************************************/
|
||||
@ -289,8 +298,10 @@ PK_PUBLIC void pkRegisterModule(PKVM* vm, PkHandle* module);
|
||||
|
||||
// Create a new class on the [module] with the [name] and return it.
|
||||
// If the [base_class] is NULL by default it'll set to "Object" class.
|
||||
PK_PUBLIC PkHandle* pkNewClass(PKVM* vm, PkHandle* base_class,
|
||||
PkHandle* module, const char* name);
|
||||
PK_PUBLIC PkHandle* pkNewClass(PKVM* vm, const char* name,
|
||||
PkHandle* base_class, PkHandle* module,
|
||||
pkNewInstanceFn new_fn,
|
||||
pkDeleteInstanceFn delete_fn);
|
||||
|
||||
// Add a native method to the given class. If the [arity] is -1 that means
|
||||
// the method has variadic parameters and use pkGetArgc() to get the argc.
|
||||
|
@ -69,8 +69,10 @@ void pkRegisterModule(PKVM* vm, PkHandle* module) {
|
||||
vmRegisterModule(vm, module_, module_->name);
|
||||
}
|
||||
|
||||
PkHandle* pkNewClass(PKVM* vm, PkHandle* base_class, PkHandle* module,
|
||||
const char* name) {
|
||||
PkHandle* pkNewClass(PKVM* vm, const char* name,
|
||||
PkHandle* base_class, PkHandle* module,
|
||||
pkNewInstanceFn new_fn,
|
||||
pkDeleteInstanceFn delete_fn) {
|
||||
CHECK_NULL(module);
|
||||
CHECK_NULL(name);
|
||||
CHECK_TYPE(module, OBJ_MODULE);
|
||||
@ -84,6 +86,9 @@ PkHandle* pkNewClass(PKVM* vm, PkHandle* base_class, PkHandle* module,
|
||||
Class* class_ = newClass(vm, name, (int)strlen(name),
|
||||
super, (Module*)AS_OBJ(module->value),
|
||||
NULL, NULL);
|
||||
class_->new_fn = new_fn;
|
||||
class_->delete_fn = delete_fn;
|
||||
|
||||
return vmNewHandle(vm, VAR_OBJ(class_));
|
||||
}
|
||||
|
||||
@ -92,9 +97,21 @@ void pkClassAddMethod(PKVM* vm, PkHandle* cls,
|
||||
pkNativeFn fptr, int arity) {
|
||||
CHECK_NULL(cls);
|
||||
CHECK_NULL(fptr);
|
||||
CHECK_TYPE(cls, OBJ_MODULE);
|
||||
CHECK_TYPE(cls, OBJ_CLASS);
|
||||
|
||||
TODO;
|
||||
Class* class_ = (Class*)AS_OBJ(cls->value);
|
||||
|
||||
Function* fn = newFunction(vm, name, (int)strlen(name),
|
||||
class_->owner, true, NULL, NULL);
|
||||
|
||||
// No need to push the function to temp references of the VM
|
||||
// since it's written to the constant pool of the module and the module
|
||||
// won't be garbage collected (class handle has reference to the module).
|
||||
|
||||
Closure* method = newClosure(vm, fn);
|
||||
vmPushTempRef(vm, &method->_super); // method.
|
||||
pkClosureBufferWrite(&class_->methods, vm, method);
|
||||
vmPopTempRef(vm); // method.
|
||||
}
|
||||
|
||||
void* pkGetSelf(const PKVM* vm) {
|
||||
|
@ -94,6 +94,7 @@ DEFINE_BUFFER(Uint, uint32_t)
|
||||
DEFINE_BUFFER(Byte, uint8_t)
|
||||
DEFINE_BUFFER(Var, Var)
|
||||
DEFINE_BUFFER(String, String*)
|
||||
DEFINE_BUFFER(Closure, Closure*)
|
||||
|
||||
void pkByteBufferAddString(pkByteBuffer* self, PKVM* vm, const char* str,
|
||||
uint32_t length) {
|
||||
@ -146,6 +147,13 @@ void markStringBuffer(PKVM* vm, pkStringBuffer* self) {
|
||||
}
|
||||
}
|
||||
|
||||
void markClosureBuffer(PKVM* vm, pkClosureBuffer* self) {
|
||||
if (self == NULL) return;
|
||||
for (uint32_t i = 0; i < self->count; i++) {
|
||||
markObject(vm, &self->data[i]->_super);
|
||||
}
|
||||
}
|
||||
|
||||
static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
|
||||
// TODO: trace here.
|
||||
|
||||
@ -271,6 +279,10 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
|
||||
markObject(vm, &cls->owner->_super);
|
||||
markObject(vm, &cls->ctor->_super);
|
||||
markObject(vm, &cls->name->_super);
|
||||
|
||||
markClosureBuffer(vm, &cls->methods);
|
||||
vm->bytes_allocated += sizeof(Closure) * cls->methods.capacity;
|
||||
|
||||
} break;
|
||||
|
||||
case OBJ_INST:
|
||||
@ -500,10 +512,14 @@ Class* newClass(PKVM* vm, const char* name, int length,
|
||||
|
||||
vmPushTempRef(vm, &cls->_super); // class.
|
||||
|
||||
pkClosureBufferInit(&cls->methods);
|
||||
|
||||
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) {
|
||||
@ -523,7 +539,13 @@ Instance* newInstance(PKVM* vm, Class* cls) {
|
||||
Instance* inst = ALLOCATE(vm, Instance);
|
||||
varInitObject(&inst->_super, vm, OBJ_INST);
|
||||
inst->cls = cls;
|
||||
inst->native = NULL;
|
||||
if (cls->new_fn != NULL) {
|
||||
vmPushTempRef(vm, &inst->_super); // inst.
|
||||
inst->native = cls->new_fn();
|
||||
vmPopTempRef(vm); // inst.
|
||||
} else {
|
||||
inst->native = NULL;
|
||||
}
|
||||
return inst;
|
||||
}
|
||||
|
||||
@ -1016,12 +1038,13 @@ void freeObject(PKVM* vm, Object* self) {
|
||||
|
||||
case OBJ_CLASS: {
|
||||
Class* cls = (Class*)self;
|
||||
pkClosureBufferClear(&cls->methods, vm);
|
||||
} break;
|
||||
|
||||
case OBJ_INST: {
|
||||
Instance* inst = (Instance*)self;
|
||||
if (inst->native) {
|
||||
TODO; // Call native clean function.
|
||||
if (inst->cls->delete_fn != NULL) {
|
||||
inst->cls->delete_fn(inst->native);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
@ -200,6 +200,7 @@ DECLARE_BUFFER(Uint, uint32_t)
|
||||
DECLARE_BUFFER(Byte, uint8_t)
|
||||
DECLARE_BUFFER(Var, Var)
|
||||
DECLARE_BUFFER(String, String*)
|
||||
DECLARE_BUFFER(Closure, Closure*)
|
||||
|
||||
// Add all the characters to the buffer, byte buffer can also be used as a
|
||||
// buffer to write string (like a string stream). Note that this will not
|
||||
@ -494,6 +495,15 @@ struct Class {
|
||||
const char* docstring;
|
||||
|
||||
Closure* ctor; //< The constructor function.
|
||||
|
||||
// A buffer of methods of the class.
|
||||
pkClosureBuffer methods;
|
||||
|
||||
// Allocater and de-allocator functions for native types.
|
||||
// For script/ builtin types it'll be NULL.
|
||||
pkNewInstanceFn new_fn;
|
||||
pkDeleteInstanceFn delete_fn;
|
||||
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
Loading…
Reference in New Issue
Block a user