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