mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-03-04 05:05:57 +08:00
path.listdir, dir functions were added
This commit is contained in:
parent
6308f74f04
commit
9ac483a5b0
@ -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" : (
|
||||||
|
@ -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);
|
||||||
|
@ -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");
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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([[], []]) == "[][]")
|
||||||
|
@ -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
5
tests/modules/path.pk
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import path
|
||||||
|
|
||||||
|
THIS_PATH = path.dirname(__file__)
|
||||||
|
|
||||||
|
assert('path.pk' in path.listdir(THIS_PATH))
|
Loading…
Reference in New Issue
Block a user