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