1 #include "Cello/Type.h"
2 
3 #include "Cello/Bool.h"
4 #include "Cello/Exception.h"
5 #include "Cello/Number.h"
6 #include "Cello/String.h"
7 
8 #include <string.h>
9 
10 var Type = type_data {
11   type_begin(Type),
12   type_entry(Type, New),
13   type_entry(Type, AsStr),
14   type_entry(Type, Show),
15   type_end(Type),
16 };
17 
Type_Cast(var obj,var t,const char * func,const char * file,int line)18 var Type_Cast(var obj, var t, const char* func, const char* file, int line) {
19 
20   if (type_of(obj) is t) {
21     return obj;
22   } else {
23     return throw(TypeError,
24       "Argument to function '%s' at '%s:%i' :: "
25       "Got Type '%s' :: "
26       "Expected Type '%s'",
27       $(String, (char*)func), $(String, (char*)file), $(Int, line), type_of(obj), t);
28   }
29 
30 }
31 
Type_New(var self,var_list vl)32 var Type_New(var self, var_list vl) {
33 
34   const char* name = as_str(var_list_get(vl));
35   int count = as_long(var_list_get(vl));
36   var* ifaces = var_list_get(vl);
37   const char** inames = var_list_get(vl);
38 
39   TypeData* newtype = malloc(sizeof(TypeData) * (count + 3));
40 
41   newtype[0].class_object = NULL;
42   newtype[0].class_name = "__Type";
43 
44   newtype[1].class_object = (void*)name;
45   newtype[1].class_name = "__Name";
46 
47   newtype[2].class_object = NULL;
48   newtype[2].class_name = "__Parent";
49 
50   for(int i = 0; i < count; i++) {
51     newtype[3+i].class_object = ifaces[i];
52     newtype[3+i].class_name = inames[i];
53   }
54 
55   return newtype;
56 }
57 
Type_Delete(var self)58 var Type_Delete(var self) {
59   return self;
60 }
61 
Type_Size(void)62 size_t Type_Size(void) {
63   return 0;
64 }
65 
Type_AsStr(var self)66 const char* Type_AsStr(var self) {
67   return type_class(self, __Name);
68 }
69 
Type_Name(var self)70 const char* Type_Name(var self) {
71 
72   TypeData* t = self;
73 
74   while(t->class_name) {
75     if (strcmp(t->class_name, "__Name") == 0) {
76       return t->class_object;
77     }
78     t++;
79   }
80 
81   return throw(ClassError,
82     "Cannot find Class '__Name' for object '%p' :: "
83     "Was is correctly constructed? :: "
84     "Does the data start with a 'type' entry? ::"
85     "Was `type_begin` used?", self);
86 
87 }
88 
Type_Parent(var self)89 var Type_Parent(var self) {
90 
91   TypeData* t = self;
92 
93   while(t->class_name) {
94     if (strcmp(t->class_name, "__Parent") == 0) {
95       return t->class_object;
96     }
97     t++;
98   }
99 
100   return throw(ClassError,
101     "Cannot find Class '__Parent' for object '%p' :: "
102     "Was is correctly constructed? :: "
103     "Does the data start with a 'type' entry? ::"
104     "Was `type_begin` used?", self);
105 
106 }
107 
Type_Implements(var self,const char * class_name,const char * func,const char * file,int line)108 var Type_Implements(var self, const char* class_name, const char* func, const char* file, int line) {
109 
110   TypeData* t = self;
111 
112   if (t[0].class_object != NULL) {
113     return throw(ClassError,
114       "Function '%s' at '%s:%i' :: "
115       "Object '%p' is not a type! :: "
116       "It does not start with a NULL pointer",
117       $(String, (char*)func), $(String, (char*)file), $(Int, line), self);
118   }
119 
120   while(t->class_name) {
121     if (strcmp(t->class_name, class_name) == 0) { return True; }
122     t++;
123   }
124 
125   var parent = Type_Parent(self);
126 
127   return bool_var(parent isnt NULL and Type_Implements(parent, class_name, func, file, line));
128 
129 }
130 
Type_Implements_Method(var self,int offset,const char * class_name,const char * func,const char * file,int line)131 var Type_Implements_Method(var self, int offset, const char* class_name, const char* func, const char* file, int line) {
132 
133   if (not Type_Implements(self, class_name, func, file, line)) {
134 
135     return Type_Implements_Method(Type_Parent(self), offset, class_name, func, file, line);
136 
137   } else {
138 
139     intptr_t* func_address = Type_Class(self, class_name, func, file, line) + offset;
140     return bool_var(*func_address);
141 
142   }
143 
144 }
145 
Type_Class(var self,const char * class_name,const char * func,const char * file,int line)146 var Type_Class(var self, const char* class_name, const char* func, const char* file, int line) {
147   TypeData* t = self;
148 
149   if (t[0].class_object != NULL) {
150     return throw(ClassError,
151       "Function '%s' at '%s:%i' :: "
152       "Object '%p' is not a type! :: "
153       "It does not start with a NULL pointer",
154       $(String, (char*)func), $(String, (char*)file), $(Int, line), self);
155   }
156 
157   while(t->class_name) {
158     if (strcmp(t->class_name, class_name) == 0) {
159       return (var)t->class_object;
160     }
161     t++;
162   }
163 
164   var parent = Type_Parent(self);
165 
166   if (parent isnt NULL and Type_Implements(parent, class_name, func, file, line)) {
167     return Type_Class(parent, class_name, func, file, line);
168   }
169 
170   return throw(ClassError,
171     "Function '%s' at '%s:%i' :: "
172     "Type '%s' does not implement class '%s'",
173     $(String, (char*)func), $(String, (char*)file), $(Int, line),
174     $(String, (char*)Type_Name(self)), $(String, (char*)class_name));
175 
176 }
177 
Type_Class_Method(var self,int offset,const char * class_name,const char * method_name,const char * func,const char * file,int line)178 var Type_Class_Method(var self, int offset, const char* class_name, const char* method_name, const char* func, const char* file, int line) {
179 
180   if (Type_Implements_Method(self, offset, class_name, func, file, line)) {
181     return Type_Class(self, class_name, func, file, line);
182   }
183 
184   var parent = Type_Parent(self);
185 
186   if (Type_Implements_Method(parent, offset, class_name, func, file, line)) {
187     return Type_Class(parent, class_name, func, file, line);
188   }
189 
190   return throw(ClassError,
191     "Function '%s' at '%s:%i' :: "
192     "Type '%s' implements class '%s' but not the specific method '%s' required",
193     $(String, (char*)func), $(String, (char*)file), $(Int, line),
194     self, $(String, (char*)class_name), $(String, (char*)method_name));
195 
196 }
197 
Type_Show(var self,var output,int pos)198 int Type_Show(var self, var output, int pos) {
199   return print_to(output, pos, "%s", self);
200 }
201 
Type_Inherit(var self,var parent)202 void Type_Inherit(var self, var parent) {
203 
204   TypeData* t = self;
205 
206   while(t->class_name) {
207     if (strcmp(t->class_name, "__Parent") == 0) {
208       t->class_object = parent;
209       return;
210     }
211     t++;
212   }
213 
214   throw(ClassError,
215     "Cannot find Class '__Parent' for object '%p' :: "
216     "Was is correctly constructed? :: "
217     "Does the data start with a 'type' entry? ::"
218     "Was `type_begin` used?", self);
219 
220 }
221 
222 
223