1 /* Operations depending on program specifics. 2 3 Copyright (C) 2015, 2016, 2017, 2018, 2021 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 <stdlib.h> 20 #include "types.h" 21 #include "ops.h" 22 #include "progconsts.h" 23 #include "progops.h" 24 #include "progtypes.h" 25 #include "main.h" 26 #include "exceptions.h" 27 #include "calls.h" 28 29 /* Generic instantiation operations, defining common members. */ 30 31 void __init(__ref obj, const __table * table, __ref cls) 32 { 33 obj->table = table; 34 obj->pos = __INSTANCEPOS; 35 __store_via_object(obj, __class__, __ATTRVALUE(cls)); 36 } 37 38 __attr __new(const __table * table, __ref cls, size_t size, int immutable) 39 { 40 __ref obj = (__ref) (immutable ? __ALLOCATEIM : __ALLOCATE)(1, size); 41 __init(obj, table, cls); 42 return __ATTRVALUE(obj); 43 } 44 45 __attr __new_wrapper(__attr context, __attr attr) 46 { 47 return __new___builtins___core_wrapper(__NULL, context, attr); 48 } 49 50 /* Generic internal data allocation. */ 51 52 __fragment *__new_fragment(__int n) 53 { 54 /* Allocate space for the list. */ 55 56 __fragment *data = (__fragment *) __ALLOCATE(1, __FRAGMENT_SIZE(n)); 57 58 /* The initial capacity is the same as the given size. */ 59 60 data->size = 0; 61 data->capacity = n; 62 return data; 63 } 64 65 void __newdata_sequence(__int number, __fragment *data, __attr args[]) 66 { 67 __int i; 68 69 /* Copy the given number of values. */ 70 71 for (i = 0; i < number; i++) 72 data->attrs[i] = args[i]; 73 74 data->size = number; 75 } 76 77 __attr __newdata_list(__int number, __attr args[]) 78 { 79 __attr self = __NEWINSTANCE(__builtins___list_list); 80 __fragment *data = __new_fragment(number); 81 82 /* Store a reference to the data in the object's __data__ attribute. */ 83 84 __store_via_object(__VALUE(self), __data__, (__attr) {.seqvalue=data}); 85 __newdata_sequence(number, data, args); 86 return self; 87 } 88 89 __attr __newdata_tuple(__int number, __attr args[]) 90 { 91 /* Allocate the tuple and fragment together. */ 92 93 __attr self = __new(&__INSTANCETABLE(__builtins___tuple_tuple), 94 &__builtins___tuple_tuple, 95 __INSTANCESIZE(__builtins___tuple_tuple) + __FRAGMENT_SIZE(number), 0); 96 __fragment *data = (__fragment *) ((void *) __VALUE(self) + __INSTANCESIZE(__builtins___tuple_tuple)); 97 98 /* Store a reference to the data in the object's __data__ attribute. */ 99 100 __store_via_object(__VALUE(self), __data__, (__attr) {.seqvalue=data}); 101 __newdata_sequence(number, data, args); 102 return self; 103 } 104 105 #ifdef __HAVE___builtins___dict_dict 106 __attr __newdata_dict(__int number, __attr args[]) 107 { 108 __attr self = __NEWINSTANCE(__builtins___dict_dict); 109 110 /* Create a temporary list using the arguments. */ 111 112 __attr tmp = __newdata_list(number, args); 113 114 /* Call __init__ with the dict object and list argument. */ 115 116 __fn___builtins___dict_dict___init__(self, tmp); 117 return self; 118 } 119 #endif /* __HAVE___builtins___dict_dict */ 120 121 /* Helpers for raising errors within common operations. */ 122 123 void __raise_eof_error() 124 { 125 #ifdef __HAVE___builtins___exception_io_EOFError 126 __Raise(__new___builtins___exception_io_EOFError(__NULL)); 127 #endif /* __HAVE___builtins___exception_io_EOFError */ 128 } 129 130 void __raise_io_error(__attr value) 131 { 132 #ifdef __HAVE___builtins___exception_io_IOError 133 __Raise(__new___builtins___exception_io_IOError(__NULL, value)); 134 #endif /* __HAVE___builtins___exception_io_IOError */ 135 } 136 137 void __raise_memory_error() 138 { 139 __Raise(__new___builtins___core_MemoryError(__NULL)); 140 } 141 142 void __raise_os_error(__attr value, __attr arg) 143 { 144 #ifdef __HAVE___builtins___exception_system_OSError 145 __Raise(__new___builtins___exception_system_OSError(__NULL, value, arg)); 146 #endif /* __HAVE___builtins___exception_system_OSError */ 147 } 148 149 void __raise_overflow_error() 150 { 151 __Raise(__new___builtins___core_OverflowError(__NULL)); 152 } 153 154 void __raise_unbound_method_error() 155 { 156 __Raise(__new___builtins___core_UnboundMethodInvocation(__NULL)); 157 } 158 159 void __raise_type_error() 160 { 161 __Raise(__new___builtins___core_TypeError(__NULL)); 162 } 163 164 void __raise_value_error(__attr value) 165 { 166 #ifdef __HAVE___builtins___exception_base_ValueError 167 __Raise(__new___builtins___exception_base_ValueError(__NULL, value)); 168 #endif /* __HAVE___builtins___exception_base_ValueError */ 169 } 170 171 void __raise_zero_division_error() 172 { 173 __Raise(__new___builtins___core_ZeroDivisionError(__NULL)); 174 } 175 176 /* Helper for raising exception instances. */ 177 178 __attr __ensure_instance(__attr arg) 179 { 180 /* Reserve space for the instance. */ 181 182 __attr args[1] = {__NULL}; 183 184 /* Return instances as provided. */ 185 186 if (__is_instance(__VALUE(arg))) 187 return arg; 188 189 /* Invoke non-instances to produce instances. */ 190 191 else 192 return __invoke(arg, 0, 0, 0, 0, 1, args); 193 } 194 195 /* Generic invocation operations. */ 196 197 /* Invoke the given callable, supplying keyword argument details in the given 198 codes and arguments arrays, indicating the number of arguments described. 199 The number of positional arguments is specified, and such arguments then 200 follow as conventional function arguments. Typically, at least one argument 201 is specified, starting with any context argument. 202 */ 203 204 __attr __invoke(__attr callable, int always_callable, 205 unsigned int nkwargs, __param kwcodes[], __attr kwargs[], 206 unsigned int nargs, __attr args[]) 207 { 208 /* Unwrap any wrapped function. */ 209 210 __attr target = __unwrap_callable(callable); 211 212 /* Obtain the __args__ special member, referencing the parameter table. */ 213 /* Refer to the table and minimum/maximum. */ 214 215 const __ptable *ptable = __check_and_load_via_object(__VALUE(target), __args__).ptable; 216 const unsigned int min = ptable->min, max = ptable->max; 217 218 /* Reserve enough space for the arguments. */ 219 220 __attr *allargs = args, moreargs[max]; 221 222 /* Traverse the arguments. */ 223 224 unsigned int pos, kwpos; 225 226 /* Check the number of arguments. */ 227 228 if ((nargs == max) && (nkwargs == 0)) 229 { 230 /* pass */ 231 } 232 233 /* NOTE: Should use a more specific exception. */ 234 235 else if ((min > (nargs + nkwargs)) || ((nargs + nkwargs) > max)) 236 { 237 __raise_type_error(); 238 } 239 240 /* Copy the arguments. */ 241 242 else if (nargs < max) 243 { 244 allargs = moreargs; 245 246 for (pos = 0; pos < nargs; pos++) 247 allargs[pos] = args[pos]; 248 249 /* Erase the remaining arguments. */ 250 251 for (pos = nargs; pos < max; pos++) 252 __SETNULL(allargs[pos]); 253 254 /* Fill keyword arguments. */ 255 256 for (kwpos = 0; kwpos < nkwargs; kwpos++) 257 { 258 pos = __HASPARAM(ptable, kwcodes[kwpos].pos, kwcodes[kwpos].code); 259 260 /* Check the table entry against the supplied argument details. 261 Set the argument but only if it does not overwrite positional 262 arguments. */ 263 /* NOTE: Should use a more specific exception. */ 264 265 if ((pos == -1) || (pos < nargs)) 266 __raise_type_error(); 267 268 /* Set the argument using the appropriate position. */ 269 270 allargs[pos] = kwargs[kwpos]; 271 } 272 273 /* Fill the defaults. */ 274 275 for (pos = nargs; pos < max; pos++) 276 { 277 if (__ISNULL(allargs[pos])) 278 allargs[pos] = __GETDEFAULT(__VALUE(target), pos - min); 279 } 280 } 281 282 /* Call with the prepared arguments via a special adaptor function that 283 converts the array to an argument list. */ 284 285 return __call_with_args( 286 always_callable ? 287 __get_function_unwrapped(allargs[0], target) : 288 __check_and_get_function_unwrapped(allargs[0], target), 289 allargs, max); 290 } 291 292 /* Error routines. */ 293 294 __attr __unbound_method(__attr __self) 295 { 296 __Raise(__new___builtins___core_UnboundMethodInvocation(__NULL)); 297 return __builtins___none_None; /* superfluous */ 298 } 299 300 /* Generic operations depending on specific program details. */ 301 302 void __SETDEFAULT(__ref obj, int pos, __attr value) 303 { 304 __store_via_object__(obj, __FUNCTION_INSTANCE_SIZE + pos, value); 305 } 306 307 __attr __GETDEFAULT(__ref obj, int pos) 308 { 309 return __load_via_object__(obj, __FUNCTION_INSTANCE_SIZE + pos); 310 } 311 312 int __BOOL(__attr attr) 313 { 314 __ref value; 315 316 /* Non-zero integers yield a non-zero result. Since the integer type can be 317 larger than int, a conversion is performed. */ 318 319 if (__INTEGER(attr)) 320 return __TOINT(attr) ? 1 : 0; 321 322 /* Test against True and False explicitly. If necessary, invoke the bool 323 function with the object and test against True. */ 324 325 value = attr.value; 326 327 return value == &__predefined___builtins___boolean_True ? 1 : 328 value == &__predefined___builtins___boolean_False ? 0 : 329 __VALUE(__fn___builtins___boolean_bool(__NULL, attr)) == &__predefined___builtins___boolean_True; 330 }