From 1951b3d5f7aeeca5af804095921560d495a1ae5e Mon Sep 17 00:00:00 2001 From: Thakee Nathees Date: Thu, 21 Apr 2022 08:36:37 +0530 Subject: [PATCH] self initialization and constructor calls implemented fibers are moved to builtin class and the fiber module has removed. native docstring support required to move math to cli modules (TODO) --- src/pk_core.c | 186 ++++++++++++++++++------------------------- src/pk_vm.c | 21 ++++- tests/lang/fibers.pk | 23 +++--- 3 files changed, 108 insertions(+), 122 deletions(-) diff --git a/src/pk_core.c b/src/pk_core.c index 456d750..7d200da 100644 --- a/src/pk_core.c +++ b/src/pk_core.c @@ -122,7 +122,7 @@ void* pkGetSelf(const PKVM* vm) { } void pkModuleAddGlobal(PKVM* vm, PkHandle* module, - const char* name, PkHandle* value) { + const char* name, PkHandle* value) { CHECK_TYPE(module, OBJ_MODULE); CHECK_NULL(value); @@ -1120,68 +1120,6 @@ DEF(stdMathRound, RET(VAR_NUM(round(num))); } -// 'Fiber' module methods. -// ----------------------- - -DEF(stdFiberNew, - "new(fn:Closure) -> fiber\n" - "Create and return a new fiber from the given function [fn].") { - - Closure* closure; - if (!validateArgClosure(vm, 1, &closure)) return; - RET(VAR_OBJ(newFiber(vm, closure))); -} - -DEF(stdFiberRun, - "run(fb:Fiber, ...) -> var\n" - "Runs the fiber's function with the provided arguments and returns it's " - "return value or the yielded value if it's yielded.") { - - int argc = ARGC; - if (argc == 0) // Missing the fiber argument. - RET_ERR(newString(vm, "Missing argument - fiber.")); - - Fiber* fb; - if (!validateArgFiber(vm, 1, &fb)) return; - - // Buffer of argument to call vmPrepareFiber(). - Var* args[MAX_ARGC]; - - // ARG(1) is fiber, function arguments are ARG(2), ARG(3), ... ARG(argc). - for (int i = 1; i < argc; i++) { - args[i - 1] = &ARG(i + 1); - } - - // Switch fiber and start execution. - if (vmPrepareFiber(vm, fb, argc - 1, args)) { - ASSERT(fb == vm->fiber, OOPS); - fb->state = FIBER_RUNNING; - } -} - -DEF(stdFiberResume, - "resume(fb:Fiber) -> var\n" - "Resumes a yielded function from a previous call of fiber_run() function. " - "Return it's return value or the yielded value if it's yielded.") { - - int argc = ARGC; - if (argc == 0) // Missing the fiber argument. - RET_ERR(newString(vm, "Expected at least 1 argument(s).")); - if (argc > 2) // Can only accept 1 argument for resume. - RET_ERR(newString(vm, "Expected at most 2 argument(s).")); - - Fiber* fb; - if (!validateArgFiber(vm, 1, &fb)) return; - - Var value = (argc == 1) ? VAR_NULL : ARG(2); - - // Switch fiber and resume execution. - if (vmSwitchFiber(vm, fb, &value)) { - ASSERT(fb == vm->fiber, OOPS); - fb->state = FIBER_RUNNING; - } -} - static void initializeCoreModules(PKVM* vm) { #define MODULE_ADD_FN(module, name, fn, argc) \ moduleAddFunctionInternal(vm, module, name, fn, argc, DOCSTRING(fn)) @@ -1226,54 +1164,35 @@ static void initializeCoreModules(PKVM* vm) { // modify the PI, like in python. moduleAddGlobal(vm, math, "PI", 2, VAR_NUM(M_PI)); - // FIXME: - // Temproarly rename the fiber to move it to the builtin type classes. - NEW_MODULE(fiber, "_Fiber"); - MODULE_ADD_FN(fiber, "new", stdFiberNew, 1); - MODULE_ADD_FN(fiber, "run", stdFiberRun, -1); - MODULE_ADD_FN(fiber, "resume", stdFiberResume, -1); - #undef MODULE_ADD_FN #undef NEW_MODULE } -#undef IS_NUM_BYTE -#undef DOCSTRING -#undef DEF - /*****************************************************************************/ /* BUILTIN CLASS CONSTRUCTORS */ /*****************************************************************************/ -static inline void _setSelf(PKVM* vm, Var value) { - vm->fiber->self = value; -} - -static inline Var _getSelf(PKVM* vm) { - return vm->fiber->self; -} - static void _ctorNull(PKVM* vm) { - _setSelf(vm, VAR_NULL); + RET(VAR_NULL); } static void _ctorBool(PKVM* vm) { - _setSelf(vm, toBool(ARG(1))); + RET(toBool(ARG(1))); } static void _ctorNumber(PKVM* vm) { double value; if (!validateNumeric(vm, ARG(1), &value, "Argument 1")) return; - _setSelf(vm, VAR_NUM(value)); + RET(VAR_NUM(value)); } static void _ctorString(PKVM* vm) { if (!pkCheckArgcRange(vm, ARGC, 0, 1)) return; if (ARGC == 0) { - _setSelf(vm, VAR_OBJ(newStringLength(vm, NULL, 0))); + RET(VAR_OBJ(newStringLength(vm, NULL, 0))); return; } - _setSelf(vm, VAR_OBJ(toString(vm, ARG(1)))); + RET(VAR_OBJ(toString(vm, ARG(1)))); } static void _ctorList(PKVM* vm) { @@ -1283,11 +1202,11 @@ static void _ctorList(PKVM* vm) { listAppend(vm, list, ARG(i + 1)); } vmPopTempRef(vm); // list. - _setSelf(vm, VAR_OBJ(list)); + RET(VAR_OBJ(list)); } static void _ctorMap(PKVM* vm) { - _setSelf(vm, VAR_OBJ(newMap(vm))); + RET(VAR_OBJ(newMap(vm))); } static void _ctorRange(PKVM* vm) { @@ -1295,26 +1214,72 @@ static void _ctorRange(PKVM* vm) { if (!validateNumeric(vm, ARG(1), &from, "Argument 1")) return; if (!validateNumeric(vm, ARG(2), &to, "Argument 2")) return; - _setSelf(vm, VAR_OBJ(newRange(vm, from, to))); + RET(VAR_OBJ(newRange(vm, from, to))); } static void _ctorFiber(PKVM* vm) { Closure* closure; if (!validateArgClosure(vm, 1, &closure)) return; - _setSelf(vm, VAR_OBJ(newFiber(vm, closure))); + RET(VAR_OBJ(newFiber(vm, closure))); } /*****************************************************************************/ /* BUILTIN CLASS METHODS */ /*****************************************************************************/ -static void _listAppend(PKVM* vm) { - Var self = _getSelf(vm); - ASSERT(IS_OBJ_TYPE(self, OBJ_LIST), OOPS); - listAppend(vm, ((List*)AS_OBJ(self)), ARG(1)); - RET(self); +#define SELF (vm->fiber->self) + +DEF(_listAppend, + "List.append(value:var) -> List\n" + "Append the [value] to the list and return the list.") { + + ASSERT(IS_OBJ_TYPE(SELF, OBJ_LIST), OOPS); + + listAppend(vm, ((List*)AS_OBJ(SELF)), ARG(1)); + RET(SELF); } +DEF(_fiberRun, + "Fiber.run(...) -> var\n" + "Runs the fiber's function with the provided arguments and returns it's " + "return value or the yielded value if it's yielded.") { + + ASSERT(IS_OBJ_TYPE(SELF, OBJ_FIBER), OOPS); + Fiber* self = (Fiber*)AS_OBJ(SELF); + + // Buffer of argument to call vmPrepareFiber(). + Var* args[MAX_ARGC]; + + for (int i = 0; i < ARGC; i++) { + args[i] = &ARG(i + 1); + } + + // Switch fiber and start execution. + if (vmPrepareFiber(vm, self, ARGC, args)) { + self->state = FIBER_RUNNING; + } +} + +DEF(_fiberResume, + "Fiber.resume() -> var\n" + "Resumes a yielded function from a previous call of fiber_run() function. " + "Return it's return value or the yielded value if it's yielded.") { + + ASSERT(IS_OBJ_TYPE(SELF, OBJ_FIBER), OOPS); + Fiber* self = (Fiber*)AS_OBJ(SELF); + + if (!pkCheckArgcRange(vm, ARGC, 0, 1)) return; + + Var value = (ARGC == 1) ? ARG(1) : VAR_NULL; + + // Switch fiber and resume execution. + if (vmSwitchFiber(vm, self, &value)) { + self->state = FIBER_RUNNING; + } +} + +#undef SELF + /*****************************************************************************/ /* BUILTIN CLASS INITIALIZATION */ /*****************************************************************************/ @@ -1349,24 +1314,29 @@ static void initializePrimitiveClasses(PKVM* vm) { #undef ADD_CTOR -#define ADD_METHOD(type, name, ptr, arity_) \ - do { \ - Function* fn = newFunction(vm, name, (int)strlen(name), \ - NULL, true, NULL, NULL); \ - fn->native = ptr; \ - fn->arity = arity_; \ - vmPushTempRef(vm, &fn->_super); /* fn. */ \ - pkClosureBufferWrite(&vm->builtin_classes[type]->methods, \ - vm, newClosure(vm, fn)); \ - vmPopTempRef(vm); /* fn. */ \ +#define ADD_METHOD(type, name, ptr, arity_) \ + do { \ + Function* fn = newFunction(vm, name, (int)strlen(name), \ + NULL, true, DOCSTRING(ptr), NULL); \ + fn->native = ptr; \ + fn->arity = arity_; \ + vmPushTempRef(vm, &fn->_super); /* fn. */ \ + pkClosureBufferWrite(&vm->builtin_classes[type]->methods, \ + vm, newClosure(vm, fn)); \ + vmPopTempRef(vm); /* fn. */ \ } while (false) - ADD_METHOD(PK_LIST, "append", _listAppend, 1); + ADD_METHOD(PK_LIST, "append", _listAppend, 1); + ADD_METHOD(PK_FIBER, "run", _fiberRun, -1); + ADD_METHOD(PK_FIBER, "resume", _fiberResume, -1); #undef ADD_METHOD - } +#undef IS_NUM_BYTE +#undef DOCSTRING +#undef DEF + /*****************************************************************************/ /* OPERATORS */ /*****************************************************************************/ diff --git a/src/pk_vm.c b/src/pk_vm.c index 2b9847a..a6242f3 100644 --- a/src/pk_vm.c +++ b/src/pk_vm.c @@ -1087,13 +1087,30 @@ L_do_call: closure = (const Closure*)AS_OBJ(callable); } else if (IS_OBJ_TYPE(callable, OBJ_CLASS)) { - closure = (const Closure*)((Class*)AS_OBJ(callable))->ctor; + Class* cls = (Class*)AS_OBJ(callable); + + // Allocate / create a new self before calling constructor on it. + fiber->self = preConstructSelf(vm, cls); + CHECK_ERROR(); + + closure = (const Closure*)(cls)->ctor; + + // No constructor is defined on the class. Just return self. + if (closure == NULL) { + if (argc != 0) { + String* msg = stringFormat(vm, "Expected exactly 0 argument(s)."); + RUNTIME_ERROR(msg); + } + + *fiber->ret = fiber->self; + fiber->self = VAR_UNDEFINED; + DISPATCH(); + } } else { RUNTIME_ERROR(stringFormat(vm, "$ $(@).", "Expected a callable to " "call, instead got", varTypeName(callable), toString(vm, callable))); - DISPATCH(); } // If we reached here it's a valid callable. diff --git a/tests/lang/fibers.pk b/tests/lang/fibers.pk index 0a6a79a..25f6435 100644 --- a/tests/lang/fibers.pk +++ b/tests/lang/fibers.pk @@ -3,10 +3,8 @@ def f0() yield("yield value") end -import _Fiber - -fiber = _Fiber.new(f0) -yield_value = _Fiber.run(fiber) +fiber = Fiber(f0) +yield_value = fiber.run() assert(yield_value == "yield value") assert(!fiber.is_done) @@ -14,9 +12,10 @@ def f1() assert(yield("y") == "r") yield() end -fiber = _Fiber.new(f1) -assert(_Fiber.run(fiber) == "y") -_Fiber.resume(fiber, "r") + +fiber = Fiber(f1) +assert(fiber.run() == "y") +fiber.resume("r") assert(!fiber.is_done) def f2(p1, p2, p3) @@ -27,11 +26,11 @@ def f2(p1, p2, p3) return p1 + p2 * p3 end -fiber = _Fiber.new(f2) -p3 = _Fiber.run(fiber, 1, 2, 3); assert(p3 == 3) -p2 = _Fiber.resume(fiber, 'r1'); assert(p2 == 2) -p1 = _Fiber.resume(fiber, 'r2'); assert(p1 == 1) -pa = _Fiber.resume(fiber, 'r3'); assert(pa == 7) +fiber = Fiber(f2) +p3 = fiber.run(1, 2, 3); assert(p3 == 3) +p2 = fiber.resume('r1'); assert(p2 == 2) +p1 = fiber.resume('r2'); assert(p1 == 1) +pa = fiber.resume('r3'); assert(pa == 7) assert(fiber.is_done) # If we got here, that means all test were passed.