getMethod and preConstructSelf functions impl

This commit is contained in:
Thakee Nathees 2022-04-20 20:38:23 +05:30
parent 67ab2057c0
commit 167355be59
4 changed files with 205 additions and 2 deletions

View File

@ -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)))

View File

@ -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.

View File

@ -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.

View File

@ -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);