Merge pull request #238 from ThakeeNathees/register-builtin

Register builtin function implementation
This commit is contained in:
Thakee Nathees 2022-05-26 11:20:22 +05:30 committed by GitHub
commit fb1e1099c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 60 additions and 15 deletions

View File

@ -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.
}
pkClosureBufferWrite(&class_->methods, 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) {

View File

@ -1506,7 +1506,7 @@ static void _toStringInternal(PKVM* vm, const Var v, pkByteBuffer* buff,
for (uint32_t i = 0; i < str->length; i++) {
char c = str->data[i];
switch (c) {
case '"': pkByteBufferAddString(buff, vm, "\\\"", 2); break;
case '"': pkByteBufferAddString(buff, vm, "\\\"", 2); break;
case '\\': pkByteBufferAddString(buff, vm, "\\\\", 2); break;
case '\n': pkByteBufferAddString(buff, vm, "\\n", 2); break;
case '\r': pkByteBufferAddString(buff, vm, "\\r", 2); break;

View File

@ -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

View File

@ -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).

View File

@ -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

View File

@ -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);