diff --git a/src/debug.c b/src/debug.c index c9e722e..ced513b 100644 --- a/src/debug.c +++ b/src/debug.c @@ -1,7 +1,9 @@ #include +#include #include "debug.h" #include "vm.h" +#include "util.h" void krk_disassembleChunk(FILE * f, KrkFunction * func, const char * name) { KrkChunk * chunk = &func->chunk; @@ -180,3 +182,46 @@ size_t krk_disassembleInstruction(FILE * f, KrkFunction * func, size_t offset) { return offset + size; } +/** + * dis.dis(object) + */ +KRK_FUNC(dis,{ + if (argc < 1) { + krk_runtimeError(vm.exceptions->argumentError, "dis() takes "); + return BOOLEAN_VAL(0); + } + + if (IS_CLOSURE(argv[0])) { + KrkFunction * func = AS_CLOSURE(argv[0])->function; + krk_disassembleChunk(stdout, func, func->name ? func->name->chars : "(unnamed)"); + } else if (IS_BOUND_METHOD(argv[0])) { + if (AS_BOUND_METHOD(argv[0])->method->type == OBJ_CLOSURE) { + KrkFunction * func = ((KrkClosure*)AS_BOUND_METHOD(argv[0])->method)->function; + const char * methodName = func->name ? func->name->chars : "(unnamed)"; + const char * typeName = IS_CLASS(AS_BOUND_METHOD(argv[0])->receiver) ? AS_CLASS(AS_BOUND_METHOD(argv[0])->receiver)->name->chars : krk_typeName(AS_BOUND_METHOD(argv[0])->receiver); + char * tmp = malloc(strlen(methodName) + strlen(typeName) + 2); + sprintf(tmp, "%s.%s", typeName, methodName); + krk_disassembleChunk(stdout, func, tmp); + free(tmp); + } else { + krk_runtimeError(vm.exceptions->typeError, "Can not disassemble built-in method of '%s'", krk_typeName(AS_BOUND_METHOD(argv[0])->receiver)); + } + } else if (IS_CLASS(argv[0])) { + krk_runtimeError(vm.exceptions->typeError, "todo: class disassembly"); + } else { + krk_runtimeError(vm.exceptions->typeError, "Don't know how to disassemble '%s'", krk_typeName(argv[0])); + } + + return NONE_VAL(); +}) + +_noexport +void _createAndBind_disMod(void) { + KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass); + krk_attachNamedObject(&vm.modules, "dis", (KrkObj*)module); + krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("dis")); + krk_attachNamedValue(&module->fields, "__file__", NONE_VAL()); + krk_attachNamedObject(&module->fields, "__doc__", + (KrkObj*)S("Provides tools for disassembling bytecode.")); + BIND_FUNC(module, dis); +} diff --git a/src/debug.h b/src/debug.h index 33cb8df..afeaf69 100644 --- a/src/debug.h +++ b/src/debug.h @@ -7,3 +7,4 @@ extern void krk_disassembleChunk(FILE * f, KrkFunction * func, const char * name); extern size_t krk_disassembleInstruction(FILE * f, KrkFunction * func, size_t offset); extern size_t krk_lineNumber(KrkChunk * chunk, size_t offset); +extern void _createAndBind_disMod(void); diff --git a/src/module_fileio.c b/src/fileio.c similarity index 96% rename from src/module_fileio.c rename to src/fileio.c index a63eeb2..c0c9ef9 100644 --- a/src/module_fileio.c +++ b/src/fileio.c @@ -1,5 +1,5 @@ /** - * Native module for providing access to stdio. + * Provides an interface to C FILE* streams. */ #include #include @@ -462,11 +462,14 @@ KRK_METHOD(Directory,__repr__,{ return OBJECT_VAL(out); }) -KrkValue krk_module_onload_fileio(void) { +_noexport +void _createAndBind_fileioMod(void) { KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass); - /* Store it on the stack for now so we can do stuff that may trip GC - * and not lose it to garbage colletion... */ - krk_push(OBJECT_VAL(module)); + krk_attachNamedObject(&vm.modules, "fileio", (KrkObj*)module); + krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("fileio")); + krk_attachNamedValue(&module->fields, "__file__", NONE_VAL()); + krk_attachNamedObject(&module->fields, "__doc__", + (KrkObj*)S("Provides access to C buffered file I/O functions.")); /* Define a class to represent files. (Should this be a helper method?) */ krk_makeClass(module, &File, "File", vm.baseClasses->objectClass); @@ -511,9 +514,4 @@ KrkValue krk_module_onload_fileio(void) { /* Our base will be the open method */ BIND_FUNC(module,open); BIND_FUNC(module,opendir); - - /* Pop the module object before returning; it'll get pushed again - * by the VM before the GC has a chance to run, so it's safe. */ - assert(AS_INSTANCE(krk_pop()) == module); - return OBJECT_VAL(module); } diff --git a/src/kuroko.c b/src/kuroko.c index 696b4c7..31d71ec 100644 --- a/src/kuroko.c +++ b/src/kuroko.c @@ -465,10 +465,6 @@ _finishArgs: #ifdef BUNDLE_LIBS /* Add any other modules you want to include that are normally built as shared objects. */ - BUNDLED(fileio); - BUNDLED(dis); - BUNDLED(os); - BUNDLED(time); BUNDLED(math); #endif diff --git a/src/module_dis.c b/src/module_dis.c deleted file mode 100644 index 13fcb9e..0000000 --- a/src/module_dis.c +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Currently just dis(). - */ -#include -#include -#include -#include -#include - -#include "vm.h" -#include "value.h" -#include "object.h" -#include "debug.h" - -#define S(c) (krk_copyString(c,sizeof(c)-1)) - -/** - * dis.dis(object) - */ -static KrkValue krk_dis(int argc, KrkValue argv[], int hasKw) { - if (argc < 1) { - krk_runtimeError(vm.exceptions->argumentError, "dis() takes "); - return BOOLEAN_VAL(0); - } - -#ifdef ENABLE_DISASSEMBLY - if (IS_CLOSURE(argv[0])) { - KrkFunction * func = AS_CLOSURE(argv[0])->function; - krk_disassembleChunk(stdout, func, func->name ? func->name->chars : "(unnamed)"); - } else if (IS_BOUND_METHOD(argv[0])) { - if (AS_BOUND_METHOD(argv[0])->method->type == OBJ_CLOSURE) { - KrkFunction * func = ((KrkClosure*)AS_BOUND_METHOD(argv[0])->method)->function; - const char * methodName = func->name ? func->name->chars : "(unnamed)"; - const char * typeName = IS_CLASS(AS_BOUND_METHOD(argv[0])->receiver) ? AS_CLASS(AS_BOUND_METHOD(argv[0])->receiver)->name->chars : krk_typeName(AS_BOUND_METHOD(argv[0])->receiver); - char * tmp = malloc(strlen(methodName) + strlen(typeName) + 2); - sprintf(tmp, "%s.%s", typeName, methodName); - krk_disassembleChunk(stdout, func, tmp); - free(tmp); - } else { - krk_runtimeError(vm.exceptions->typeError, "Can not disassemble built-in method of '%s'", krk_typeName(AS_BOUND_METHOD(argv[0])->receiver)); - } - } else if (IS_CLASS(argv[0])) { - krk_runtimeError(vm.exceptions->typeError, "todo: class disassembly"); - } else { - krk_runtimeError(vm.exceptions->typeError, "Don't know how to disassemble '%s'", krk_typeName(argv[0])); - } -#else - krk_runtimeError(vm.exceptions->typeError, "Kuroko was built with debug methods stripped; disassembly is not available."); -#endif - - return NONE_VAL(); -} - -KrkValue krk_module_onload_dis(void) { - KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass); - krk_push(OBJECT_VAL(module)); - krk_defineNative(&module->fields, "dis", krk_dis); - assert(AS_INSTANCE(krk_pop()) == module); - return OBJECT_VAL(module); -} - diff --git a/src/module_time.c b/src/module_time.c deleted file mode 100644 index e83b3dc..0000000 --- a/src/module_time.c +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Currently just sleep(). - */ -#include -#include -#include -#include -#include -#include - -#include "vm.h" -#include "value.h" -#include "object.h" - -#define S(c) (krk_copyString(c,sizeof(c)-1)) - -/** - * system.sleep(seconds) - */ -static KrkValue _time_sleep(int argc, KrkValue argv[], int hasKw) { - if (argc < 1) { - krk_runtimeError(vm.exceptions->argumentError, "sleep: expect at least one argument."); - return BOOLEAN_VAL(0); - } - - /* Accept an integer or a floating point. Anything else, just ignore. */ - unsigned int usecs = (IS_INTEGER(argv[0]) ? AS_INTEGER(argv[0]) : - (IS_FLOATING(argv[0]) ? AS_FLOATING(argv[0]) : 0)) * - 1000000; - - usleep(usecs); - - return BOOLEAN_VAL(1); -} - -static KrkValue _time_time(int argc, KrkValue argv[], int hasKw) { - time_t out = time(NULL); - return FLOATING_VAL(out); /* TODO actually support subsecond values */ -} - -KrkValue krk_module_onload_time(void) { - KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass); - /* Store it on the stack for now so we can do stuff that may trip GC - * and not lose it to garbage colletion... */ - krk_push(OBJECT_VAL(module)); - - krk_defineNative(&module->fields, "sleep", _time_sleep); - krk_defineNative(&module->fields, "time", _time_time); - - /* Pop the module object before returning; it'll get pushed again - * by the VM before the GC has a chance to run, so it's safe. */ - assert(AS_INSTANCE(krk_pop()) == module); - return OBJECT_VAL(module); -} - diff --git a/src/module_os.c b/src/os.c similarity index 97% rename from src/module_os.c rename to src/os.c index 8d53e5b..30421c0 100644 --- a/src/module_os.c +++ b/src/os.c @@ -1,6 +1,3 @@ -/** - * Currently just uname(). - */ #include #include #include @@ -480,11 +477,14 @@ KRK_FUNC(execvp,{ return krk_runtimeError(OSError, "Expected to not return from exec, but did."); }) -KrkValue krk_module_onload_os(void) { +_noexport +void _createAndBind_osMod(void) { KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass); - /* Store it on the stack for now so we can do stuff that may trip GC - * and not lose it to garbage colletion... */ - krk_push(OBJECT_VAL(module)); + krk_attachNamedObject(&vm.modules, "os", (KrkObj*)module); + krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("os")); + krk_attachNamedValue(&module->fields, "__file__", NONE_VAL()); + krk_attachNamedObject(&module->fields, "__doc__", + (KrkObj*)S("Provides access to low-level system operations.")); #ifdef _WIN32 krk_attachNamedObject(&module->fields, "name", (KrkObj*)S("nt")); @@ -590,11 +590,6 @@ KrkValue krk_module_onload_os(void) { _loadEnviron(module); - - /* Pop the module object before returning; it'll get pushed again - * by the VM before the GC has a chance to run, so it's safe. */ - assert(AS_INSTANCE(krk_pop()) == module); - return OBJECT_VAL(module); } diff --git a/src/time.c b/src/time.c new file mode 100644 index 0000000..fc8093b --- /dev/null +++ b/src/time.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +#include + +#include "vm.h" +#include "value.h" +#include "object.h" +#include "util.h" + +KRK_FUNC(sleep,{ + FUNCTION_TAKES_EXACTLY(1); + + if (!IS_INTEGER(argv[0]) && !IS_FLOATING(argv[0])) { + return TYPE_ERROR(int or float,argv[0]); + } + + unsigned int usecs = (IS_INTEGER(argv[0]) ? AS_INTEGER(argv[0]) : + (IS_FLOATING(argv[0]) ? AS_FLOATING(argv[0]) : 0)) * + 1000000; + + usleep(usecs); + + return BOOLEAN_VAL(1); +}) + +KRK_FUNC(time,{ + FUNCTION_TAKES_NONE(); + time_t out = time(NULL); + return FLOATING_VAL(out); +}) + +_noexport +void _createAndBind_timeMod(void) { + KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass); + krk_attachNamedObject(&vm.modules, "time", (KrkObj*)module); + krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("time")); + krk_attachNamedValue(&module->fields, "__file__", NONE_VAL()); + krk_attachNamedObject(&module->fields, "__doc__", + (KrkObj*)S("Provides timekeeping functions.")); + BIND_FUNC(module,sleep); + BIND_FUNC(module,time); +} + diff --git a/src/vm.c b/src/vm.c index 0e0ee25..63dee33 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1162,6 +1162,10 @@ void krk_initVM(int flags) { _createAndBind_setClass(); _createAndBind_exceptions(); _createAndBind_gcMod(); + _createAndBind_disMod(); + _createAndBind_timeMod(); + _createAndBind_osMod(); + _createAndBind_fileioMod(); #ifdef ENABLE_THREADING _createAndBind_threadsMod(); #endif diff --git a/src/vm.h b/src/vm.h index 575a709..1ef3d8c 100644 --- a/src/vm.h +++ b/src/vm.h @@ -233,6 +233,9 @@ extern void _createAndBind_builtins(void); extern void _createAndBind_type(void); extern void _createAndBind_exceptions(void); extern void _createAndBind_gcMod(void); +extern void _createAndBind_timeMod(void); +extern void _createAndBind_osMod(void); +extern void _createAndBind_fileioMod(void); extern int krk_doRecursiveModuleLoad(KrkString * name); diff --git a/test/testRuntimeException.krk.expect b/test/testRuntimeException.krk.expect index bbf57cd..500fb07 100644 --- a/test/testRuntimeException.krk.expect +++ b/test/testRuntimeException.krk.expect @@ -1,2 +1,2 @@ -oh no! sleep: expect at least one argument. +oh no! sleep() takes exactly 1 argument (0 given) Back from try/except