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_wrapper(__attr context, __attr attr) 46 { 47 return __new___builtins___core_wrapper(__NULL, __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__(__NULL, 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, __NULL)); 127 #endif /* __HAVE___builtins___exception_io_EOFError */ 128 } 129 130 void __raise_floating_point_error() 131 { 132 __Raise(__new___builtins___core_FloatingPointError(__NULL, __NULL)); 133 } 134 135 void __raise_io_error(__attr value) 136 { 137 #ifdef __HAVE___builtins___exception_io_IOError 138 __Raise(__new___builtins___exception_io_IOError(__NULL, __NULL, value)); 139 #endif /* __HAVE___builtins___exception_io_IOError */ 140 } 141 142 void __raise_memory_error() 143 { 144 __Raise(__new___builtins___core_MemoryError(__NULL, __NULL)); 145 } 146 147 void __raise_os_error(__attr value, __attr arg) 148 { 149 #ifdef __HAVE___builtins___exception_system_OSError 150 __Raise(__new___builtins___exception_system_OSError(__NULL, __NULL, value, arg)); 151 #endif /* __HAVE___builtins___exception_system_OSError */ 152 } 153 154 void __raise_overflow_error() 155 { 156 __Raise(__new___builtins___core_OverflowError(__NULL, __NULL)); 157 } 158 159 void __raise_unbound_method_error() 160 { 161 __Raise(__new___builtins___core_UnboundMethodInvocation(__NULL, __NULL)); 162 } 163 164 void __raise_type_error() 165 { 166 __Raise(__new___builtins___core_TypeError(__NULL, __NULL)); 167 } 168 169 void __raise_underflow_error() 170 { 171 __Raise(__new___builtins___core_UnderflowError(__NULL, __NULL)); 172 } 173 174 void __raise_value_error(__attr value) 175 { 176 #ifdef __HAVE___builtins___exception_base_ValueError 177 __Raise(__new___builtins___exception_base_ValueError(__NULL, __NULL, value)); 178 #endif /* __HAVE___builtins___exception_base_ValueError */ 179 } 180 181 void __raise_zero_division_error() 182 { 183 __Raise(__new___builtins___core_ZeroDivisionError(__NULL, __NULL)); 184 } 185 186 /* Helper for raising exception instances. */ 187 188 __attr __ensure_instance(__attr __stack, __attr arg) 189 { 190 /* Reserve space for the stack and instance. */ 191 192 __attr args[2] = {__stack, __NULL}; 193 194 /* Return instances as provided. */ 195 196 if (__is_instance(__VALUE(arg))) 197 return arg; 198 199 /* Invoke non-instances to produce instances. */ 200 201 else 202 return __invoke(arg, 0, 0, 0, 0, 2, args); 203 } 204 205 /* Generic invocation operations. */ 206 207 /* Invoke the given callable, supplying keyword argument details in the given 208 codes and arguments arrays, indicating the number of arguments described. 209 The number of positional arguments is specified, and such arguments then 210 follow as conventional function arguments. 211 212 Typically, at least two arguments are specified, starting with the stack 213 argument and any context argument. 214 */ 215 216 __attr __invoke(__attr callable, int always_callable, 217 unsigned int nkwargs, __param kwcodes[], __attr kwargs[], 218 unsigned int nargs, __attr args[]) 219 { 220 /* Unwrap any wrapped function. */ 221 222 __attr target = __unwrap_callable(callable); 223 224 /* Obtain the __args__ special member, referencing the parameter table. */ 225 226 const __ptable *ptable = __check_and_load_via_object(__VALUE(target), __args__).ptable; 227 228 /* Refer to the table and minimum/maximum, adjusting for the stack 229 argument. */ 230 231 unsigned int min = ptable->min + 1, max = ptable->max + 1; 232 233 /* Reserve enough space for the arguments. */ 234 235 __attr *allargs = args, moreargs[max]; 236 237 /* Traverse the arguments. */ 238 239 unsigned int pos, kwpos; 240 241 /* Check the number of arguments. */ 242 243 if ((nargs == max) && (nkwargs == 0)) 244 { 245 /* pass */ 246 } 247 248 /* NOTE: Should use a more specific exception. */ 249 250 else if ((min > (nargs + nkwargs)) || ((nargs + nkwargs) > max)) 251 { 252 __raise_type_error(); 253 } 254 255 /* Copy the arguments. */ 256 257 else if (nargs < max) 258 { 259 allargs = moreargs; 260 261 for (pos = 0; pos < nargs; pos++) 262 allargs[pos] = args[pos]; 263 264 /* Erase the remaining arguments. */ 265 266 for (pos = nargs; pos < max; pos++) 267 __SETNULL(allargs[pos]); 268 269 /* Fill keyword arguments. */ 270 271 for (kwpos = 0; kwpos < nkwargs; kwpos++) 272 { 273 pos = __HASPARAM(ptable, kwcodes[kwpos].pos, kwcodes[kwpos].code); 274 275 /* Check the table entry against the supplied argument details. 276 Set the argument but only if it does not overwrite positional 277 arguments. Here, the position is adjusted for the stack 278 argument. */ 279 280 if ((pos == -1) || (pos + 1 < nargs)) 281 { 282 /* NOTE: Should use a more specific exception. */ 283 284 __raise_type_error(); 285 } 286 287 /* Set the argument using the appropriate position, adjusting for 288 the stack argument. */ 289 290 allargs[pos + 1] = kwargs[kwpos]; 291 } 292 293 /* Fill the defaults. */ 294 295 for (pos = nargs; pos < max; pos++) 296 { 297 if (__ISNULL(allargs[pos])) 298 allargs[pos] = __GETDEFAULT(__VALUE(target), pos - min); 299 } 300 } 301 302 /* Call with the prepared arguments via a special adaptor function that 303 converts the array to an argument list. The stack argument occupies 304 position #0, with the context occupying position #1. */ 305 306 return __call_with_args( 307 always_callable ? 308 __get_function_unwrapped(allargs[1], target) : 309 __check_and_get_function_unwrapped(allargs[1], target), 310 allargs, max); 311 } 312 313 /* Error routines. */ 314 315 __attr __unbound_method(__attr __stack, __attr __self) 316 { 317 __Raise(__new___builtins___core_UnboundMethodInvocation(__stack, __NULL)); 318 return __builtins___none_None; /* superfluous */ 319 } 320 321 /* Generic operations depending on specific program details. */ 322 323 void __SETDEFAULT(__ref obj, int pos, __attr value) 324 { 325 __store_via_object__(obj, __FUNCTION_INSTANCE_SIZE + pos, value); 326 } 327 328 __attr __GETDEFAULT(__ref obj, int pos) 329 { 330 return __load_via_object__(obj, __FUNCTION_INSTANCE_SIZE + pos); 331 } 332 333 int __BOOL(__attr attr) 334 { 335 __ref value; 336 337 /* Non-zero integers yield a non-zero result. Since the integer type can be 338 larger than int, a conversion is performed. */ 339 340 if (__INTEGER(attr)) 341 return __TOINT(attr) ? 1 : 0; 342 343 /* Test against True and False explicitly. If necessary, invoke the bool 344 function with the object and test against True. */ 345 346 value = __VALUE(attr); 347 348 return value == (__ref) &__predefined___builtins___boolean_True ? 1 : 349 value == (__ref) &__predefined___builtins___boolean_False ? 0 : 350 __VALUE(__fn___builtins___boolean_bool(__NULL, __NULL, attr)) == 351 (__ref) &__predefined___builtins___boolean_True; 352 } 353 354 /* Conversion of trailing data to an integer. */ 355 356 __int __TOINT(__attr attr) 357 { 358 return __get_trailing_data(attr, __builtins___int_int); 359 } 360 361 /* Instance test functions, to be replaced by tagged pointer usage. */ 362 363 int __INTEGER(__attr attr) 364 { 365 __ref value = __VALUE(attr); 366 return __get_class(value) == &__builtins___int_int; 367 } 368 369 int __FLOAT(__attr attr) 370 { 371 __ref value = __VALUE(attr); 372 return __get_class(value) == &__builtins___float_float; 373 }