Merge pull request #244 from ThakeeNathees/relpath-api-change

path library api changes
This commit is contained in:
Thakee Nathees 2022-05-29 19:02:33 +05:30 committed by GitHub
commit b30dfc8e4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 168 additions and 38 deletions

View File

@ -140,14 +140,32 @@ void initializeCore(PKVM* vm) {
initializePrimitiveClasses(vm); initializePrimitiveClasses(vm);
} }
void initializeScript(PKVM* vm, Module* module) { void initializeModule(PKVM* vm, Module* module, bool is_main) {
ASSERT(module->path != NULL, OOPS);
ASSERT(module->path->data[0] != SPECIAL_NAME_CHAR, OOPS); String *path = module->path, *name = NULL;
if (is_main) {
// TODO: consider static string "__main__" stored in PKVM. to reduce
// allocations everytime here.
name = newString(vm, "__main__");
vmPushTempRef(vm, &name->_super); // _main.
} else {
ASSERT(module->name != NULL, OOPS);
name = module->name;
}
ASSERT(name != NULL, OOPS);
// A script's path will always the absolute normalized path (the path // A script's path will always the absolute normalized path (the path
// resolving function would do take care of it) which is something that // resolving function would do take care of it) which is something that
// was added after python 3.9. // was added after python 3.9.
moduleSetGlobal(vm, module, "__file__", 8, VAR_OBJ(module->path)); if (path != NULL) {
moduleSetGlobal(vm, module, "__file__", 8, VAR_OBJ(path));
}
moduleSetGlobal(vm, module, "__name__", 8, VAR_OBJ(name));
if (is_main) vmPopTempRef(vm); // _main.
} }
/*****************************************************************************/ /*****************************************************************************/
@ -233,6 +251,22 @@ static inline bool _callBinaryOpMethod(PKVM* vm, Var self, Var other,
return true; return true;
} }
/*****************************************************************************/
/* REFLECTION AND HELPER FUNCTIONS */
/*****************************************************************************/
// Add all the methods recursively to the lits used for generating a list of
// attributes for the 'dir()' function.
static void _collectMethods(PKVM* vm, List* list, Class* cls) {
if (cls == NULL) return;
for (uint32_t i = 0; i < cls->methods.count; i++) {
listAppend(vm, list,
VAR_OBJ(newString(vm, cls->methods.data[i]->fn->name)));
}
_collectMethods(vm, list, cls->super_class);
}
/*****************************************************************************/ /*****************************************************************************/
/* CORE BUILTIN FUNCTIONS */ /* CORE BUILTIN FUNCTIONS */
/*****************************************************************************/ /*****************************************************************************/
@ -273,18 +307,6 @@ DEF(coreHelp,
} }
} }
// Add all the methods recursively to the lits used for generating a list of
// attributes for the 'dir()' function.
static void _collectMethods(PKVM* vm, List* list, Class* cls) {
if (cls == NULL) return;
for (uint32_t i = 0; i < cls->methods.count; i++) {
listAppend(vm, list,
VAR_OBJ(newString(vm, cls->methods.data[i]->fn->name)));
}
_collectMethods(vm, list, cls->super_class);
}
DEF(coreDir, DEF(coreDir,
"dir(v:var) -> List[String]\n" "dir(v:var) -> List[String]\n"
"It'll return all the elements of the variable [v]. If [v] is a module " "It'll return all the elements of the variable [v]. If [v] is a module "
@ -661,6 +683,7 @@ Module* newModuleInternal(PKVM* vm, const char* name) {
module->initialized = true; module->initialized = true;
vmPopTempRef(vm); // _name vmPopTempRef(vm); // _name
initializeModule(vm, module, false);
return module; return module;
} }
@ -683,7 +706,7 @@ void moduleAddFunctionInternal(PKVM* vm, Module* module,
// 'lang' library methods. // 'lang' library methods.
DEF(stdLangGC, DEF(stdLangGC,
"gc() -> num\n" "lang.gc() -> num\n"
"Trigger garbage collection and return the amount of bytes cleaned.") { "Trigger garbage collection and return the amount of bytes cleaned.") {
size_t bytes_before = vm->bytes_allocated; size_t bytes_before = vm->bytes_allocated;
@ -693,7 +716,7 @@ DEF(stdLangGC,
} }
DEF(stdLangDisas, DEF(stdLangDisas,
"disas(fn:Closure) -> String\n" "lang.disas(fn:Closure) -> String\n"
"Returns the disassembled opcode of the function [fn].") { "Returns the disassembled opcode of the function [fn].") {
// TODO: support dissasemble class constructors and module main body. // TODO: support dissasemble class constructors and module main body.
@ -707,9 +730,73 @@ DEF(stdLangDisas,
dumpFunctionCode(vm, closure->fn); dumpFunctionCode(vm, closure->fn);
} }
DEF(stdLangBackTrace,
"lang.backtrace() -> String\n"
"Returns the backtrace as a string, each line is formated as "
"'<function>;<file>;<line>\n'.") {
// FIXME:
// All of the bellow code were copied from "debug.c" file, consider
// refactor the functionality in a way that it's possible to re use them.
pkByteBuffer bb;
pkByteBufferInit(&bb);
Fiber* fiber = vm->fiber;
ASSERT(fiber != NULL, OOPS);
while (fiber) {
for (int i = fiber->frame_count - 1; i >= 0; i--) {
CallFrame* frame = &fiber->frames[i];
const Function* fn = frame->closure->fn;
// After fetching the instruction the ip will be inceased so we're
// reducing it by 1. But stack overflows are occure before executing
// any instruction of that function, so the instruction_index possibly
// be -1 (set it to zero in that case).
int instruction_index = (int)(frame->ip - fn->fn->opcodes.data) - 1;
if (instruction_index == -1) instruction_index = 0;
int line = fn->fn->oplines.data[instruction_index];
// Note that path can be null.
const char* path = (fn->owner->path) ? fn->owner->path->data : "<?>";
const char* fn_name = (fn->name) ? fn->name : "<?>";
pkByteBufferAddStringFmt(&bb, vm, "%s;%s;%i\n", fn_name, path, line);
}
if (fiber->caller) fiber = fiber->caller;
else fiber = fiber->native;
}
// bb.count not including the null byte and which is the length.
String* bt = newStringLength(vm, bb.data, bb.count);
vmPushTempRef(vm, &bt->_super); // bt.
pkByteBufferClear(&bb, vm);
vmPopTempRef(vm); // bt.
RET(VAR_OBJ(bt));
}
DEF(stdLangModules,
"lang.modules() -> List\n"
"Returns the list of all registered modules.") {
List* list = newList(vm, 8);
vmPushTempRef(vm, &list->_super); // list.
for (uint32_t i = 0; i < vm->modules->capacity; i++) {
if (!IS_UNDEF(vm->modules->entries[i].key)) {
listAppend(vm, list, vm->modules->entries[i].value);
}
}
vmPopTempRef(vm); // list.
RET(VAR_OBJ(list));
}
#ifdef DEBUG #ifdef DEBUG
DEF(stdLangDebugBreak, DEF(stdLangDebugBreak,
"debug_break() -> null\n" "lang.debug_break() -> null\n"
"A debug function for development (will be removed).") { "A debug function for development (will be removed).") {
DEBUG_BREAK(); DEBUG_BREAK();
@ -729,6 +816,8 @@ static void initializeCoreModules(PKVM* vm) {
NEW_MODULE(lang, "lang"); NEW_MODULE(lang, "lang");
MODULE_ADD_FN(lang, "gc", stdLangGC, 0); MODULE_ADD_FN(lang, "gc", stdLangGC, 0);
MODULE_ADD_FN(lang, "disas", stdLangDisas, 1); MODULE_ADD_FN(lang, "disas", stdLangDisas, 1);
MODULE_ADD_FN(lang, "backtrace", stdLangBackTrace, 0);
MODULE_ADD_FN(lang, "modules", stdLangModules, 0);
#ifdef DEBUG #ifdef DEBUG
MODULE_ADD_FN(lang, "debug_break", stdLangDebugBreak, 0); MODULE_ADD_FN(lang, "debug_break", stdLangDebugBreak, 0);
#endif #endif

View File

@ -45,10 +45,14 @@
// Initialize core language, builtin function and core libs. // Initialize core language, builtin function and core libs.
void initializeCore(PKVM* vm); void initializeCore(PKVM* vm);
// Initialize a script module. At the moment it'll define __file__ global // Initialize a module. If the script has path, it'll define __file__ global
// as an absolute path of the script. [path] should be the normalized absolute // as an absolute path of the module. [path] will be the normalized absolute
// path of the script. // path of the module. If the module's path is NULL, it's name is used.
void initializeScript(PKVM* vm, Module* module); //
// Also define __name__ as the name of the module, assuming all the modules
// have name excpet for main which. for main the name will be defined as
// '__main__' just like python.
void initializeModule(PKVM* vm, Module* module, bool is_main);
// Create a new module with the given [name] and returns as a Module*. // Create a new module with the given [name] and returns as a Module*.
// This is function is a wrapper around `newModule()` function to create // This is function is a wrapper around `newModule()` function to create

View File

@ -378,7 +378,7 @@ PkResult pkRunFile(PKVM* vm, const char* path) {
module->path = script_path; module->path = script_path;
vmPopTempRef(vm); // script_path. vmPopTempRef(vm); // script_path.
initializeScript(vm, module); initializeModule(vm, module, true);
const char* _path = module->path->data; const char* _path = module->path->data;
char* source = vm->config.load_script_fn(vm, _path); char* source = vm->config.load_script_fn(vm, _path);
@ -461,6 +461,7 @@ PkResult pkRunREPL(PKVM* vm) {
PkHandle* module = pkNewModule(vm, "@(REPL)"); PkHandle* module = pkNewModule(vm, "@(REPL)");
ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE), OOPS); ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE), OOPS);
Module* _module = (Module*) AS_OBJ(module->value); Module* _module = (Module*) AS_OBJ(module->value);
initializeModule(vm, _module, true);
// A buffer to store multiple lines read from stdin. // A buffer to store multiple lines read from stdin.
pkByteBuffer lines; pkByteBuffer lines;

View File

@ -41,6 +41,22 @@ void pkByteBufferAddString(pkByteBuffer* self, PKVM* vm, const char* str,
} }
} }
void pkByteBufferAddStringFmt(pkByteBuffer* self, PKVM* vm,
const char* fmt, ...) {
va_list args;
va_start(args, fmt);
va_list copy;
va_copy(copy, args);
int length = vsnprintf(NULL, 0, fmt, copy);
va_end(copy);
pkByteBufferReserve(self, vm, self->count + (size_t) length + 1);
vsnprintf(self->data + self->count, self->capacity - self->count, fmt, args);
self->count += length;
va_end(args);
}
void varInitObject(Object* self, PKVM* vm, ObjectType type) { void varInitObject(Object* self, PKVM* vm, ObjectType type) {
self->type = type; self->type = type;
self->is_marked = false; self->is_marked = false;
@ -207,6 +223,7 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
vm->bytes_allocated += sizeof(CallFrame) * fiber->frame_capacity; vm->bytes_allocated += sizeof(CallFrame) * fiber->frame_capacity;
markObject(vm, &fiber->caller->_super); markObject(vm, &fiber->caller->_super);
markObject(vm, &fiber->native->_super);
markObject(vm, &fiber->error->_super); markObject(vm, &fiber->error->_super);
markValue(vm, fiber->self); markValue(vm, fiber->self);

View File

@ -210,6 +210,10 @@ DECLARE_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);
// Add formated string to the byte buffer.
void pkByteBufferAddStringFmt(pkByteBuffer* self, PKVM* vm,
const char* fmt, ...);
// Type enums of the pocketlang heap allocated types. // Type enums of the pocketlang heap allocated types.
typedef enum { typedef enum {
OBJ_STRING = 0, OBJ_STRING = 0,
@ -484,8 +488,11 @@ struct Fiber {
// and reset to VAR_UNDEFINED. // and reset to VAR_UNDEFINED.
Var self; Var self;
// Caller of this fiber if it has one, NULL otherwise. // [caller] is the caller of the fiber that was created by invoking the
Fiber* caller; // pocket concurency model. Where [native] is the native fiber which
// started this fiber. If a native function wants to call pocket function
// it needs to create a new fiber, so we keep track of both.
Fiber *caller, *native;
// Runtime error initially NULL, heap allocated. // Runtime error initially NULL, heap allocated.
String* error; String* error;

View File

@ -319,6 +319,7 @@ PkResult vmCallMethod(PKVM* vm, Var self, Closure* fn,
Fiber* fiber = newFiber(vm, fn); Fiber* fiber = newFiber(vm, fn);
fiber->self = self; fiber->self = self;
fiber->native = vm->fiber;
vmPushTempRef(vm, &fiber->_super); // fiber. vmPushTempRef(vm, &fiber->_super); // fiber.
bool success = vmPrepareFiber(vm, fiber, argc, argv); bool success = vmPrepareFiber(vm, fiber, argc, argv);
@ -436,9 +437,20 @@ Var vmImportModule(PKVM* vm, String* from, String* path) {
// Make a new module, compile and cache it. // Make a new module, compile and cache it.
module = newModule(vm); module = newModule(vm);
module->path = resolved; module->path = resolved;
// FIXME:
// __name__ will contain '/' instead of '.', To fix this I should use
// stringReplace with old = '/', new = '.' and the parameters should be
// string objects which should be allocated in VM statically for single
// char strings.
//
// path here is the imported symbol not the actual path,
// Example: "foo/bar" which was imported as "foo.bar"
module->name = path;
vmPushTempRef(vm, &module->_super); // module. vmPushTempRef(vm, &module->_super); // module.
{ {
initializeScript(vm, module); initializeModule(vm, module, false);
PkResult result = compile(vm, module, source, NULL); PkResult result = compile(vm, module, source, NULL);
pkRealloc(vm, source, 0); pkRealloc(vm, source, 0);
if (result == PK_RESULT_SUCCESS) { if (result == PK_RESULT_SUCCESS) {

View File

@ -241,16 +241,16 @@ DEF(_pathAbspath, "") {
} }
DEF(_pathRelpath, "") { DEF(_pathRelpath, "") {
const char* from, * path; const char* path, * from;
if (!pkValidateSlotString(vm, 1, &from, NULL)) return; if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
if (!pkValidateSlotString(vm, 2, &path, NULL)) return; if (!pkValidateSlotString(vm, 2, &from, NULL)) return;
char abs_from[MAX_PATH_LEN];
pathAbs(from, abs_from, sizeof(abs_from));
char abs_path[MAX_PATH_LEN]; char abs_path[MAX_PATH_LEN];
pathAbs(path, abs_path, sizeof(abs_path)); pathAbs(path, abs_path, sizeof(abs_path));
char abs_from[MAX_PATH_LEN];
pathAbs(from, abs_from, sizeof(abs_from));
char result[MAX_PATH_LEN]; char result[MAX_PATH_LEN];
uint32_t len = (uint32_t) cwk_path_get_relative(abs_from, abs_path, uint32_t len = (uint32_t) cwk_path_get_relative(abs_from, abs_path,
result, sizeof(result)); result, sizeof(result));
@ -278,7 +278,7 @@ DEF(_pathJoin, "") {
pkSetSlotStringLength(vm, 0, result, len); pkSetSlotStringLength(vm, 0, result, len);
} }
DEF(_pathNormalize, "") { DEF(_pathNormpath, "") {
const char* path; const char* path;
if (!pkValidateSlotString(vm, 1, &path, NULL)) return; if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
@ -386,7 +386,7 @@ void registerModulePath(PKVM* vm) {
pkModuleAddFunction(vm, path, "abspath", _pathAbspath, 1); pkModuleAddFunction(vm, path, "abspath", _pathAbspath, 1);
pkModuleAddFunction(vm, path, "relpath", _pathRelpath, 2); pkModuleAddFunction(vm, path, "relpath", _pathRelpath, 2);
pkModuleAddFunction(vm, path, "join", _pathJoin, -1); pkModuleAddFunction(vm, path, "join", _pathJoin, -1);
pkModuleAddFunction(vm, path, "normalize", _pathNormalize, 1); pkModuleAddFunction(vm, path, "normpath", _pathNormpath, 1);
pkModuleAddFunction(vm, path, "basename", _pathBaseName, 1); pkModuleAddFunction(vm, path, "basename", _pathBaseName, 1);
pkModuleAddFunction(vm, path, "dirname", _pathDirName, 1); pkModuleAddFunction(vm, path, "dirname", _pathDirName, 1);
pkModuleAddFunction(vm, path, "isabspath", _pathIsPathAbs, 1); pkModuleAddFunction(vm, path, "isabspath", _pathIsPathAbs, 1);