1 /* Common operations. */ 2 3 #include <stdlib.h> 4 #include "ops.h" 5 #include "progconsts.h" 6 #include "progtypes.h" 7 8 extern void __raise_type_error(); 9 extern void __raise_memory_error(); 10 11 /* Direct access and manipulation of static objects. */ 12 13 __attr __load_static(__ref parent, __ref obj) 14 { 15 __attr out = {.context=parent, .value=obj}; 16 return out; 17 } 18 19 /* Direct retrieval operations, returning and setting attributes. */ 20 21 __attr __load_via_object(__ref obj, int pos) 22 { 23 return obj->attrs[pos]; 24 } 25 26 __attr __load_via_class(__ref obj, int pos) 27 { 28 return __load_via_object(__get_class(obj), pos); 29 } 30 31 __attr __get_class_and_load(__ref obj, int pos) 32 { 33 if (__is_instance(obj)) 34 return __load_via_class(obj, pos); 35 else 36 return __load_via_object(obj, pos); 37 } 38 39 /* Direct storage operations. */ 40 41 int __store_via_object(__ref obj, int pos, __attr value) 42 { 43 obj->attrs[pos] = value; 44 return 1; 45 } 46 47 int __get_class_and_store(__ref obj, int pos, __attr value) 48 { 49 /* Forbid class-relative assignments. */ 50 51 __raise_type_error(); 52 return 0; 53 } 54 55 /* Introspection. */ 56 57 int __is_instance(__ref obj) 58 { 59 return obj->pos == __INSTANCEPOS; 60 } 61 62 int __is_type_instance(__ref obj) 63 { 64 return __HASATTR(__get_class(obj), __TYPE_CLASS_POS, __TYPE_CLASS_CODE); 65 } 66 67 __ref __get_class(__ref obj) 68 { 69 return __load_via_object(obj, __pos___class__).value; 70 } 71 72 __attr __get_class_attr(__ref obj) 73 { 74 return __load_via_object(obj, __pos___class__); 75 } 76 77 /* Attribute testing operations. */ 78 79 __ref __test_specific_instance(__ref obj, __ref type) 80 { 81 return __get_class(obj) == type ? obj : 0; 82 } 83 84 __ref __test_specific_object(__ref obj, __ref type) 85 { 86 return __test_specific_type(obj, type) || __test_specific_instance(obj, type) ? obj : 0; 87 } 88 89 __ref __test_specific_type(__ref obj, __ref type) 90 { 91 return obj == type ? obj : 0; 92 } 93 94 __ref __test_common_instance(__ref obj, int pos, int code) 95 { 96 return __HASATTR(__get_class(obj), pos, code) ? obj : 0; 97 } 98 99 __ref __test_common_object(__ref obj, int pos, int code) 100 { 101 return __test_common_type(obj, pos, code) || __test_common_instance(obj, pos, code) ? obj : 0; 102 } 103 104 __ref __test_common_type(__ref obj, int pos, int code) 105 { 106 return __HASATTR(obj, pos, code) ? obj : 0; 107 } 108 109 /* Attribute testing and retrieval operations. */ 110 111 static __attr __check_and_load_via_object_null(__ref obj, int pos, int code) 112 { 113 if (__HASATTR(obj, pos, code)) 114 return __load_via_object(obj, pos); 115 else 116 return __NULL; 117 } 118 119 __attr __check_and_load_via_class(__ref obj, int pos, int code) 120 { 121 return __check_and_load_via_object(__get_class(obj), pos, code); 122 } 123 124 __attr __check_and_load_via_object(__ref obj, int pos, int code) 125 { 126 if (__HASATTR(obj, pos, code)) 127 return __load_via_object(obj, pos); 128 129 __raise_type_error(); 130 return __NULL; 131 } 132 133 __attr __check_and_load_via_any(__ref obj, int pos, int code) 134 { 135 __attr out = __check_and_load_via_object_null(obj, pos, code); 136 if (out.value == 0) 137 out = __check_and_load_via_class(obj, pos, code); 138 return out; 139 } 140 141 /* Attribute testing and storage operations. */ 142 143 int __check_and_store_via_class(__ref obj, int pos, int code, __attr value) 144 { 145 /* Forbid class-relative assignments. */ 146 147 __raise_type_error(); 148 return 0; 149 } 150 151 int __check_and_store_via_object(__ref obj, int pos, int code, __attr value) 152 { 153 if (__HASATTR(obj, pos, code)) 154 { 155 __store_via_object(obj, pos, value); 156 return 1; 157 } 158 159 /* No suitable attribute. */ 160 161 __raise_type_error(); 162 return 0; 163 } 164 165 int __check_and_store_via_any(__ref obj, int pos, int code, __attr value) 166 { 167 if (__check_and_store_via_object(obj, pos, code, value)) 168 return 1; 169 170 /* Forbid class-relative assignments. */ 171 172 __raise_type_error(); 173 return 0; 174 } 175 176 /* Context-related operations. */ 177 178 __attr __test_context(__ref context, __attr attr) 179 { 180 /* Preserve any existing null or instance context. */ 181 182 if ((attr.context == 0) || __is_instance(attr.context)) 183 return attr; 184 185 /* Test any instance context against the context employed by the 186 attribute. */ 187 188 if (__is_instance(context)) 189 if (__test_common_instance(context, __TYPEPOS(attr.context), __TYPECODE(attr.context))) 190 return __replace_context(context, attr); 191 else 192 __raise_type_error(); 193 194 /* Test for access to a type class attribute using a type instance. */ 195 196 if (__test_specific_type(attr.context, &__TYPE_CLASS_TYPE) && __is_type_instance(context)) 197 return __replace_context(context, attr); 198 199 /* Otherwise, preserve the attribute as retrieved. */ 200 201 return attr; 202 } 203 204 __attr __replace_context(__ref context, __attr attr) 205 { 206 __attr out; 207 208 /* Set the context. */ 209 210 out.context = context; 211 212 /* Reference a callable version of the attribute by obtaining the bound 213 method reference from the __fn__ special attribute. */ 214 215 out.value = __load_via_object(attr.value, __ATTRPOS(__fn__)).b; 216 return out; 217 } 218 219 __attr __update_context(__ref context, __attr attr) 220 { 221 __attr out = {context, .fn=attr.fn}; 222 return out; 223 } 224 225 /* Basic structure tests. */ 226 227 int __WITHIN(__ref obj, int pos) 228 { 229 return pos < obj->table->size; 230 } 231 232 int __HASATTR(__ref obj, int pos, int code) 233 { 234 return __WITHIN(obj, pos) && (obj->table->attrs[pos] == code); 235 } 236 237 /* Parameter position operations. */ 238 239 int __HASPARAM(const __ptable *ptable, int ppos, int pcode) 240 { 241 __param param; 242 243 if (ppos < ptable->size) 244 { 245 param = ptable->params[ppos]; 246 if (param.code == pcode) 247 return param.pos; 248 } 249 250 return -1; 251 } 252 253 /* Conversions. */ 254 255 __attr __CONTEXT_AS_VALUE(__attr attr) 256 { 257 __attr out; 258 out.context = attr.context; 259 out.value = attr.context; 260 return out; 261 } 262 263 /* Type testing. */ 264 265 __ref __ISFUNC(__ref obj) 266 { 267 return __test_specific_instance(obj, &__FUNCTION_TYPE); 268 } 269 270 int __ISNULL(__attr value) 271 { 272 /* (value.context == __NULL.context) is superfluous */ 273 return (value.value == 0); /* __NULL.value */ 274 } 275 276 /* Attribute codes and positions for type objects. */ 277 278 unsigned int __TYPECODE(__ref obj) 279 { 280 return obj->table->attrs[obj->pos]; 281 } 282 283 unsigned int __TYPEPOS(__ref obj) 284 { 285 return obj->pos; 286 } 287 288 /* Memory allocation. */ 289 290 void *__ALLOCATE(size_t nmemb, size_t size) 291 { 292 void *ptr = calloc(nmemb, size); 293 if (ptr == NULL) 294 __raise_memory_error(); 295 return ptr; 296 } 297 298 void *__REALLOCATE(void *ptr, size_t size) 299 { 300 void *nptr = realloc(ptr, size); 301 if (nptr == NULL) 302 __raise_memory_error(); 303 return nptr; 304 } 305 306 /* Copying of structures. */ 307 308 __ref __COPY(__ref obj, int size) 309 { 310 __ref copy = (__ref) __ALLOCATE(1, size); 311 memcpy(copy, obj, size); 312 return copy; 313 }