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