mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-11 07:00:58 +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;
|
user_data.repl_mode = false;
|
||||||
pkSetUserData(vm, &user_data);
|
pkSetUserData(vm, &user_data);
|
||||||
|
|
||||||
registerModulePath(vm);
|
REGISTER_ALL_MODULES(vm);
|
||||||
//REGISTER_ALL_MODULES(vm);
|
|
||||||
|
|
||||||
PkCompileOptions options = pkNewCompilerOptions();
|
PkCompileOptions options = pkNewCompilerOptions();
|
||||||
options.debug = debug;
|
options.debug = debug;
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
#include "modules.h"
|
#include "modules.h"
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* FILE CLASS */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
// Str | If already exists | If does not exist |
|
// Str | If already exists | If does not exist |
|
||||||
// -----+-------------------+-------------------|
|
// -----+-------------------+-------------------|
|
||||||
// 'r' | read from start | failure to open |
|
// 'r' | read from start | failure to open |
|
||||||
@ -31,26 +35,21 @@ typedef struct {
|
|||||||
bool closed; // True if the file isn't closed yet.
|
bool closed; // True if the file isn't closed yet.
|
||||||
} File;
|
} File;
|
||||||
|
|
||||||
/*****************************************************************************/
|
void* _newFile() {
|
||||||
/* FILE OBJECT OPERATORS */
|
File* file = NEW_OBJ(File);
|
||||||
/*****************************************************************************/
|
file->closed = true;
|
||||||
|
file->mode = FMODE_NONE;
|
||||||
void fileGetAttrib(PKVM* vm, File* file, const char* attrib) {
|
file->fp = NULL;
|
||||||
if (strcmp(attrib, "closed") == 0) {
|
return file;
|
||||||
pkReturnBool(vm, file->closed);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fileSetAttrib(PKVM* vm, File* file, const char* attrib) {
|
void _deleteFile(void* ptr) {
|
||||||
return false;
|
File* file = (File*)ptr;
|
||||||
}
|
|
||||||
|
|
||||||
void fileClean(PKVM* vm, File* file) {
|
|
||||||
if (!file->closed) {
|
if (!file->closed) {
|
||||||
if (fclose(file->fp) != 0) { /* TODO: error! */ }
|
if (fclose(file->fp) != 0) { /* TODO: error! */ }
|
||||||
file->closed = true;
|
file->closed = true;
|
||||||
}
|
}
|
||||||
|
FREE_OBJ(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -171,7 +170,7 @@ static void _fileClose(PKVM* vm) {
|
|||||||
void registerModuleIO(PKVM* vm) {
|
void registerModuleIO(PKVM* vm) {
|
||||||
PkHandle* io = pkNewModule(vm, "io");
|
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, "open", _fileOpen, -1);
|
||||||
pkClassAddMethod(vm, cls_file, "read", _fileRead, 0);
|
pkClassAddMethod(vm, cls_file, "read", _fileRead, 0);
|
||||||
pkClassAddMethod(vm, cls_file, "write", _fileWrite, 1);
|
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.
|
// to indicate if it's failed to load the script.
|
||||||
typedef PkStringPtr (*pkLoadScriptFn) (PKVM* vm, const char* path);
|
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 */
|
/* 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.
|
// 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.
|
// If the [base_class] is NULL by default it'll set to "Object" class.
|
||||||
PK_PUBLIC PkHandle* pkNewClass(PKVM* vm, PkHandle* base_class,
|
PK_PUBLIC PkHandle* pkNewClass(PKVM* vm, const char* name,
|
||||||
PkHandle* module, 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
|
// 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.
|
// 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);
|
vmRegisterModule(vm, module_, module_->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
PkHandle* pkNewClass(PKVM* vm, PkHandle* base_class, PkHandle* module,
|
PkHandle* pkNewClass(PKVM* vm, const char* name,
|
||||||
const char* name) {
|
PkHandle* base_class, PkHandle* module,
|
||||||
|
pkNewInstanceFn new_fn,
|
||||||
|
pkDeleteInstanceFn delete_fn) {
|
||||||
CHECK_NULL(module);
|
CHECK_NULL(module);
|
||||||
CHECK_NULL(name);
|
CHECK_NULL(name);
|
||||||
CHECK_TYPE(module, OBJ_MODULE);
|
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),
|
Class* class_ = newClass(vm, name, (int)strlen(name),
|
||||||
super, (Module*)AS_OBJ(module->value),
|
super, (Module*)AS_OBJ(module->value),
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
class_->new_fn = new_fn;
|
||||||
|
class_->delete_fn = delete_fn;
|
||||||
|
|
||||||
return vmNewHandle(vm, VAR_OBJ(class_));
|
return vmNewHandle(vm, VAR_OBJ(class_));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,9 +97,21 @@ void pkClassAddMethod(PKVM* vm, PkHandle* cls,
|
|||||||
pkNativeFn fptr, int arity) {
|
pkNativeFn fptr, int arity) {
|
||||||
CHECK_NULL(cls);
|
CHECK_NULL(cls);
|
||||||
CHECK_NULL(fptr);
|
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) {
|
void* pkGetSelf(const PKVM* vm) {
|
||||||
|
@ -94,6 +94,7 @@ DEFINE_BUFFER(Uint, uint32_t)
|
|||||||
DEFINE_BUFFER(Byte, uint8_t)
|
DEFINE_BUFFER(Byte, uint8_t)
|
||||||
DEFINE_BUFFER(Var, Var)
|
DEFINE_BUFFER(Var, Var)
|
||||||
DEFINE_BUFFER(String, String*)
|
DEFINE_BUFFER(String, String*)
|
||||||
|
DEFINE_BUFFER(Closure, Closure*)
|
||||||
|
|
||||||
void pkByteBufferAddString(pkByteBuffer* self, PKVM* vm, const char* str,
|
void pkByteBufferAddString(pkByteBuffer* self, PKVM* vm, const char* str,
|
||||||
uint32_t length) {
|
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) {
|
static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
|
||||||
// TODO: trace here.
|
// TODO: trace here.
|
||||||
|
|
||||||
@ -271,6 +279,10 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
|
|||||||
markObject(vm, &cls->owner->_super);
|
markObject(vm, &cls->owner->_super);
|
||||||
markObject(vm, &cls->ctor->_super);
|
markObject(vm, &cls->ctor->_super);
|
||||||
markObject(vm, &cls->name->_super);
|
markObject(vm, &cls->name->_super);
|
||||||
|
|
||||||
|
markClosureBuffer(vm, &cls->methods);
|
||||||
|
vm->bytes_allocated += sizeof(Closure) * cls->methods.capacity;
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case OBJ_INST:
|
case OBJ_INST:
|
||||||
@ -500,10 +512,14 @@ Class* newClass(PKVM* vm, const char* name, int length,
|
|||||||
|
|
||||||
vmPushTempRef(vm, &cls->_super); // class.
|
vmPushTempRef(vm, &cls->_super); // class.
|
||||||
|
|
||||||
|
pkClosureBufferInit(&cls->methods);
|
||||||
|
|
||||||
cls->owner = NULL;
|
cls->owner = NULL;
|
||||||
cls->super_class = super;
|
cls->super_class = super;
|
||||||
cls->docstring = NULL;
|
cls->docstring = NULL;
|
||||||
cls->ctor = NULL;
|
cls->ctor = NULL;
|
||||||
|
cls->new_fn = NULL;
|
||||||
|
cls->delete_fn = NULL;
|
||||||
|
|
||||||
// Builtin types doesn't belongs to a module.
|
// Builtin types doesn't belongs to a module.
|
||||||
if (module != NULL) {
|
if (module != NULL) {
|
||||||
@ -523,7 +539,13 @@ Instance* newInstance(PKVM* vm, Class* cls) {
|
|||||||
Instance* inst = ALLOCATE(vm, Instance);
|
Instance* inst = ALLOCATE(vm, Instance);
|
||||||
varInitObject(&inst->_super, vm, OBJ_INST);
|
varInitObject(&inst->_super, vm, OBJ_INST);
|
||||||
inst->cls = cls;
|
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;
|
return inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1016,12 +1038,13 @@ void freeObject(PKVM* vm, Object* self) {
|
|||||||
|
|
||||||
case OBJ_CLASS: {
|
case OBJ_CLASS: {
|
||||||
Class* cls = (Class*)self;
|
Class* cls = (Class*)self;
|
||||||
|
pkClosureBufferClear(&cls->methods, vm);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case OBJ_INST: {
|
case OBJ_INST: {
|
||||||
Instance* inst = (Instance*)self;
|
Instance* inst = (Instance*)self;
|
||||||
if (inst->native) {
|
if (inst->cls->delete_fn != NULL) {
|
||||||
TODO; // Call native clean function.
|
inst->cls->delete_fn(inst->native);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
@ -200,6 +200,7 @@ DECLARE_BUFFER(Uint, uint32_t)
|
|||||||
DECLARE_BUFFER(Byte, uint8_t)
|
DECLARE_BUFFER(Byte, uint8_t)
|
||||||
DECLARE_BUFFER(Var, Var)
|
DECLARE_BUFFER(Var, Var)
|
||||||
DECLARE_BUFFER(String, String*)
|
DECLARE_BUFFER(String, String*)
|
||||||
|
DECLARE_BUFFER(Closure, Closure*)
|
||||||
|
|
||||||
// Add all the characters to the buffer, byte buffer can also be used as a
|
// 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
|
// buffer to write string (like a string stream). Note that this will not
|
||||||
@ -494,6 +495,15 @@ struct Class {
|
|||||||
const char* docstring;
|
const char* docstring;
|
||||||
|
|
||||||
Closure* ctor; //< The constructor function.
|
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 {
|
typedef struct {
|
||||||
|
Loading…
Reference in New Issue
Block a user