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