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, int immutable) 32 { 33 __ref obj = (__ref) (immutable ? __ALLOCATEIM : __ALLOCATE)(1, size); 34 obj->table = table; 35 obj->pos = __INSTANCEPOS; 36 __store_via_object(obj, __class__, __ATTRVALUE(cls)); 37 return __ATTRVALUE(obj); 38 } 39 40 __attr __new_wrapper(__attr context, __attr attr) 41 { 42 return __new___builtins___core_wrapper(__NULL, 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 __attr __newdata_sequence(__attr self, __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; 67 68 /* Copy the given number of values. */ 69 70 for (i = 0; i < number; i++) 71 data->attrs[i] = 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(__VALUE(self), __data__, attr); 78 return self; 79 } 80 81 #ifdef __HAVE___builtins___dict_dict 82 __attr __newdata_mapping(__attr self, __attr args[], unsigned int number) 83 { 84 /* Create a temporary list using the arguments. */ 85 86 __attr tmp = __newliteral___builtins___list_list(args, number); 87 88 /* Call __init__ with the dict object and list argument. */ 89 90 __fn___builtins___dict_dict___init__(self, tmp); 91 return self; 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 __Raise(__new___builtins___exception_io_EOFError(__NULL)); 101 #endif /* __HAVE___builtins___exception_io_EOFError */ 102 } 103 104 void __raise_io_error(__attr value) 105 { 106 #ifdef __HAVE___builtins___exception_io_IOError 107 __Raise(__new___builtins___exception_io_IOError(__NULL, value)); 108 #endif /* __HAVE___builtins___exception_io_IOError */ 109 } 110 111 void __raise_memory_error() 112 { 113 __Raise(__new___builtins___core_MemoryError(__NULL)); 114 } 115 116 void __raise_os_error(__attr value, __attr arg) 117 { 118 #ifdef __HAVE___builtins___exception_system_OSError 119 __Raise(__new___builtins___exception_system_OSError(__NULL, value, arg)); 120 #endif /* __HAVE___builtins___exception_system_OSError */ 121 } 122 123 void __raise_overflow_error() 124 { 125 __Raise(__new___builtins___core_OverflowError(__NULL)); 126 } 127 128 void __raise_type_error() 129 { 130 __Raise(__new___builtins___core_TypeError(__NULL)); 131 } 132 133 void __raise_zero_division_error() 134 { 135 __Raise(__new___builtins___core_ZeroDivisionError(__NULL)); 136 } 137 138 /* Helper for raising exception instances. */ 139 140 __attr __ensure_instance(__attr arg) 141 { 142 /* Reserve space for the instance. */ 143 144 __attr args[1] = {__NULL}; 145 146 /* Return instances as provided. */ 147 148 if (__is_instance(__VALUE(arg))) 149 return arg; 150 151 /* Invoke non-instances to produce instances. */ 152 153 else 154 return __invoke(arg, 0, 0, 0, 0, 1, args); 155 } 156 157 /* Generic invocation operations. */ 158 159 /* Invoke the given callable, supplying keyword argument details in the given 160 codes and arguments arrays, indicating the number of arguments described. 161 The number of positional arguments is specified, and such arguments then 162 follow as conventional function arguments. Typically, at least one argument 163 is specified, starting with any context argument. 164 */ 165 166 __attr __invoke(__attr callable, int always_callable, 167 unsigned int nkwargs, __param kwcodes[], __attr kwargs[], 168 unsigned int nargs, __attr args[]) 169 { 170 /* Unwrap any wrapped function. */ 171 172 __attr target = __unwrap_callable(callable); 173 174 /* Obtain the __args__ special member, referencing the parameter table. */ 175 /* Refer to the table and minimum/maximum. */ 176 177 const __ptable *ptable = __check_and_load_via_object(__VALUE(target), __args__).ptable; 178 const unsigned int min = ptable->min, max = ptable->max; 179 180 /* Reserve enough space for the arguments. */ 181 182 __attr *allargs = args, moreargs[max]; 183 184 /* Traverse the arguments. */ 185 186 unsigned int pos, kwpos; 187 188 /* Check the number of arguments. */ 189 190 if ((nargs == max) && (nkwargs == 0)) 191 { 192 /* pass */ 193 } 194 195 /* NOTE: Should use a more specific exception. */ 196 197 else if ((min > (nargs + nkwargs)) || ((nargs + nkwargs) > max)) 198 { 199 __raise_type_error(); 200 } 201 202 /* Copy the arguments. */ 203 204 else if (nargs < max) 205 { 206 allargs = moreargs; 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 __SETNULL(allargs[pos]); 215 216 /* Fill keyword arguments. */ 217 218 for (kwpos = 0; kwpos < nkwargs; kwpos++) 219 { 220 pos = __HASPARAM(ptable, kwcodes[kwpos].pos, kwcodes[kwpos].code); 221 222 /* Check the table entry against the supplied argument details. 223 Set the argument but only if it does not overwrite positional 224 arguments. */ 225 /* NOTE: Should use a more specific exception. */ 226 227 if ((pos == -1) || (pos < nargs)) 228 __raise_type_error(); 229 230 /* Set the argument using the appropriate position. */ 231 232 allargs[pos] = kwargs[kwpos]; 233 } 234 235 /* Fill the defaults. */ 236 237 for (pos = nargs; pos < max; pos++) 238 { 239 if (__ISNULL(allargs[pos])) 240 allargs[pos] = __GETDEFAULT(__VALUE(target), pos - min); 241 } 242 } 243 244 /* Call with the prepared arguments via a special adaptor function that 245 converts the array to an argument list. */ 246 247 return __call_with_args( 248 always_callable ? 249 __get_function_unwrapped(allargs[0], target) : 250 __check_and_get_function_unwrapped(allargs[0], target), 251 allargs, max); 252 } 253 254 /* Error routines. */ 255 256 __attr __unbound_method(__attr __self) 257 { 258 __Raise(__new___builtins___core_UnboundMethodInvocation(__NULL)); 259 return __builtins___none_None; /* superfluous */ 260 } 261 262 /* Generic operations depending on specific program details. */ 263 264 void __SETDEFAULT(__ref obj, int pos, __attr value) 265 { 266 __store_via_object__(obj, __FUNCTION_INSTANCE_SIZE + pos, value); 267 } 268 269 __attr __GETDEFAULT(__ref obj, int pos) 270 { 271 return __load_via_object__(obj, __FUNCTION_INSTANCE_SIZE + pos); 272 } 273 274 int __BOOL(__attr attr) 275 { 276 /* Invoke the bool function with the object and test against True. */ 277 278 return __VALUE(attr) == &__predefined___builtins___boolean_True ? 1 : 279 __VALUE(attr) == &__predefined___builtins___boolean_False ? 0 : 280 __VALUE(__fn___builtins___boolean_bool(__NULL, attr)) == &__predefined___builtins___boolean_True; 281 }