mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-03-04 13:15:55 +08:00
Merge pull request #238 from ThakeeNathees/register-builtin
Register builtin function implementation
This commit is contained in:
commit
fb1e1099c7
@ -177,6 +177,30 @@ void pkSetUserData(PKVM* vm, void* user_data) {
|
||||
vm->config.user_data = user_data;
|
||||
}
|
||||
|
||||
void pkRegisterBuiltinFn(PKVM* vm, const char* name, pkNativeFn fn,
|
||||
int arity, const char* docstring) {
|
||||
ASSERT(vm->builtins_count < BUILTIN_FN_CAPACITY,
|
||||
"Maximum builtin function limit reached, To increase the limit set "
|
||||
"BUILTIN_FN_CAPACITY and recompile.");
|
||||
|
||||
// TODO: if the functions are sorted, we can do a binary search, but builtin
|
||||
// functions are not searched at runtime, just looked up using it's index
|
||||
// O(1) However it'll decrease the compile time.
|
||||
for (int i = 0; i < vm->builtins_count; i++) {
|
||||
Closure* bfn = vm->builtins_funcs[i];
|
||||
ASSERT(strcmp(bfn->fn->name, name) != 0,
|
||||
"Overriding existing function not supported yet.");
|
||||
}
|
||||
|
||||
Function* fptr = newFunction(vm, name, (int) strlen(name), NULL,
|
||||
true, docstring, NULL);
|
||||
vmPushTempRef(vm, &fptr->_super); // fptr.
|
||||
fptr->native = fn;
|
||||
fptr->arity = arity;
|
||||
vm->builtins_funcs[vm->builtins_count++] = newClosure(vm, fptr);
|
||||
vmPopTempRef(vm); // fptr.
|
||||
}
|
||||
|
||||
PkHandle* pkNewModule(PKVM* vm, const char* name) {
|
||||
CHECK_ARG_NULL(name);
|
||||
Module* module = newModuleInternal(vm, name);
|
||||
@ -260,14 +284,8 @@ void pkClassAddMethod(PKVM* vm, PkHandle* cls,
|
||||
vmPopTempRef(vm); // fn.
|
||||
vmPushTempRef(vm, &method->_super); // method.
|
||||
{
|
||||
if (strcmp(name, CTOR_NAME) == 0) {
|
||||
class_->ctor = method;
|
||||
|
||||
} else {
|
||||
vmPushTempRef(vm, &method->_super); // method.
|
||||
pkClosureBufferWrite(&class_->methods, vm, method);
|
||||
vmPopTempRef(vm); // method.
|
||||
}
|
||||
if (!strcmp(name, CTOR_NAME)) class_->ctor = method;
|
||||
}
|
||||
vmPopTempRef(vm); // method.
|
||||
}
|
||||
@ -670,7 +688,7 @@ bool pkIsSlotInstanceOf(PKVM* vm, int inst, int cls, bool* val) {
|
||||
void pkReserveSlots(PKVM* vm, int count) {
|
||||
if (vm->fiber == NULL) vm->fiber = newFiber(vm, NULL);
|
||||
int needed = (int)(vm->fiber->ret - vm->fiber->stack) + count;
|
||||
vmEnsureStackSize(vm, needed);
|
||||
vmEnsureStackSize(vm, vm->fiber, needed);
|
||||
}
|
||||
|
||||
int pkGetSlotsCount(PKVM* vm) {
|
||||
|
@ -231,6 +231,8 @@ bool vmPrepareFiber(PKVM* vm, Fiber* fiber, int argc, Var* argv) {
|
||||
|
||||
ASSERT(fiber->stack != NULL && fiber->sp == fiber->stack + 1, OOPS);
|
||||
ASSERT(fiber->ret == fiber->stack, OOPS);
|
||||
|
||||
vmEnsureStackSize(vm, fiber, (int) (fiber->sp - fiber->stack) + argc);
|
||||
ASSERT((fiber->stack + fiber->stack_size) - fiber->sp >= argc, OOPS);
|
||||
|
||||
// Pass the function arguments.
|
||||
@ -454,14 +456,13 @@ Var vmImportModule(PKVM* vm, String* from, String* path) {
|
||||
return VAR_OBJ(module);
|
||||
}
|
||||
|
||||
void vmEnsureStackSize(PKVM* vm, int size) {
|
||||
void vmEnsureStackSize(PKVM* vm, Fiber* fiber, int size) {
|
||||
|
||||
if (size >= (MAX_STACK_SIZE / sizeof(Var))) {
|
||||
VM_SET_ERROR(vm, newString(vm, "Maximum stack limit reached."));
|
||||
return;
|
||||
}
|
||||
|
||||
Fiber* fiber = vm->fiber;
|
||||
if (fiber->stack_size >= size) return;
|
||||
|
||||
int new_size = utilPowerOf2Ceil(size);
|
||||
@ -524,7 +525,7 @@ static inline void pushCallFrame(PKVM* vm, const Closure* closure) {
|
||||
// Grow the stack if needed.
|
||||
int current_stack_slots = (int)(vm->fiber->sp - vm->fiber->stack) + 1;
|
||||
int needed = closure->fn->fn->stack_size + current_stack_slots;
|
||||
vmEnsureStackSize(vm, needed);
|
||||
vmEnsureStackSize(vm, vm->fiber, needed);
|
||||
|
||||
CallFrame* frame = vm->fiber->frames + vm->fiber->frame_count++;
|
||||
frame->rbp = vm->fiber->ret;
|
||||
@ -567,7 +568,7 @@ static inline void reuseCallFrame(PKVM* vm, const Closure* closure) {
|
||||
// Grow the stack if needed (least probably).
|
||||
int needed = (closure->fn->fn->stack_size +
|
||||
(int)(vm->fiber->sp - vm->fiber->stack));
|
||||
vmEnsureStackSize(vm, needed);
|
||||
vmEnsureStackSize(vm, vm->fiber, needed);
|
||||
}
|
||||
|
||||
// Capture the [local] into an upvalue and return it. If the upvalue already
|
||||
|
@ -147,7 +147,7 @@ PkHandle* vmNewHandle(PKVM* vm, Var value);
|
||||
|
||||
// If the stack size is less than [size], the stack will grow to keep more
|
||||
// values on it.
|
||||
void vmEnsureStackSize(PKVM* vm, int size);
|
||||
void vmEnsureStackSize(PKVM* vm, Fiber* fiber, int size);
|
||||
|
||||
// Trigger garbage collection. This is an implementation of mark and sweep
|
||||
// garbage collection (https://en.wikipedia.org/wiki/Tracing_garbage_collection).
|
||||
|
@ -212,6 +212,12 @@ PK_PUBLIC void pkSetUserData(PKVM* vm, void* user_data);
|
||||
// Returns the associated user data.
|
||||
PK_PUBLIC void* pkGetUserData(const PKVM* vm);
|
||||
|
||||
// Register a new builtin function with the given [name]. [docstring] could be
|
||||
// NULL or will always valid pointer since PKVM doesn't allocate a string for
|
||||
// docstrings.
|
||||
PK_PUBLIC void pkRegisterBuiltinFn(PKVM* vm, const char* name, pkNativeFn fn,
|
||||
int arity, const char* docstring);
|
||||
|
||||
// Invoke pocketlang's allocator directly. This function should be called
|
||||
// when the host application want to send strings to the PKVM that are claimed
|
||||
// by the VM once the caller returned it. For other uses you **should** call
|
||||
|
@ -402,12 +402,32 @@ DEF(_fileTell, "") {
|
||||
pkSetSlotNumber(vm, 0, (double) ftell(file->fp));
|
||||
}
|
||||
|
||||
// open(path, mode='r') is equal to:
|
||||
//
|
||||
// from io import File
|
||||
// return File().open(path, mode)
|
||||
DEF(_open, NULL /* == _fileOpen */) {
|
||||
|
||||
// slots[1] = path
|
||||
// slots[2] = mode
|
||||
int argc = pkGetArgc(vm);
|
||||
if (!pkCheckArgcRange(vm, argc, 1, 2)) return;
|
||||
if (argc == 1) pkSetSlotString(vm, 2, "r");
|
||||
|
||||
if (!pkImportModule(vm, "io", 0)) return; // slots[0] = io
|
||||
if (!pkGetAttribute(vm, 0, "File", 0)) return; // slots[0] = File
|
||||
if (!pkNewInstance(vm, 0, 0, 0, 0)) return; // slots[0] = File()
|
||||
if (!pkCallMethod(vm, 0, "open", 2, 1, -1)) return; // slots[0] = opened file
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* MODULE REGISTER */
|
||||
/*****************************************************************************/
|
||||
|
||||
void registerModuleIO(PKVM* vm) {
|
||||
|
||||
pkRegisterBuiltinFn(vm, "open", _open, -1, DOCSTRING(_fileOpen));
|
||||
|
||||
PkHandle* io = pkNewModule(vm, "io");
|
||||
|
||||
pkReserveSlots(vm, 2);
|
||||
|
Loading…
Reference in New Issue
Block a user