1 /* Common operations. 2 3 Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk> 4 5 This program is free software; you can redistribute it and/or modify it under 6 the terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 3 of the License, or (at your option) any later 8 version. 9 10 This program is distributed in the hope that it will be useful, but WITHOUT 11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 13 details. 14 15 You should have received a copy of the GNU General Public License along with 16 this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include "gc.h" /* GC_MALLOC, GC_REALLOC */ 20 #include "types.h" 21 #include "ops.h" 22 #include "progops.h" /* for raising errors */ 23 #include "progconsts.h" 24 #include "progtypes.h" 25 26 /* Basic structure tests. */ 27 28 static inline int __WITHIN(__ref obj, int pos) 29 { 30 return pos < obj->table->size; 31 } 32 33 static inline int __HASATTR(__ref obj, int pos, int code) 34 { 35 return __WITHIN(obj, pos) && (obj->table->attrs[pos] == code); 36 } 37 38 /* Direct access and manipulation of static objects. */ 39 40 __attr __load_static_ignore(__ref obj) 41 { 42 return (__attr) {.value=obj}; 43 } 44 45 __attr __load_static_replace(__ref context, __ref obj) 46 { 47 return __update_context(context, (__attr) {.value=obj}); 48 } 49 50 __attr __load_static_test(__ref context, __ref obj) 51 { 52 return __test_context(context, (__attr) {.value=obj}); 53 } 54 55 /* Direct retrieval operations, returning and setting attributes. */ 56 57 __attr __load_via_object__(__ref obj, int pos) 58 { 59 return obj->attrs[pos]; 60 } 61 62 __attr __load_via_class__(__ref obj, int pos) 63 { 64 return __load_via_object__(__get_class(obj), pos); 65 } 66 67 __attr __get_class_and_load__(__ref obj, int pos) 68 { 69 if (__is_instance(obj)) 70 return __load_via_class__(obj, pos); 71 else 72 return __load_via_object__(obj, pos); 73 } 74 75 /* Direct storage operations. */ 76 77 int __store_via_object__(__ref obj, int pos, __attr value) 78 { 79 obj->attrs[pos] = value; 80 return 1; 81 } 82 83 int __get_class_and_store__(__ref obj, int pos, __attr value) 84 { 85 /* Forbid class-relative assignments. */ 86 87 __raise_type_error(); 88 return 0; 89 } 90 91 /* Introspection. */ 92 93 int __is_instance(__ref obj) 94 { 95 return obj->pos == __INSTANCEPOS; 96 } 97 98 int __is_subclass(__ref obj, __attr cls) 99 { 100 return __HASATTR(obj, __TYPEPOS(cls.value), __TYPECODE(cls.value)); 101 } 102 103 int __is_instance_subclass(__ref obj, __attr cls) 104 { 105 return __is_instance(obj) && __HASATTR(__get_class(obj), __TYPEPOS(cls.value), __TYPECODE(cls.value)); 106 } 107 108 int __is_type_instance(__ref obj) 109 { 110 return __HASATTR(__get_class(obj), __TYPE_CLASS_POS, __TYPE_CLASS_CODE); 111 } 112 113 __ref __get_class(__ref obj) 114 { 115 return __load_via_object(obj, __class__).value; 116 } 117 118 __attr __get_class_attr(__ref obj) 119 { 120 return __load_via_object(obj, __class__); 121 } 122 123 /* Attribute testing operations. */ 124 125 __ref __test_specific_instance(__ref obj, __ref type) 126 { 127 return __get_class(obj) == type ? obj : 0; 128 } 129 130 __ref __test_specific_object(__ref obj, __ref type) 131 { 132 return __test_specific_type(obj, type) || __test_specific_instance(obj, type) ? obj : 0; 133 } 134 135 __ref __test_specific_type(__ref obj, __ref type) 136 { 137 return obj == type ? obj : 0; 138 } 139 140 __ref __test_common_instance__(__ref obj, int pos, int code) 141 { 142 return __HASATTR(__get_class(obj), pos, code) ? obj : 0; 143 } 144 145 __ref __test_common_object__(__ref obj, int pos, int code) 146 { 147 return __test_common_type__(obj, pos, code) || __test_common_instance__(obj, pos, code) ? obj : 0; 148 } 149 150 __ref __test_common_type__(__ref obj, int pos, int code) 151 { 152 return __HASATTR(obj, pos, code) ? obj : 0; 153 } 154 155 /* Attribute testing and retrieval operations. */ 156 157 __attr __check_and_load_via_object_null(__ref obj, int pos, int code) 158 { 159 if (__HASATTR(obj, pos, code)) 160 return __load_via_object__(obj, pos); 161 else 162 return __NULL; 163 } 164 165 __attr __check_and_load_via_class__(__ref obj, int pos, int code) 166 { 167 return __check_and_load_via_object__(__get_class(obj), pos, code); 168 } 169 170 __attr __check_and_load_via_object__(__ref obj, int pos, int code) 171 { 172 if (__HASATTR(obj, pos, code)) 173 return __load_via_object__(obj, pos); 174 175 __raise_type_error(); 176 return __NULL; 177 } 178 179 __attr __check_and_load_via_any__(__ref obj, int pos, int code) 180 { 181 __attr out = __check_and_load_via_object_null(obj, pos, code); 182 if (out.value == 0) 183 out = __check_and_load_via_class__(obj, pos, code); 184 return out; 185 } 186 187 /* Attribute testing and storage operations. */ 188 189 int __check_and_store_via_class__(__ref obj, int pos, int code, __attr value) 190 { 191 /* Forbid class-relative assignments. */ 192 193 __raise_type_error(); 194 return 0; 195 } 196 197 int __check_and_store_via_object__(__ref obj, int pos, int code, __attr value) 198 { 199 if (__HASATTR(obj, pos, code)) 200 { 201 __store_via_object__(obj, pos, value); 202 return 1; 203 } 204 205 /* No suitable attribute. */ 206 207 __raise_type_error(); 208 return 0; 209 } 210 211 int __check_and_store_via_any__(__ref obj, int pos, int code, __attr value) 212 { 213 if (__check_and_store_via_object__(obj, pos, code, value)) 214 return 1; 215 216 /* Forbid class-relative assignments. */ 217 218 __raise_type_error(); 219 return 0; 220 } 221 222 /* Context-related operations. */ 223 224 int __test_context_update(__ref context, __attr attr) 225 { 226 /* Return whether the context should be updated for the attribute. */ 227 228 __ref attrcontext = __CONTEXT_AS_VALUE(attr).value; 229 230 /* Preserve any existing null or instance context. */ 231 232 if ((attrcontext == 0) || __is_instance(attrcontext)) 233 return 0; 234 235 /* Test any instance context against the context employed by the 236 attribute. */ 237 238 if (__is_instance(context)) 239 { 240 /* Obtain the special class attribute position and code identifying the 241 attribute context's class, inspecting the context instance for 242 compatibility. */ 243 244 if (__test_common_instance__(context, __TYPEPOS(attrcontext), __TYPECODE(attrcontext))) 245 return 1; 246 else 247 __raise_type_error(); 248 } 249 250 /* Test for access to a type class attribute using a type instance. */ 251 252 if (__test_specific_type(attrcontext, &__TYPE_CLASS_TYPE) && __is_type_instance(context)) 253 return 1; 254 255 /* Otherwise, preserve the attribute as retrieved. */ 256 257 return 0; 258 } 259 260 __attr __test_context(__ref context, __attr attr) 261 { 262 /* Update the context or return the unchanged attribute. */ 263 264 if (__test_context_update(context, attr)) 265 return __update_context(context, attr); 266 else 267 return attr; 268 } 269 270 __attr __update_context(__ref context, __attr attr) 271 { 272 return __new_wrapper(context, attr); 273 } 274 275 __attr __test_context_revert(int target, __ref context, __attr attr, __ref contexts[]) 276 { 277 /* Revert the local context to that employed by the attribute if the 278 supplied context is not appropriate. */ 279 280 if (!__test_context_update(context, attr)) 281 contexts[target] = __CONTEXT_AS_VALUE(attr).value; 282 return attr; 283 } 284 285 __attr __test_context_static(int target, __ref context, __ref value, __ref contexts[]) 286 { 287 /* Set the local context to the specified context if appropriate. */ 288 289 if (__test_context_update(context, (__attr) {.value=value})) 290 contexts[target] = context; 291 return (__attr) {.value=value}; 292 } 293 294 /* Context testing for invocations. */ 295 296 int __type_method_invocation(__ref context, __attr target) 297 { 298 __ref targetcontext = __CONTEXT_AS_VALUE(target).value; 299 300 /* Require instances, not classes, where methods are function instances. */ 301 302 if (!__is_instance(target.value)) 303 return 0; 304 305 /* Access the context of the callable and test if it is the type object. */ 306 307 return ((targetcontext != 0) && __test_specific_type(targetcontext, &__TYPE_CLASS_TYPE) && __is_type_instance(context)); 308 } 309 310 __attr __unwrap_callable(__attr callable) 311 { 312 __attr value = __check_and_load_via_object_null(callable.value, __ATTRPOS(__value__), __ATTRCODE(__value__)); 313 return value.value ? value : callable; 314 } 315 316 __attr (*__get_function(__ref context, __attr target))(__attr[]) 317 { 318 /* Require null or instance contexts for functions and methods respectively, 319 or type instance contexts for type methods. */ 320 321 if ((context == 0) || __is_instance(context) || __type_method_invocation(context, target)) 322 return __load_via_object(target.value, __fn__).fn; 323 else 324 return __unbound_method; 325 } 326 327 __attr (*__check_and_get_function(__ref context, __attr target))(__attr[]) 328 { 329 /* Require null or instance contexts for functions and methods respectively, 330 or type instance contexts for type methods. */ 331 332 if ((context == 0) || __is_instance(context) || __type_method_invocation(context, target)) 333 return __check_and_load_via_object__(target.value, __ATTRPOS(__fn__), __ATTRCODE(__fn__)).fn; 334 else 335 return __unbound_method; 336 } 337 338 /* Parameter position operations. */ 339 340 int __HASPARAM(const __ptable *ptable, int ppos, int pcode) 341 { 342 __param param; 343 344 if (ppos < ptable->size) 345 { 346 param = ptable->params[ppos]; 347 if (param.code == pcode) 348 return param.pos; 349 } 350 351 return -1; 352 } 353 354 /* Conversions. */ 355 356 __attr __CONTEXT_AS_VALUE(__attr attr) 357 { 358 return __check_and_load_via_object_null(attr.value, __ATTRPOS(__context__), __ATTRCODE(__context__)); 359 } 360 361 /* Type testing. */ 362 363 __ref __ISFUNC(__ref obj) 364 { 365 return __test_specific_instance(obj, &__FUNCTION_TYPE); 366 } 367 368 int __ISNULL(__attr value) 369 { 370 return (value.value == 0); /* __NULL.value */ 371 } 372 373 /* Attribute codes and positions for type objects. */ 374 375 unsigned int __TYPECODE(__ref obj) 376 { 377 return obj->table->attrs[obj->pos]; 378 } 379 380 unsigned int __TYPEPOS(__ref obj) 381 { 382 return obj->pos; 383 } 384 385 /* Memory allocation. */ 386 387 void *__ALLOCATE(size_t nmemb, size_t size) 388 { 389 void *ptr = GC_MALLOC(nmemb * size); /* sets memory to zero */ 390 if (ptr == NULL) 391 __raise_memory_error(); 392 return ptr; 393 } 394 395 void *__REALLOCATE(void *ptr, size_t size) 396 { 397 void *nptr = GC_REALLOC(ptr, size); 398 if (nptr == NULL) 399 __raise_memory_error(); 400 return nptr; 401 } 402 403 /* Copying of structures. */ 404 405 __ref __COPY(__ref obj, int size) 406 { 407 __ref copy = (__ref) __ALLOCATE(1, size); 408 memcpy(copy, obj, size); 409 return copy; 410 }