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