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