Skip to content

Commit

Permalink
Added support for type parents
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Holden committed Sep 11, 2013
1 parent 19e2ed7 commit 02a55d2
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 52 deletions.
23 changes: 14 additions & 9 deletions include/Cello/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,24 @@ var Type_Delete(var self);
size_t Type_Size(void);

#define cast(X, T) Type_Cast(X, T, __func__, __FILE__, __LINE__)
var Type_Cast(var self, var type, const char* func, const char* file, int line);

#define type_implements(T, C) Type_Implements_Name(T, #C, __func__, __FILE__, __LINE__)
var Type_Implements_Name(var self, const char* class_name, const char* func, const char* file, int line);
#define type_implements(T, C) Type_Implements(T, #C, __func__, __FILE__, __LINE__)
#define type_implements_method(T, C, M) Type_Implements_Method(T, offsetof(C, M), #C, __func__, __FILE__, __LINE__)

#define type_class(T, C) Type_Class(T, #C, __func__, __FILE__, __LINE__)
#define type_class_method(T, C, M, ...) ((C*)Type_Class_Method(T, offsetof(C, M), #C, #M, __func__, __FILE__, __LINE__))->M(__VA_ARGS__)

var Type_Cast(var self, var type, const char* func, const char* file, int line);

#define type_implements_method(T, C, M) Type_Implements_Method_Name(T, offsetof(C, M), #C, __func__, __FILE__, __LINE__)
var Type_Implements_Method_Name(var self, int offset, const char* class_name, const char* func, const char* file, int line);
var Type_Implements(var self, const char* class_name, const char* func, const char* file, int line);
var Type_Implements_Method(var self, int offset, const char* class_name, const char* func, const char* file, int line);

#define type_class(T, C) Type_Class_Name(T, #C, __func__, __FILE__, __LINE__)
var Type_Class_Name(var self, const char* class_name, const char* func, const char* file, int line);
var Type_Class(var self, const char* class_name, const char* func, const char* file, int line);
var Type_Class_Method(var self, int offset, const char* class_name, const char* method_name, const char* func, const char* file, int line);

#define type_class_method(T, C, M, ...) ((C*)Type_Class_Name_Method(T, ((C*)type_class(T, C))->M, #C, #M, __func__, __FILE__, __LINE__))->M(__VA_ARGS__)
var Type_Class_Name_Method(var self, var method, const char* class_name, const char* method_name, const char* func, const char* file, int line);
const char* Type_Name(var self);
var Type_Parent(var self);
void Type_Inherit(var self, var parent);

const char* Type_AsStr(var self);
int Type_Show(var self, var output, int pos);
Expand Down
147 changes: 104 additions & 43 deletions src/Type.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,20 @@ var Type_New(var self, var_list vl) {
var* ifaces = var_list_get(vl);
const char** inames = var_list_get(vl);

TypeData* newtype = malloc(sizeof(TypeData) * (count + 2));
TypeData* newtype = malloc(sizeof(TypeData) * (count + 3));

newtype[0].class_object = NULL;
newtype[0].class_name = "__Type";

newtype[1].class_object = (void*)name;
newtype[1].class_name = "__Name";

newtype[2].class_object = NULL;
newtype[2].class_name = "__Parent";

for(int i = 0; i < count; i++) {
newtype[2+i].class_object = ifaces[i];
newtype[2+i].class_name = inames[i];
newtype[3+i].class_object = ifaces[i];
newtype[3+i].class_name = inames[i];
}

return newtype;
Expand All @@ -64,7 +67,46 @@ const char* Type_AsStr(var self) {
return type_class(self, __Name);
}

var Type_Implements_Name(var self, const char* class_name, const char* func, const char* file, int line) {
const char* Type_Name(var self) {

TypeData* t = self;

while(t->class_name) {
if (strcmp(t->class_name, "__Name") == 0) {
return t->class_object;
}
t++;
}

return throw(ClassError,
"Cannot find Class '__Name' for object '%p' :: "
"Was is correctly constructed? :: "
"Does the data start with a 'type' entry? ::"
"Was `type_begin` used?", self);

}

var Type_Parent(var self) {

TypeData* t = self;

while(t->class_name) {
if (strcmp(t->class_name, "__Parent") == 0) {
return t->class_object;
}
t++;
}

return throw(ClassError,
"Cannot find Class '__Parent' for object '%p' :: "
"Was is correctly constructed? :: "
"Does the data start with a 'type' entry? ::"
"Was `type_begin` used?", self);

}

var Type_Implements(var self, const char* class_name, const char* func, const char* file, int line) {

TypeData* t = self;

if (t[0].class_object != NULL) {
Expand All @@ -76,25 +118,32 @@ var Type_Implements_Name(var self, const char* class_name, const char* func, con
}

while(t->class_name) {
if (strcmp(t->class_name, class_name) == 0) return True;
if (strcmp(t->class_name, class_name) == 0) { return True; }
t++;
}

return False;
var parent = Type_Parent(self);

return bool_var(parent isnt NULL and Type_Implements(parent, class_name, func, file, line));

}

var Type_Implements_Method_Name(var self, int offset, const char* class_name, const char* func, const char* file, int line) {
var Type_Implements_Method(var self, int offset, const char* class_name, const char* func, const char* file, int line) {

if (not Type_Implements_Name(self, class_name, func, file, line)) {
return False;
if (not Type_Implements(self, class_name, func, file, line)) {

return Type_Implements_Method(Type_Parent(self), offset, class_name, func, file, line);

} else {
intptr_t* func_address = Type_Class_Name(self, class_name, func, file, line) + offset;

intptr_t* func_address = Type_Class(self, class_name, func, file, line) + offset;
return bool_var(*func_address);

}

}

var Type_Class_Name(var self, const char* class_name, const char* func, const char* file, int line) {
var Type_Class(var self, const char* class_name, const char* func, const char* file, int line) {
TypeData* t = self;

if (t[0].class_object != NULL) {
Expand All @@ -105,57 +154,69 @@ var Type_Class_Name(var self, const char* class_name, const char* func, const ch
$(String, (char*)func), $(String, (char*)file), $(Int, line), self);
}

const char* type_name = NULL;

while(t->class_name) {
if (strcmp(t->class_name, "__Name") == 0) {
type_name = t->class_object;
}
if (strcmp(t->class_name, class_name) == 0) {
return (var)t->class_object;
}
t++;
}

if (type_name == NULL) {
var parent = Type_Parent(self);

return throw(ClassError,
"Function '%s' at '%s:%i' :: "
"Cannot find class '__Name' for object '%p' :: "
"Was is correctly Constructed? :: "
"Does it start with a 'type' entry? ::"
"Was `methods_begin` used?",
$(String, (char*)func), $(String, (char*)file), $(Int, line), self);

} else {

return throw(ClassError,
"Function '%s' at '%s:%i' :: "
"Type '%s' does not implement class '%s'",
$(String, (char*)func), $(String, (char*)file), $(Int, line),
$(String, (char*)type_name), $(String, (char*)class_name));

if (parent isnt NULL and Type_Implements(parent, class_name, func, file, line)) {
return Type_Class(parent, class_name, func, file, line);
}

return throw(ClassError,
"Function '%s' at '%s:%i' :: "
"Type '%s' does not implement class '%s'",
$(String, (char*)func), $(String, (char*)file), $(Int, line),
$(String, (char*)Type_Name(self)), $(String, (char*)class_name));

}

var Type_Class_Name_Method(var self, var method, const char* class_name, const char* method_name, const char* func, const char* file, int line) {
var Type_Class_Method(var self, int offset, const char* class_name, const char* method_name, const char* func, const char* file, int line) {

var c = Type_Class_Name(self, class_name, func, file, line);
if (Type_Implements_Method(self, offset, class_name, func, file, line)) {
return Type_Class(self, class_name, func, file, line);
}

if (method == NULL) {
return throw(ClassError,
"Function '%s' at '%s:%i' :: "
"Type '%s' implements class '%s' but not the specific method '%s' required",
$(String, (char*)func), $(String, (char*)file), $(Int, line),
self, $(String, (char*)class_name), $(String, (char*)method_name));
} else {
return c;
var parent = Type_Parent(self);

if (Type_Implements_Method(parent, offset, class_name, func, file, line)) {
return Type_Class(parent, class_name, func, file, line);
}

return throw(ClassError,
"Function '%s' at '%s:%i' :: "
"Type '%s' implements class '%s' but not the specific method '%s' required",
$(String, (char*)func), $(String, (char*)file), $(Int, line),
self, $(String, (char*)class_name), $(String, (char*)method_name));

}

int Type_Show(var self, var output, int pos) {
return print_to(output, pos, "%s", self);
}

void Type_Inherit(var self, var parent) {

TypeData* t = self;

while(t->class_name) {
if (strcmp(t->class_name, "__Parent") == 0) {
t->class_object = parent;
return;
}
t++;
}

throw(ClassError,
"Cannot find Class '__Parent' for object '%p' :: "
"Was is correctly constructed? :: "
"Does the data start with a 'type' entry? ::"
"Was `type_begin` used?", self);

}


40 changes: 40 additions & 0 deletions tests/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,28 @@ local var TestType_Eq(var self, var obj) {
instance(TestType, New) = { TestType_New, TestType_Delete, TestType_Size };
instance(TestType, Eq) = { TestType_Eq };

class {
var (*return_true)(var);
} ReturnTrue;

local var return_true(var self) {
return type_class_method(self, ReturnTrue, return_true, self);
}

global var IntParent;

local var IntParent_ReturnTrue(var self) {
return True;
}

instance(IntParent, ReturnTrue) = { IntParent_ReturnTrue };

var IntParent = type_data {
type_begin(IntParent),
type_entry(IntParent, ReturnTrue),
type_end(IntParent),
};

PT_SUITE(suite_core) {

PT_TEST(test_type) {
Expand Down Expand Up @@ -509,6 +531,24 @@ PT_SUITE(suite_core) {

}

PT_TEST(test_type_parent) {

PT_ASSERT(not type_implements(Int, ReturnTrue));
PT_ASSERT(not type_implements(Real, ReturnTrue));
PT_ASSERT(type_implements(IntParent, ReturnTrue));

PT_ASSERT(return_true(IntParent));

Type_Inherit(Int, IntParent);

PT_ASSERT(type_implements(Int, ReturnTrue));
PT_ASSERT(not type_implements(Real, ReturnTrue));
PT_ASSERT(type_implements(IntParent, ReturnTrue));

PT_ASSERT(return_true(Int));

}

PT_TEST(test_show) {

var out = new(String, $(String, ""));
Expand Down

0 comments on commit 02a55d2

Please sign in to comment.