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;
|
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) {
|
PkHandle* pkNewModule(PKVM* vm, const char* name) {
|
||||||
CHECK_ARG_NULL(name);
|
CHECK_ARG_NULL(name);
|
||||||
Module* module = newModuleInternal(vm, name);
|
Module* module = newModuleInternal(vm, name);
|
||||||
@ -260,14 +284,8 @@ void pkClassAddMethod(PKVM* vm, PkHandle* cls,
|
|||||||
vmPopTempRef(vm); // fn.
|
vmPopTempRef(vm); // fn.
|
||||||
vmPushTempRef(vm, &method->_super); // method.
|
vmPushTempRef(vm, &method->_super); // method.
|
||||||
{
|
{
|
||||||
if (strcmp(name, CTOR_NAME) == 0) {
|
pkClosureBufferWrite(&class_->methods, vm, method);
|
||||||
class_->ctor = method;
|
if (!strcmp(name, CTOR_NAME)) class_->ctor = method;
|
||||||
|
|
||||||
} else {
|
|
||||||
vmPushTempRef(vm, &method->_super); // method.
|
|
||||||
pkClosureBufferWrite(&class_->methods, vm, method);
|
|
||||||
vmPopTempRef(vm); // method.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
vmPopTempRef(vm); // method.
|
vmPopTempRef(vm); // method.
|
||||||
}
|
}
|
||||||
@ -670,7 +688,7 @@ bool pkIsSlotInstanceOf(PKVM* vm, int inst, int cls, bool* val) {
|
|||||||
void pkReserveSlots(PKVM* vm, int count) {
|
void pkReserveSlots(PKVM* vm, int count) {
|
||||||
if (vm->fiber == NULL) vm->fiber = newFiber(vm, NULL);
|
if (vm->fiber == NULL) vm->fiber = newFiber(vm, NULL);
|
||||||
int needed = (int)(vm->fiber->ret - vm->fiber->stack) + count;
|
int needed = (int)(vm->fiber->ret - vm->fiber->stack) + count;
|
||||||
vmEnsureStackSize(vm, needed);
|
vmEnsureStackSize(vm, vm->fiber, needed);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pkGetSlotsCount(PKVM* vm) {
|
int pkGetSlotsCount(PKVM* vm) {
|
||||||
|
@ -1506,7 +1506,7 @@ static void _toStringInternal(PKVM* vm, const Var v, pkByteBuffer* buff,
|
|||||||
for (uint32_t i = 0; i < str->length; i++) {
|
for (uint32_t i = 0; i < str->length; i++) {
|
||||||
char c = str->data[i];
|
char c = str->data[i];
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '"': pkByteBufferAddString(buff, vm, "\\\"", 2); break;
|
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 '\n': pkByteBufferAddString(buff, vm, "\\n", 2); break;
|
||||||
case '\r': pkByteBufferAddString(buff, vm, "\\r", 2); break;
|
case '\r': pkByteBufferAddString(buff, vm, "\\r", 2); break;
|
||||||
|
@ -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->stack != NULL && fiber->sp == fiber->stack + 1, OOPS);
|
||||||
ASSERT(fiber->ret == fiber->stack, 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);
|
ASSERT((fiber->stack + fiber->stack_size) - fiber->sp >= argc, OOPS);
|
||||||
|
|
||||||
// Pass the function arguments.
|
// Pass the function arguments.
|
||||||
@ -454,14 +456,13 @@ Var vmImportModule(PKVM* vm, String* from, String* path) {
|
|||||||
return VAR_OBJ(module);
|
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))) {
|
if (size >= (MAX_STACK_SIZE / sizeof(Var))) {
|
||||||
VM_SET_ERROR(vm, newString(vm, "Maximum stack limit reached."));
|
VM_SET_ERROR(vm, newString(vm, "Maximum stack limit reached."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Fiber* fiber = vm->fiber;
|
|
||||||
if (fiber->stack_size >= size) return;
|
if (fiber->stack_size >= size) return;
|
||||||
|
|
||||||
int new_size = utilPowerOf2Ceil(size);
|
int new_size = utilPowerOf2Ceil(size);
|
||||||
@ -524,7 +525,7 @@ static inline void pushCallFrame(PKVM* vm, const Closure* closure) {
|
|||||||
// Grow the stack if needed.
|
// Grow the stack if needed.
|
||||||
int current_stack_slots = (int)(vm->fiber->sp - vm->fiber->stack) + 1;
|
int current_stack_slots = (int)(vm->fiber->sp - vm->fiber->stack) + 1;
|
||||||
int needed = closure->fn->fn->stack_size + current_stack_slots;
|
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++;
|
CallFrame* frame = vm->fiber->frames + vm->fiber->frame_count++;
|
||||||
frame->rbp = vm->fiber->ret;
|
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).
|
// Grow the stack if needed (least probably).
|
||||||
int needed = (closure->fn->fn->stack_size +
|
int needed = (closure->fn->fn->stack_size +
|
||||||
(int)(vm->fiber->sp - vm->fiber->stack));
|
(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
|
// 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
|
// If the stack size is less than [size], the stack will grow to keep more
|
||||||
// values on it.
|
// 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
|
// Trigger garbage collection. This is an implementation of mark and sweep
|
||||||
// garbage collection (https://en.wikipedia.org/wiki/Tracing_garbage_collection).
|
// 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.
|
// Returns the associated user data.
|
||||||
PK_PUBLIC void* pkGetUserData(const PKVM* vm);
|
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
|
// Invoke pocketlang's allocator directly. This function should be called
|
||||||
// when the host application want to send strings to the PKVM that are claimed
|
// 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
|
// 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));
|
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 */
|
/* MODULE REGISTER */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
void registerModuleIO(PKVM* vm) {
|
void registerModuleIO(PKVM* vm) {
|
||||||
|
|
||||||
|
pkRegisterBuiltinFn(vm, "open", _open, -1, DOCSTRING(_fileOpen));
|
||||||
|
|
||||||
PkHandle* io = pkNewModule(vm, "io");
|
PkHandle* io = pkNewModule(vm, "io");
|
||||||
|
|
||||||
pkReserveSlots(vm, 2);
|
pkReserveSlots(vm, 2);
|
||||||
|
Loading…
Reference in New Issue
Block a user