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 /* NOTE: Should use a more specific exception. */ 203 204 if ((min > (nargs + nkwargs)) || ((nargs + nkwargs) > max)) 205 __raise_type_error(); 206 207 /* Copy the arguments. */ 208 209 for (pos = 0; pos < nargs; pos++) 210 allargs[pos] = args[pos]; 211 212 /* Erase the remaining arguments. */ 213 214 for (pos = nargs; pos < max; pos++) 215 { 216 allargs[pos].value = 0; 217 } 218 219 /* Fill keyword arguments. */ 220 221 for (kwpos = 0; kwpos < nkwargs; kwpos++) 222 { 223 pos = __HASPARAM(ptable, kwcodes[kwpos].pos, kwcodes[kwpos].code); 224 225 /* Check the table entry against the supplied argument details. 226 Set the argument but only if it does not overwrite positional 227 arguments. */ 228 /* NOTE: Should use a more specific exception. */ 229 230 if ((pos == -1) || (pos < nargs)) 231 __raise_type_error(); 232 233 /* Set the argument using the appropriate position. */ 234 235 allargs[pos] = kwargs[kwpos]; 236 } 237 238 /* Fill the defaults. */ 239 240 for (pos = nargs; pos < max; pos++) 241 { 242 if (allargs[pos].value == 0) 243 allargs[pos] = __GETDEFAULT(callable.value, pos - min); 244 } 245 246 /* Call with the prepared arguments. */ 247 248 return (always_callable ? __get_function(callable) : __check_and_get_function(callable))(allargs); 249 } 250 251 /* Error routines. */ 252 253 __attr __unbound_method(__attr args[]) 254 { 255 __attr excargs[1]; 256 __attr exc = __new___builtins___core_UnboundMethodInvocation(excargs); 257 __Raise(exc); 258 return __builtins___none_None; /* superfluous */ 259 } 260 261 /* Generic operations depending on specific program details. */ 262 263 void __SETDEFAULT(__ref obj, int pos, __attr value) 264 { 265 __store_via_object(obj, __FUNCTION_INSTANCE_SIZE + pos, value); 266 } 267 268 __attr __GETDEFAULT(__ref obj, int pos) 269 { 270 return __load_via_object(obj, __FUNCTION_INSTANCE_SIZE + pos); 271 } 272 273 int __BOOL(__attr attr) 274 { 275 __attr args[2] = {__NULL, attr}; 276 277 /* Invoke the bool function with the object and test against True. */ 278 279 return __fn___builtins___boolean_bool(args).value == __builtins___boolean_True.value; 280 }