mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-05 20:26:53 +08:00
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)
This commit is contained in:
parent
03bac026ee
commit
1951b3d5f7
186
src/pk_core.c
186
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 */
|
||||
/*****************************************************************************/
|
||||
|
21
src/pk_vm.c
21
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.
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user