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