1 /* Common operations. */ 2 3 #include <stdlib.h> 4 #include "ops.h" 5 #include "progconsts.h" 6 #include "progtypes.h" 7 8 /* Direct access and manipulation of static objects. */ 9 10 __attr __load_static(__ref parent, __ref obj) 11 { 12 __attr out = {.context=parent, .value=obj}; 13 return out; 14 } 15 16 /* Direct retrieval operations, returning and setting attributes. */ 17 18 __attr __load_via_object(__ref obj, int pos) 19 { 20 return obj->attrs[pos]; 21 } 22 23 __attr __load_via_class(__ref obj, int pos) 24 { 25 return __load_via_object(__get_class(obj), pos); 26 } 27 28 __attr __get_class_and_load(__ref obj, int pos) 29 { 30 if (__is_instance(obj)) 31 return __load_via_class(obj, pos); 32 else 33 return __load_via_object(obj, pos); 34 } 35 36 /* Direct storage operations. */ 37 38 int __store_via_object(__ref obj, int pos, __attr value) 39 { 40 obj->attrs[pos] = value; 41 return 1; 42 } 43 44 /* Introspection. */ 45 46 int __is_instance(__ref obj) 47 { 48 return obj->pos == __INSTANCEPOS; 49 } 50 51 __ref __get_class(__ref obj) 52 { 53 return __load_via_object(obj, __pos___class__).value; 54 } 55 56 /* Attribute testing operations. */ 57 58 __ref __test_specific_instance(__ref obj, __ref type) 59 { 60 return __get_class(obj) == type ? obj : 0; 61 } 62 63 __ref __test_common_instance(__ref obj, int pos, int code) 64 { 65 return __HASATTR(__get_class(obj), pos, code) ? obj : 0; 66 } 67 68 __ref __test_common_object(__ref obj, int pos, int code) 69 { 70 return __test_common_type(obj, pos, code) || __test_common_instance(obj, pos, code) ? obj : 0; 71 } 72 73 __ref __test_common_type(__ref obj, int pos, int code) 74 { 75 return __HASATTR(obj, pos, code) ? obj : 0; 76 } 77 78 /* Attribute testing and retrieval operations. */ 79 80 __attr __check_and_load_via_class(__ref obj, int pos, int code) 81 { 82 return __check_and_load_via_object(__get_class(obj), pos, code); 83 } 84 85 __attr __check_and_load_via_object(__ref obj, int pos, int code) 86 { 87 return __HASATTR(obj, pos, code) ? __load_via_object(obj, pos) : __NULL; 88 } 89 90 __attr __check_and_load_via_any(__ref obj, int pos, int code) 91 { 92 __attr out = __check_and_load_via_object(obj, pos, code); 93 if (out.value == 0) 94 out = __check_and_load_via_class(obj, pos, code); 95 return out; 96 } 97 98 /* Attribute testing and storage operations. */ 99 100 int __check_and_store_via_object(__ref obj, int pos, int code, __attr value) 101 { 102 if (__HASATTR(obj, pos, code)) 103 { 104 __store_via_object(obj, pos, value); 105 return 1; 106 } 107 return 0; 108 } 109 110 int __check_and_store_via_any(__ref obj, int pos, int code, __attr value) 111 { 112 if (__check_and_store_via_object(obj, pos, code, value)) 113 return 1; 114 return __check_and_store_via_object(__get_class(obj), pos, code, value); 115 } 116 117 /* Context-related operations. */ 118 119 __attr __test_context(__ref context, __attr attr) 120 { 121 /* Preserve any existing instance context. */ 122 123 if (__is_instance(attr.context)) 124 return attr; 125 if (__is_instance(context) && __test_common_instance(context, __TYPEPOS(attr.context), __TYPECODE(attr.context))) 126 return __replace_context(context, attr); 127 if (!__is_instance(context) && __test_common_type(context, __TYPEPOS(attr.context), __TYPECODE(attr.context))) 128 return __update_context(context, attr); 129 130 /* NOTE: An error may be more appropriate. */ 131 132 return __NULL; 133 } 134 135 __attr __replace_context(__ref context, __attr attr) 136 { 137 __attr out; 138 139 /* Set the context. */ 140 141 out.context = context; 142 143 /* Reference a callable version of the attribute by obtaining the bound 144 method reference from the __fn__ special attribute. */ 145 146 out.value = __load_via_object(attr.value, __ATTRPOS(__fn__)).b; 147 return out; 148 } 149 150 __attr __update_context(__ref context, __attr attr) 151 { 152 __attr out = {context, .fn=attr.fn}; 153 return out; 154 } 155 156 /* Basic structure tests. */ 157 158 int __WITHIN(__ref obj, int pos) 159 { 160 return pos < obj->table->size; 161 } 162 163 int __HASATTR(__ref obj, int pos, int code) 164 { 165 return __WITHIN(obj, pos) && (obj->table->attrs[pos] == code); 166 } 167 168 /* Parameter position operations. */ 169 170 int __HASPARAM(const __ptable *ptable, int ppos, int pcode) 171 { 172 __param param; 173 174 if (ppos < ptable->size) 175 { 176 param = ptable->params[ppos]; 177 if (param.code == pcode) 178 return param.pos; 179 } 180 181 return -1; 182 } 183 184 /* Conversions. */ 185 186 __attr __CONTEXT_AS_VALUE(__attr attr) 187 { 188 __attr out; 189 out.context = attr.context; 190 out.value = attr.context; 191 return out; 192 } 193 194 /* Type testing. */ 195 196 __ref __ISFUNC(__ref obj) 197 { 198 return __test_specific_instance(obj, &__FUNCTION_TYPE); 199 } 200 201 int __ISNULL(__attr value) 202 { 203 /* (value.context == __NULL.context) is superfluous */ 204 return (value.value == 0); /* __NULL.value */ 205 } 206 207 /* Attribute codes and positions for type objects. */ 208 209 unsigned int __TYPECODE(__ref obj) 210 { 211 return obj->table->attrs[obj->pos]; 212 } 213 214 unsigned int __TYPEPOS(__ref obj) 215 { 216 return obj->pos; 217 } 218 219 /* Copying of structures. */ 220 221 __ref __COPY(__ref obj, int size) 222 { 223 __ref copy = calloc(1, size); 224 memcpy(copy, obj, size); 225 return copy; 226 }