1 /* Common operations. 2 3 Copyright (C) 2015, 2016, 2017, 2018, 2021 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 /* Get object reference from attribute. */ 27 28 __ref __VALUE(__attr attr) 29 { 30 return attr.value; 31 } 32 33 /* Basic structure tests. */ 34 35 static inline int __HASATTR(__ref obj, int pos, int code) 36 { 37 return (pos < obj->table->size) && (obj->table->attrs[pos] == code); 38 } 39 40 /* Direct access and manipulation of static objects. */ 41 42 __attr __load_static_ignore(__ref obj) 43 { 44 return __ATTRVALUE(obj); 45 } 46 47 __attr __load_static_replace(__attr context, __ref obj) 48 { 49 return __update_context(context, __ATTRVALUE(obj)); 50 } 51 52 __attr __load_static_test(__attr context, __ref obj) 53 { 54 return __test_context(context, __ATTRVALUE(obj)); 55 } 56 57 /* Direct retrieval operations, returning and setting attributes. */ 58 59 __attr __load_via_object__(__ref obj, int pos) 60 { 61 return obj->attrs[pos]; 62 } 63 64 __attr __load_via_class__(__ref obj, int pos) 65 { 66 return __load_via_object__(__get_class(obj), pos); 67 } 68 69 __attr __get_class_and_load__(__ref obj, int pos) 70 { 71 if (__is_instance(obj)) 72 return __load_via_class__(obj, pos); 73 else 74 return __load_via_object__(obj, pos); 75 } 76 77 /* Direct storage operations. */ 78 79 int __store_via_object__(__ref obj, int pos, __attr value) 80 { 81 obj->attrs[pos] = value; 82 return 1; 83 } 84 85 int __store_via_class__(__ref obj, int pos, __attr value) 86 { 87 return __store_via_object__(__get_class(obj), pos, value); 88 } 89 90 int __get_class_and_store__(__ref obj, int pos, __attr value) 91 { 92 /* Forbid class-relative assignments. */ 93 94 __raise_type_error(); 95 return 0; 96 } 97 98 /* Introspection. */ 99 100 int __is_instance(__ref obj) 101 { 102 return obj->pos == __INSTANCEPOS; 103 } 104 105 int __is_subclass(__ref obj, __attr cls) 106 { 107 return __HASATTR(obj, __TYPEPOS(__VALUE(cls)), __TYPECODE(__VALUE(cls))); 108 } 109 110 int __is_instance_subclass(__ref obj, __attr cls) 111 { 112 return __is_instance(obj) && __HASATTR(__get_class(obj), __TYPEPOS(__VALUE(cls)), __TYPECODE(__VALUE(cls))); 113 } 114 115 int __is_type_instance(__ref obj) 116 { 117 return __HASATTR(__get_class(obj), __TYPE_CLASS_POS, __TYPE_CLASS_CODE); 118 } 119 120 __ref __get_class(__ref obj) 121 { 122 return __VALUE(__load_via_object(obj, __class__)); 123 } 124 125 __attr __get_class_attr(__ref obj) 126 { 127 return __load_via_object(obj, __class__); 128 } 129 130 /* Attribute testing operations. */ 131 132 __ref __test_specific_instance(__ref obj, __ref type) 133 { 134 return __get_class(obj) == type ? obj : 0; 135 } 136 137 __ref __test_specific_object(__ref obj, __ref type) 138 { 139 return __test_specific_type(obj, type) || __test_specific_instance(obj, type) ? obj : 0; 140 } 141 142 __ref __test_specific_type(__ref obj, __ref type) 143 { 144 return obj == type ? obj : 0; 145 } 146 147 __ref __test_common_instance__(__ref obj, int pos, int code) 148 { 149 return __HASATTR(__get_class(obj), pos, code) ? obj : 0; 150 } 151 152 __ref __test_common_object__(__ref obj, int pos, int code) 153 { 154 return __test_common_type__(obj, pos, code) || __test_common_instance__(obj, pos, code) ? obj : 0; 155 } 156 157 __ref __test_common_type__(__ref obj, int pos, int code) 158 { 159 return __HASATTR(obj, pos, code) ? obj : 0; 160 } 161 162 /* Attribute testing and retrieval operations. */ 163 164 __attr __check_and_load_via_object_null(__ref obj, int pos, int code) 165 { 166 if (__HASATTR(obj, pos, code)) 167 return __load_via_object__(obj, pos); 168 else 169 return __NULL; 170 } 171 172 __attr __check_and_load_via_class__(__ref obj, int pos, int code) 173 { 174 return __check_and_load_via_object__(__get_class(obj), pos, code); 175 } 176 177 __attr __check_and_load_via_object__(__ref obj, int pos, int code) 178 { 179 if (__HASATTR(obj, pos, code)) 180 return __load_via_object__(obj, pos); 181 182 __raise_type_error(); 183 return __NULL; 184 } 185 186 __attr __check_and_load_via_any__(__ref obj, int pos, int code) 187 { 188 __attr out = __check_and_load_via_object_null(obj, pos, code); 189 if (__ISNULL(out)) 190 out = __check_and_load_via_class__(obj, pos, code); 191 return out; 192 } 193 194 /* Attribute testing and storage operations. */ 195 196 int __check_and_store_via_class__(__ref obj, int pos, int code, __attr value) 197 { 198 /* Forbid class-relative assignments. */ 199 200 __raise_type_error(); 201 return 0; 202 } 203 204 int __check_and_store_via_object__(__ref obj, int pos, int code, __attr value) 205 { 206 if (__HASATTR(obj, pos, code)) 207 { 208 __store_via_object__(obj, pos, value); 209 return 1; 210 } 211 212 /* No suitable attribute. */ 213 214 __raise_type_error(); 215 return 0; 216 } 217 218 int __check_and_store_via_any__(__ref obj, int pos, int code, __attr value) 219 { 220 if (__check_and_store_via_object__(obj, pos, code, value)) 221 return 1; 222 223 /* Forbid class-relative assignments. */ 224 225 __raise_type_error(); 226 return 0; 227 } 228 229 /* Context-related operations. */ 230 231 int __test_context_update(__attr context, __attr attr, int invoke) 232 { 233 /* Return whether the context should be updated for the attribute. */ 234 235 __attr attrcontext = __CONTEXT_AS_VALUE(attr); 236 __ref attrcontextvalue = __VALUE(attrcontext); 237 238 /* Preserve any existing null or instance context. */ 239 240 if (__ISNULL(attrcontext) || __is_instance(attrcontextvalue)) 241 return 0; 242 243 /* Test any instance context against the context employed by the 244 attribute. */ 245 246 if (__is_instance(__VALUE(context))) 247 { 248 /* Obtain the special class attribute position and code identifying the 249 attribute context's class, inspecting the context instance for 250 compatibility. */ 251 252 if (__test_common_instance__(__VALUE(context), __TYPEPOS(attrcontextvalue), __TYPECODE(attrcontextvalue))) 253 return 1; 254 else 255 __raise_type_error(); 256 } 257 258 /* Without a null or instance context, an invocation cannot be performed. */ 259 260 if (invoke) 261 __raise_unbound_method_error(); 262 263 /* Test for access to a type class attribute using a type instance. */ 264 265 if (__test_specific_type(attrcontextvalue, &__TYPE_CLASS_TYPE) && __is_type_instance(__VALUE(context))) 266 return 1; 267 268 /* Otherwise, preserve the attribute as retrieved. */ 269 270 return 0; 271 } 272 273 __attr __test_context(__attr context, __attr attr) 274 { 275 /* Update the context or return the unchanged attribute. */ 276 277 if (__test_context_update(context, attr, 0)) 278 return __update_context(context, attr); 279 else 280 return attr; 281 } 282 283 __attr __update_context(__attr context, __attr attr) 284 { 285 return __new_wrapper(context, attr); 286 } 287 288 __attr __test_context_revert(int target, __attr context, __attr attr, __attr contexts[]) 289 { 290 /* Revert the local context to that employed by the attribute if the 291 supplied context is not appropriate. */ 292 293 if (!__test_context_update(context, attr, 1)) 294 contexts[target] = __CONTEXT_AS_VALUE(attr); 295 return attr; 296 } 297 298 __attr __test_context_static(int target, __attr context, __ref value, __attr contexts[]) 299 { 300 /* Set the local context to the specified context if appropriate. */ 301 302 if (__test_context_update(context, __ATTRVALUE(value), 1)) 303 contexts[target] = context; 304 return __ATTRVALUE(value); 305 } 306 307 /* Context testing for invocations. */ 308 309 int __type_method_invocation(__attr context, __attr target) 310 { 311 __attr targetcontext = __CONTEXT_AS_VALUE(target); 312 313 /* Require instances, not classes, where methods are function instances. */ 314 315 if (!__is_instance(__VALUE(target))) 316 return 0; 317 318 /* Access the context of the callable and test if it is the type object. */ 319 320 return (!__ISNULL(targetcontext) && __test_specific_type(__VALUE(targetcontext), &__TYPE_CLASS_TYPE) && __is_type_instance(__VALUE(context))); 321 } 322 323 __attr __unwrap_callable(__attr callable) 324 { 325 __attr value = __check_and_load_via_object_null(__VALUE(callable), __ATTRPOS(__value__), __ATTRCODE(__value__)); 326 return __VALUE(value) ? value : callable; 327 } 328 329 __attr (*__get_function_unchecked(__attr target))() 330 { 331 return __load_via_object(__VALUE(__unwrap_callable(target)), __fn__).fn; 332 } 333 334 __attr (*__get_function(__attr context, __attr target))() 335 { 336 return __get_function_unwrapped(context, __unwrap_callable(target)); 337 } 338 339 __attr (*__get_function_unwrapped(__attr context, __attr target))() 340 { 341 /* Require null or instance contexts for functions and methods respectively, 342 or type instance contexts for type methods. */ 343 344 if (__ISNULL(context) || __is_instance(__VALUE(context)) || __type_method_invocation(context, target)) 345 return __get_function_member(target); 346 else 347 return __unbound_method; 348 } 349 350 __attr (*__get_function_member(__attr target))() 351 { 352 return __load_via_object(__VALUE(target), __fn__).fn; 353 } 354 355 __attr (*__check_and_get_function(__attr context, __attr target))() 356 { 357 return __check_and_get_function_unwrapped(context, __unwrap_callable(target)); 358 } 359 360 __attr (*__check_and_get_function_unwrapped(__attr context, __attr target))() 361 { 362 /* Require null or instance contexts for functions and methods respectively, 363 or type instance contexts for type methods. */ 364 365 if (__ISNULL(context) || __is_instance(__VALUE(context)) || __type_method_invocation(context, target)) 366 return __check_and_load_via_object__(__VALUE(target), __ATTRPOS(__fn__), __ATTRCODE(__fn__)).fn; 367 else 368 return __unbound_method; 369 } 370 371 /* Parameter position operations. */ 372 373 int __HASPARAM(const __ptable *ptable, int ppos, int pcode) 374 { 375 __param param; 376 377 if (ppos < ptable->size) 378 { 379 param = ptable->params[ppos]; 380 if (param.code == pcode) 381 return param.pos; 382 } 383 384 return -1; 385 } 386 387 /* Conversions. */ 388 389 __attr __CONTEXT_AS_VALUE(__attr attr) 390 { 391 return __check_and_load_via_object_null(__VALUE(attr), __ATTRPOS(__context__), __ATTRCODE(__context__)); 392 } 393 394 /* Type testing. */ 395 396 __ref __ISFUNC(__ref obj) 397 { 398 return __test_specific_instance(obj, &__FUNCTION_TYPE); 399 } 400 401 /* Attribute codes and positions for type objects. */ 402 403 unsigned int __TYPECODE(__ref obj) 404 { 405 return obj->table->attrs[obj->pos]; 406 } 407 408 unsigned int __TYPEPOS(__ref obj) 409 { 410 return obj->pos; 411 } 412 413 /* Memory allocation. */ 414 415 void *__ALLOCATE(size_t nmemb, size_t size) 416 { 417 void *ptr = GC_MALLOC(nmemb * size); /* sets memory to zero */ 418 if (ptr == NULL) 419 __raise_memory_error(); 420 return ptr; 421 } 422 423 void *__ALLOCATEIM(size_t nmemb, size_t size) 424 { 425 void *ptr = GC_MALLOC_ATOMIC(nmemb * size); /* sets memory to zero */ 426 if (ptr == NULL) 427 __raise_memory_error(); 428 return ptr; 429 } 430 431 void *__REALLOCATE(void *ptr, size_t size) 432 { 433 void *nptr = GC_REALLOC(ptr, size); 434 if (nptr == NULL) 435 __raise_memory_error(); 436 return nptr; 437 } 438 439 /* Copying of structures. */ 440 441 __ref __COPY(__ref obj, int size) 442 { 443 __ref copy = (__ref) __ALLOCATE(1, size); 444 memcpy(copy, obj, size); 445 return copy; 446 }