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