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