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