path.listdir, dir functions were added

This commit is contained in:
Thakee Nathees 2022-05-28 00:37:58 +05:30
parent 6308f74f04
commit 9ac483a5b0
8 changed files with 232 additions and 18 deletions

View File

@ -33,7 +33,7 @@ TEST_SUITE = {
"Modules Test" : ( "Modules Test" : (
"modules/dummy.pk", "modules/dummy.pk",
"modules/math.pk", "modules/math.pk",
"modules/io.File.pk", "modules/io.pk",
), ),
"Random Scripts" : ( "Random Scripts" : (

View File

@ -273,6 +273,87 @@ 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,
"dir(v:var) -> List[String]\n"
"It'll return all the elements of the variable [v]. If [v] is a module "
"it'll return the names of globals, functions, and classes. If it's an "
"instance it'll return all the attributes and methods.") {
Var v = ARG(1);
switch (getVarType(v)) {
case PK_NULL:
case PK_BOOL:
case PK_NUMBER:
case PK_STRING:
case PK_LIST:
case PK_MAP:
case PK_RANGE:
case PK_CLOSURE:
case PK_FIBER: {
List* list = newList(vm, 8);
vmPushTempRef(vm, &list->_super); // list.
_collectMethods(vm, list, getClass(vm, v));
vmPopTempRef(vm); // list.
RET(VAR_OBJ(list));
}
case PK_MODULE: {
Module* m = (Module*) AS_OBJ(v);
List* list = newList(vm, 8);
vmPushTempRef(vm, &list->_super); // list.
for (uint32_t i = 0; i < m->globals.count; i++) {
Var name = m->constants.data[m->global_names.data[i]];
ASSERT(IS_OBJ_TYPE(name, OBJ_STRING), OOPS);
listAppend(vm, list, name);
}
vmPopTempRef(vm); // list.
RET(VAR_OBJ(list));
} break;
case PK_CLASS: {
Class* cls = (Class*) AS_OBJ(v);
List* list = newList(vm, 8);
vmPushTempRef(vm, &list->_super); // list.
_collectMethods(vm, list, cls);
// TODO: if we add static variables to classes it should be
// added here as well.
vmPopTempRef(vm); // list.
RET(VAR_OBJ(list));
} break;
case PK_INSTANCE: {
Instance* inst = (Instance*) AS_OBJ(v);
List* list = newList(vm, 8);
vmPushTempRef(vm, &list->_super); // list.
for (uint32_t i = 0; i < inst->attribs->capacity; i++) {
Var key = (inst->attribs->entries + i)->key;
if (!IS_UNDEF(key)) {
ASSERT(IS_OBJ_TYPE(key, OBJ_STRING), OOPS);
listAppend(vm, list, key);
}
}
_collectMethods(vm, list, inst->cls);
vmPopTempRef(vm); // list.
RET(VAR_OBJ(list));
} break;
}
UNREACHABLE();
}
DEF(coreAssert, DEF(coreAssert,
"assert(condition:bool [, msg:string]) -> void\n" "assert(condition:bool [, msg:string]) -> void\n"
"If the condition is false it'll terminate the current fiber with the " "If the condition is false it'll terminate the current fiber with the "
@ -539,6 +620,7 @@ static void initializeBuiltinFunctions(PKVM* vm) {
(int)strlen(name), argc, fn, DOCSTRING(fn)); (int)strlen(name), argc, fn, DOCSTRING(fn));
// General functions. // General functions.
INITIALIZE_BUILTIN_FN("help", coreHelp, -1); INITIALIZE_BUILTIN_FN("help", coreHelp, -1);
INITIALIZE_BUILTIN_FN("dir", coreDir, 1);
INITIALIZE_BUILTIN_FN("assert", coreAssert, -1); INITIALIZE_BUILTIN_FN("assert", coreAssert, -1);
INITIALIZE_BUILTIN_FN("bin", coreBin, 1); INITIALIZE_BUILTIN_FN("bin", coreBin, 1);
INITIALIZE_BUILTIN_FN("hex", coreHex, 1); INITIALIZE_BUILTIN_FN("hex", coreHex, 1);

View File

@ -858,6 +858,74 @@ bool pkNewInstance(PKVM* vm, int cls, int index, int argc, int argv) {
return !VM_HAS_ERROR(vm); return !VM_HAS_ERROR(vm);
} }
void pkNewRange(PKVM* vm, int index, double first, double last) {
CHECK_FIBER_EXISTS(vm);
VALIDATE_SLOT_INDEX(index);
SET_SLOT(index, VAR_OBJ(newRange(vm, first, last)));
}
void pkNewList(PKVM* vm, int index) {
CHECK_FIBER_EXISTS(vm);
VALIDATE_SLOT_INDEX(index);
SET_SLOT(index, VAR_OBJ(newList(vm, 0)));
}
void pkNewMap(PKVM* vm, int index) {
CHECK_FIBER_EXISTS(vm);
VALIDATE_SLOT_INDEX(index);
SET_SLOT(index, VAR_OBJ(newMap(vm)));
}
bool pkListInsert(PKVM* vm, int list, int32_t index, int value) {
CHECK_FIBER_EXISTS(vm);
VALIDATE_SLOT_INDEX(list);
VALIDATE_SLOT_INDEX(value);
ASSERT(IS_OBJ_TYPE(SLOT(list), OBJ_LIST), "Slot value wasn't a List");
List* l = (List*) AS_OBJ(SLOT(list));
if (index < 0) index = l->elements.count + index + 1;
if (index < 0 || (uint32_t) index > l->elements.count) {
VM_SET_ERROR(vm, newString(vm, "Index out of bounds."));
return false;
}
listInsert(vm, l, (uint32_t) index, SLOT(value));
return true;
}
bool pkListPop(PKVM* vm, int list, int32_t index, int popped) {
CHECK_FIBER_EXISTS(vm);
VALIDATE_SLOT_INDEX(list);
if (popped >= 0) VALIDATE_SLOT_INDEX(popped);
ASSERT(IS_OBJ_TYPE(SLOT(list), OBJ_LIST), "Slot value wasn't a List");
List* l = (List*) AS_OBJ(SLOT(list));
if (index < 0) index += l->elements.count;
if (index < 0 || (uint32_t) index >= l->elements.count) {
VM_SET_ERROR(vm, newString(vm, "Index out of bounds."));
return false;
}
Var p = listRemoveAt(vm, l, index);
if (popped >= 0) SET_SLOT(popped, p);
return true;
}
uint32_t pkListLength(PKVM* vm, int list) {
CHECK_FIBER_EXISTS(vm);
VALIDATE_SLOT_INDEX(list);
ASSERT(IS_OBJ_TYPE(SLOT(list), OBJ_LIST), "Slot value wasn't a List");
List* l = (List*)AS_OBJ(SLOT(list));
return l->elements.count;
}
bool pkCallFunction(PKVM* vm, int fn, int argc, int argv, int ret) { bool pkCallFunction(PKVM* vm, int fn, int argc, int argv, int ret) {
CHECK_FIBER_EXISTS(vm); CHECK_FIBER_EXISTS(vm);
ASSERT(IS_OBJ_TYPE(SLOT(fn), OBJ_CLOSURE), "Slot value wasn't a function"); ASSERT(IS_OBJ_TYPE(SLOT(fn), OBJ_CLOSURE), "Slot value wasn't a function");

View File

@ -391,24 +391,9 @@ PK_PUBLIC void pkSetSlotHandle(PKVM* vm, int index, PkHandle* handle);
/* POCKET FFI */ /* POCKET FFI */
/*****************************************************************************/ /*****************************************************************************/
// Get the attribute with [name] of the instance at the [instance] slot and
// place it at the [index] slot. Return true on success.
PK_PUBLIC bool pkGetAttribute(PKVM* vm, int instance, const char* name,
int index);
// Set the attribute with [name] of the instance at the [instance] slot to
// the value at the [value] index slot. Return true on success.
PK_PUBLIC bool pkSetAttribute(PKVM* vm, int instance,
const char* name, int value);
// Place the [self] instance at the [index] slot. // Place the [self] instance at the [index] slot.
PK_PUBLIC void pkPlaceSelf(PKVM* vm, int index); PK_PUBLIC void pkPlaceSelf(PKVM* vm, int index);
// Import a module with the [path] and place it at [index] slot. The path
// sepearation should be '/'. Example: to import module "foo.bar" the [path]
// should be "foo/bar". On failure, it'll set an error and return false.
PK_PUBLIC bool pkImportModule(PKVM* vm, const char* path, int index);
// Set the [index] slot's value as the class of the [instance]. // Set the [index] slot's value as the class of the [instance].
PK_PUBLIC void pkGetClass(PKVM* vm, int instance, int index); PK_PUBLIC void pkGetClass(PKVM* vm, int instance, int index);
@ -420,6 +405,29 @@ PK_PUBLIC void pkGetClass(PKVM* vm, int instance, int index);
// is the first argument slot's index. // is the first argument slot's index.
PK_PUBLIC bool pkNewInstance(PKVM* vm, int cls, int index, int argc, int argv); PK_PUBLIC bool pkNewInstance(PKVM* vm, int cls, int index, int argc, int argv);
// Create a new Range object and place it at [index] slot.
PK_PUBLIC void pkNewRange(PKVM* vm, int index, double first, double last);
// Create a new List object and place it at [index] slot.
PK_PUBLIC void pkNewList(PKVM* vm, int index);
// Create a new Map object and place it at [index] slot.
PK_PUBLIC void pkNewMap(PKVM* vm, int index);
// Insert [value] to the [list] at the [index], if the index is less than zero,
// it'll count from backwards. ie. insert[-1] == insert[list.length].
// Note that slot [list] must be a valid list otherwise it'll fail an
// assertion.
PK_PUBLIC bool pkListInsert(PKVM* vm, int list, int32_t index, int value);
// Pop an element from [list] at [index] and place it at the [popped] slot, if
// [popped] is negative, the popped value will be ignored.
PK_PUBLIC bool pkListPop(PKVM* vm, int list, int32_t index, int popped);
// Returns the length of the list at the [list] slot, it the slot isn't a list
// an assertion will fail.
PK_PUBLIC uint32_t pkListLength(PKVM* vm, int list);
// Calls a function at the [fn] slot, with [argc] argument where [argv] is the // Calls a function at the [fn] slot, with [argc] argument where [argv] is the
// slot of the first argument. [ret] is the slot index of the return value. if // slot of the first argument. [ret] is the slot index of the return value. if
// [ret] < 0 the return value will be discarded. // [ret] < 0 the return value will be discarded.
@ -431,6 +439,21 @@ PK_PUBLIC bool pkCallFunction(PKVM* vm, int fn, int argc, int argv, int ret);
PK_PUBLIC bool pkCallMethod(PKVM* vm, int instance, const char* method, PK_PUBLIC bool pkCallMethod(PKVM* vm, int instance, const char* method,
int argc, int argv, int ret); int argc, int argv, int ret);
// Get the attribute with [name] of the instance at the [instance] slot and
// place it at the [index] slot. Return true on success.
PK_PUBLIC bool pkGetAttribute(PKVM* vm, int instance, const char* name,
int index);
// Set the attribute with [name] of the instance at the [instance] slot to
// the value at the [value] index slot. Return true on success.
PK_PUBLIC bool pkSetAttribute(PKVM* vm, int instance,
const char* name, int value);
// Import a module with the [path] and place it at [index] slot. The path
// sepearation should be '/'. Example: to import module "foo.bar" the [path]
// should be "foo/bar". On failure, it'll set an error and return false.
PK_PUBLIC bool pkImportModule(PKVM* vm, const char* path, int index);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif

View File

@ -339,6 +339,37 @@ DEF(_pathIsDir, "") {
pkSetSlotBool(vm, 0, pathIsDir(path)); pkSetSlotBool(vm, 0, pathIsDir(path));
} }
DEF(_pathListDir, "") {
int argc = pkGetArgc(vm);
if (!pkCheckArgcRange(vm, argc, 0, 1)) return;
const char* path = ".";
if (argc == 1) if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
if (!pathIsExists(path)) {
pkSetRuntimeErrorFmt(vm, "Path '%s' does not exists.", path);
return;
}
// We create a new list at slot[0] and use slot[1] as our working memory
// overriding our parameter.
pkNewList(vm, 0);
DIR* dirstream = opendir(path);
if (dirstream) {
struct dirent* dir;
while ((dir = readdir(dirstream)) != NULL) {
if (!strcmp(dir->d_name, ".")) continue;
if (!strcmp(dir->d_name, "..")) continue;
pkSetSlotString(vm, 1, dir->d_name);
if (!pkListInsert(vm, 0, -1, 1)) return;
}
closedir(dirstream);
}
}
/*****************************************************************************/ /*****************************************************************************/
/* MODULE REGISTER */ /* MODULE REGISTER */
/*****************************************************************************/ /*****************************************************************************/
@ -358,6 +389,7 @@ void registerModulePath(PKVM* vm) {
pkModuleAddFunction(vm, path, "exists", _pathExists, 1); pkModuleAddFunction(vm, path, "exists", _pathExists, 1);
pkModuleAddFunction(vm, path, "isfile", _pathIsFile, 1); pkModuleAddFunction(vm, path, "isfile", _pathIsFile, 1);
pkModuleAddFunction(vm, path, "isdir", _pathIsDir, 1); pkModuleAddFunction(vm, path, "isdir", _pathIsDir, 1);
pkModuleAddFunction(vm, path, "listdir", _pathListDir, -1);
pkRegisterModule(vm, path); pkRegisterModule(vm, path);
pkReleaseHandle(vm, path); pkReleaseHandle(vm, path);

View File

@ -1,6 +1,9 @@
## TODO: add more test of built in functions. ## TODO: add more test of built in functions.
assert("append" in dir([]))
assert("_repr" in dir(null))
assert(list_join([1, 2, 3]) == "123") assert(list_join([1, 2, 3]) == "123")
assert(list_join(["hello", " world"]) == "hello world") assert(list_join(["hello", " world"]) == "hello world")
assert(list_join([[], []]) == "[][]") assert(list_join([[], []]) == "[][]")

View File

@ -16,9 +16,10 @@ def read_file()
'line4 : qux\n', 'line4 : qux\n',
] ]
line = '' line = ''; i = 0
while line = f.getline() while line = f.getline()
assert(line in LINES) assert(LINES[i] == line)
i += 1
end end
f.close() f.close()

5
tests/modules/path.pk Normal file
View File

@ -0,0 +1,5 @@
import path
THIS_PATH = path.dirname(__file__)
assert('path.pk' in path.listdir(THIS_PATH))