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