From 167355be5952b8c4e3fcc03c80d2f5ef402b70ed Mon Sep 17 00:00:00 2001 From: Thakee Nathees Date: Wed, 20 Apr 2022 20:38:23 +0530 Subject: [PATCH] getMethod and preConstructSelf functions impl --- src/pk_core.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++- src/pk_core.h | 18 ++++++ src/pk_value.c | 23 +++++++ src/pk_value.h | 3 + 4 files changed, 205 insertions(+), 2 deletions(-) diff --git a/src/pk_core.c b/src/pk_core.c index c13fc47..e8bd365 100644 --- a/src/pk_core.c +++ b/src/pk_core.c @@ -1243,7 +1243,66 @@ static void initializeCoreModules(PKVM* vm) { #undef DEF /*****************************************************************************/ -/* PRIMITIVE TYPES CLASS */ +/* BUILTIN CLASS METHODS */ +/*****************************************************************************/ + +static forceinline void _setSelf(PKVM* vm, Var value) { + vm->fiber->frames[vm->fiber->frame_count - 1].self = value; +} + +static void _ctorNull(PKVM* vm) { + _setSelf(vm, VAR_NULL); +} + +static void _ctorBool(PKVM* vm) { + _setSelf(vm, toBool(ARG(1))); +} + +static void _ctorNumber(PKVM* vm) { + double value; + if (!validateNumeric(vm, ARG(1), &value, "Argument 1")) return; + _setSelf(vm, 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))); + return; + } + _setSelf(vm, VAR_OBJ(toString(vm, ARG(1)))); +} + +static void _ctorList(PKVM* vm) { + List* list = newList(vm, ARGC); + vmPushTempRef(vm, &list->_super); // list. + for (int i = 0; i < ARGC; i++) { + listAppend(vm, list, ARG(i + 1)); + } + vmPopTempRef(vm); // list. + _setSelf(vm, VAR_OBJ(list)); +} + +static void _ctorMap(PKVM* vm) { + _setSelf(vm, VAR_OBJ(newMap(vm))); +} + +static void _ctorRange(PKVM* vm) { + double from, to; + 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))); +} + +static void _ctorFiber(PKVM* vm) { + Closure* closure; + if (!validateArgClosure(vm, 1, &closure)) return; + _setSelf(vm, VAR_OBJ(newFiber(vm, closure))); +} + +/*****************************************************************************/ +/* BUILTIN CLASS INITIALIZATION */ /*****************************************************************************/ static void initializePrimitiveClasses(PKVM* vm) { @@ -1255,13 +1314,113 @@ static void initializePrimitiveClasses(PKVM* vm) { super, NULL, NULL, NULL); } - // TODO: Add methods to those classes. +#define ADD_CTOR(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. */ \ + vm->builtin_classes[type]->ctor = newClosure(vm, fn); \ + vmPopTempRef(vm); /* fn. */ \ + } while (false) + + ADD_CTOR(PK_NULL, "@ctorNull", _ctorNull, 0); + ADD_CTOR(PK_BOOL, "@ctorBool", _ctorBool, 1); + ADD_CTOR(PK_NUMBER, "@ctorNumber", _ctorNumber, 1); + ADD_CTOR(PK_STRING, "@ctorString", _ctorString, -1); + ADD_CTOR(PK_LIST, "@ctorList", _ctorList, -1); + ADD_CTOR(PK_MAP, "@ctorMap", _ctorMap, 0); + ADD_CTOR(PK_FIBER, "@ctorFiber", _ctorFiber, 1); + + // TODO: add methods. + } /*****************************************************************************/ /* OPERATORS */ /*****************************************************************************/ +Var preConstructSelf(PKVM* vm, Class* cls) { + +#define NO_INSTANCE(type_name) \ + VM_SET_ERROR(vm, newString(vm, \ + "Class '" type_name "' cannot be instanciated.")) + + for (int i = 0; i < PK_INSTANCE; i++) { + if (vm->builtin_classes[i] == cls) { + + switch ((PkVarType)i) { + case PK_OBJECT: + NO_INSTANCE("Object"); + return VAR_NULL; + + case PK_NULL: + case PK_BOOL: + case PK_NUMBER: + case PK_STRING: + case PK_LIST: + case PK_MAP: + case PK_RANGE: + return VAR_NULL; // Constructor will override the null. + + case PK_MODULE: + NO_INSTANCE("Module"); + return VAR_NULL; + + case PK_CLOSURE: + NO_INSTANCE("Closure"); + return VAR_NULL; + + case PK_FIBER: + return VAR_NULL; + + case PK_CLASS: + NO_INSTANCE("Class"); + return VAR_NULL; + + case PK_INSTANCE: + UNREACHABLE(); + return VAR_NULL; + } + } + } + + return VAR_OBJ(newInstance(vm, cls)); +} + +Class* getClass(PKVM* vm, Var instance) { + PkVarType type = getVarType(instance); + if (0 <= type && type < PK_INSTANCE) { + return vm->builtin_classes[type]; + } + ASSERT(IS_OBJ_TYPE(instance, OBJ_INST), OOPS); + Instance* inst = (Instance*)AS_OBJ(instance); + return inst->cls; +} + +Var getMethod(PKVM* vm, Var self, String* name, bool* is_method) { + + Class* cls = getClass(vm, self); + ASSERT(cls != NULL, OOPS); + + Class* cls_ = cls; + do { + for (int i = 0; i < (int)cls_->methods.count; i++) { + Closure* method = cls_->methods.data[i]; + if (IS_CSTR_EQ(name, method->fn->name, name->length)) { + if (is_method) *is_method = true; + return VAR_OBJ(method); + } + } + cls_ = cls_->super_class; + } while (cls_ != NULL); + + // If the attribute not found it'll set an error. + if (is_method) *is_method = false; + return varGetAttrib(vm, self, name); +} + #define UNSUPPORTED_OPERAND_TYPES(op) \ VM_SET_ERROR(vm, stringFormat(vm, "Unsupported operand types for " \ "operator '" op "' $ and $", varTypeName(v1), varTypeName(v2))) diff --git a/src/pk_core.h b/src/pk_core.h index cfe7fe3..6bf294e 100644 --- a/src/pk_core.h +++ b/src/pk_core.h @@ -17,6 +17,24 @@ void initializeCore(PKVM* vm); /* OPERATORS */ /*****************************************************************************/ +// This method is called just before constructing a type to initialize self +// and after that the constructor will be called. For builtin types this +// function will return VAR_NULL and the constructor will override self to +// it's instance (because for some classes we cannot create without argument +// example Fiber(fn), Range(from, to) etc). If the class cannot be +// instanciated (ex: Class 'Module') it'll set an error and return VAR_NULL. +// For other classes the return value will be an Instance. +Var preConstructSelf(PKVM* vm, Class* cls); + +// Returns the class of the [instance]. +Class* getClass(PKVM* vm, Var instance); + +// Returns the method (closure) in the instance [self]. If it's not an method +// but just an attribute the [is_method] pointer will be set to false and +// returns the value. +// If the method / attribute not found, it'll set a runtime error on the VM. +Var getMethod(PKVM* vm, Var self, String* name, bool* is_method); + Var varAdd(PKVM* vm, Var v1, Var v2); // Returns v1 + v2. Var varSubtract(PKVM* vm, Var v1, Var v2); // Returns v1 - v2. Var varMultiply(PKVM* vm, Var v1, Var v2); // Returns v1 * v2. diff --git a/src/pk_value.c b/src/pk_value.c index 4e31f85..ebfb174 100644 --- a/src/pk_value.c +++ b/src/pk_value.c @@ -536,6 +536,19 @@ Class* newClass(PKVM* vm, const char* name, int length, } Instance* newInstance(PKVM* vm, Class* cls) { + +#ifdef DEBUG + bool _builtin_class = false; + for (int i = 0; i < PK_INSTANCE; i++) { + if (vm->builtin_classes[i] == cls) { + _builtin_class = true; + break; + } + } + ASSERT(!_builtin_class, "Cannot create an instace of builtin class " + "with newInstance() function."); +#endif // DEBUG + Instance* inst = ALLOCATE(vm, Instance); varInitObject(&inst->_super, vm, OBJ_INST); inst->cls = cls; @@ -1272,6 +1285,16 @@ const char* varTypeName(Var v) { return getObjectTypeName(obj->type); } +PkVarType getVarType(Var v) { + if (IS_NULL(v)) return PK_NULL; + if (IS_BOOL(v)) return PK_BOOL; + if (IS_NUM(v)) return PK_NUMBER; + + ASSERT(IS_OBJ(v), OOPS); + Object* obj = AS_OBJ(v); + return getObjPkVarType(obj->type); +} + bool isValuesSame(Var v1, Var v2) { #if VAR_NAN_TAGGING // Bit representation of each values are unique so just compare the bits. diff --git a/src/pk_value.h b/src/pk_value.h index 8858b48..13a6609 100644 --- a/src/pk_value.h +++ b/src/pk_value.h @@ -744,6 +744,9 @@ const char* getObjectTypeName(ObjectType type); // Returns the type name of the var [v]. const char* varTypeName(Var v); +// Returns the PkVarType of the first class varaible [v]. +PkVarType getVarType(Var v); + // Returns true if both variables are the same (ie v1 is v2). bool isValuesSame(Var v1, Var v2);