mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-03-04 13:15:55 +08:00
Merge pull request #244 from ThakeeNathees/relpath-api-change
path library api changes
This commit is contained in:
commit
b30dfc8e4f
131
src/core/core.c
131
src/core/core.c
@ -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();
|
||||||
@ -727,8 +814,10 @@ static void initializeCoreModules(PKVM* vm) {
|
|||||||
vmPopTempRef(vm) /* module */
|
vmPopTempRef(vm) /* module */
|
||||||
|
|
||||||
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
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
@ -460,7 +460,8 @@ PkResult pkRunREPL(PKVM* vm) {
|
|||||||
// The main module that'll be used to compile and execute the input source.
|
// The main module that'll be used to compile and execute the input source.
|
||||||
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;
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user