1 /* Operations depending on program specifics. 2 */ 3 4 #include <stdlib.h> 5 #include "types.h" 6 #include "ops.h" 7 #include "progconsts.h" 8 #include "progops.h" 9 #include "progtypes.h" 10 #include "main.h" 11 #include "exceptions.h" 12 13 /* Generic instantiation operations, defining common members. */ 14 15 __attr __new(const __table * table, __ref cls, size_t size) 16 { 17 __ref obj = (__ref) __ALLOCATE(1, size); 18 __attr self = {obj, obj}; 19 __attr tmp = {0, cls}; 20 obj->table = table; 21 __store_via_object(obj, __pos___class__, tmp); 22 return self; 23 } 24 25 /* Generic internal data allocation. */ 26 27 __fragment *__new_fragment(unsigned int n) 28 { 29 /* Allocate space for the list. */ 30 __fragment *data = (__fragment *) __ALLOCATE(1, __FRAGMENT_SIZE(n)); 31 32 /* The initial capacity is the same as the given size. */ 33 data->size = 0; 34 data->capacity = n; 35 return data; 36 } 37 38 static inline unsigned int __mapping_buckets(unsigned int n) 39 { 40 return n > 0 ? n / 2 : 5; 41 } 42 43 __mapping *__new_mapping(unsigned int n) 44 { 45 /* Allocate a number of buckets. */ 46 unsigned int capacity = __mapping_buckets(n); 47 __mapping *data = (__mapping *) __ALLOCATE(1, __MAPPING_SIZE(capacity)); 48 unsigned int i; 49 50 /* Create arrays for key and value buckets. */ 51 52 data->keys = (__fragment **) __ALLOCATE(capacity, sizeof(__fragment *)); 53 data->values = (__fragment **) __ALLOCATE(capacity, sizeof(__fragment *)); 54 55 /* Allocate fragments with an initial size of 2, assuming a mostly uniform 56 distribution of values across the buckets will occur. */ 57 58 for (i = 0; i < capacity; i++) 59 { 60 data->keys[i] = __new_fragment(2); 61 data->values[i] = __new_fragment(2); 62 } 63 64 data->size = 0; 65 data->capacity = capacity; 66 return data; 67 } 68 69 void __newdata_sequence(__attr args[], unsigned int number) 70 { 71 /* Calculate the size of the fragment. */ 72 73 __fragment *data = __new_fragment(number); 74 __attr attr = {0, .seqvalue=data}; 75 unsigned int i, j; 76 77 /* Copy the given number of values, starting from the second element. */ 78 79 for (i = 1, j = 0; i <= number; i++, j++) 80 data->attrs[j] = args[i]; 81 82 data->size = number; 83 84 /* Store a reference to the data in the object's __data__ attribute. */ 85 86 __store_via_object(args[0].value, __pos___data__, attr); 87 } 88 89 #ifdef __HAVE___builtins___dict_dict 90 91 void __newdata_mapping(__attr args[], unsigned int number) 92 { 93 __mapping *data = __new_mapping(number); 94 __attr attr = {0, .mapvalue=data}; 95 __fragment *f; 96 __attr callargs[3]; 97 unsigned int i; 98 99 /* Store a reference to the data in the object's __data__ attribute. */ 100 101 __store_via_object(args[0].value, __pos___data__, attr); 102 103 /* Store the given number of values, starting from the second element. */ 104 105 callargs[0] = args[0]; 106 107 for (i = 1; i <= number; i++) 108 { 109 /* Obtain the tuple elements. */ 110 111 f = __load_via_object(args[i].value, __pos___data__).seqvalue; 112 callargs[1] = f->attrs[0]; 113 callargs[2] = f->attrs[1]; 114 115 /* Call __setitem__ with the key and value. */ 116 117 __fn___builtins___dict_dict___setitem__(callargs); 118 } 119 } 120 121 #endif /* __HAVE___builtins___dict_dict */ 122 123 /* A helper for raising type errors within common operations. */ 124 125 void __raise_type_error() 126 { 127 __attr args[1]; 128 __attr exc = __TYPE_ERROR_INSTANTIATOR(args); 129 __Raise(exc); 130 } 131 132 /* A helper for raising memory errors within common operations. */ 133 134 void __raise_memory_error() 135 { 136 __attr args[1]; 137 __attr exc = __MEMORY_ERROR_INSTANTIATOR(args); 138 __Raise(exc); 139 } 140 141 /* Generic invocation operations. */ 142 143 /* Invoke the given callable, supplying keyword argument details in the given 144 codes and arguments arrays, indicating the number of arguments described. 145 The number of positional arguments is specified, and such arguments then 146 follow as conventional function arguments. Typically, at least one argument 147 is specified, starting with any context argument. 148 */ 149 150 __attr __invoke(__attr callable, int always_callable, 151 unsigned int nkwargs, __param kwcodes[], __attr kwargs[], 152 unsigned int nargs, __attr args[]) 153 { 154 /* Obtain the __args__ special member, referencing the parameter table. */ 155 156 __attr minparams = __check_and_load_via_object(callable.value, __pos___args__, __code___args__); 157 158 /* Refer to the table and minimum/maximum. */ 159 160 const __ptable *ptable = minparams.ptable; 161 const unsigned int min = minparams.min, max = ptable->size; 162 163 /* Reserve enough space for the arguments. */ 164 165 __attr allargs[max]; 166 167 /* Traverse the arguments. */ 168 169 unsigned int pos, kwpos; 170 171 /* Check the number of arguments. */ 172 173 if ((min > (nargs + nkwargs)) || ((nargs + nkwargs) > max)) 174 return __NULL; 175 176 /* Copy the arguments. */ 177 178 for (pos = 0; pos < nargs; pos++) 179 allargs[pos] = args[pos]; 180 181 /* Erase the remaining arguments. */ 182 183 for (pos = nargs; pos < max; pos++) 184 { 185 allargs[pos].value = 0; 186 } 187 188 /* Fill keyword arguments. */ 189 190 for (kwpos = 0; kwpos < nkwargs; kwpos++) 191 { 192 pos = __HASPARAM(ptable, kwcodes[kwpos].pos, kwcodes[kwpos].code); 193 194 /* Check the table entry against the supplied argument details. 195 Set the argument but only if it does not overwrite positional 196 arguments. */ 197 198 if ((pos == -1) || (pos < nargs)) 199 return __NULL; 200 201 /* Set the argument using the appropriate position. */ 202 203 allargs[pos] = kwargs[kwpos]; 204 } 205 206 /* Fill the defaults. */ 207 208 for (pos = nargs; pos < max; pos++) 209 { 210 if (allargs[pos].value == 0) 211 allargs[pos] = __GETDEFAULT(callable.value, pos - min); 212 } 213 214 /* Call with the prepared arguments. */ 215 216 return (always_callable ? __load_via_object(callable.value, __pos___fn__) 217 : __check_and_load_via_object(callable.value, __pos___fn__, __code___fn__) 218 ).fn(allargs); 219 } 220 221 /* Error routines. */ 222 223 __attr __unbound_method(__attr args[]) 224 { 225 __attr excargs[1]; 226 __attr exc = __new___builtins___core_UnboundMethodInvocation(excargs); 227 __Raise(exc); 228 return __builtins___none_None; /* superfluous */ 229 } 230 231 /* Generic operations depending on specific program details. */ 232 233 void __SETDEFAULT(__ref obj, int pos, __attr value) 234 { 235 __store_via_object(obj, __FUNCTION_INSTANCE_SIZE + pos, value); 236 } 237 238 __attr __GETDEFAULT(__ref obj, int pos) 239 { 240 return __load_via_object(obj, __FUNCTION_INSTANCE_SIZE + pos); 241 } 242 243 int __BOOL(__attr attr) 244 { 245 __attr args[2] = {{0, 0}, attr}; 246 247 /* Invoke the bool function with the object and test against True. */ 248 249 return __fn___builtins___boolean_bool(args).value == __builtins___boolean_True.value; 250 }