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