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__, __ATTRVALUE(cls)); 37 return (__attr) {.value=obj}; 38 } 39 40 __attr __new_wrapper(__ref context, __attr attr) 41 { 42 return __new___builtins___core_wrapper(__NULL, __ATTRVALUE(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(self.value, __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(arg.value)) 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(target.value, __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 /* NOTE: Should use a more specific exception. */ 190 191 if ((min > (nargs + nkwargs)) || ((nargs + nkwargs) > max)) 192 __raise_type_error(); 193 194 /* Copy the arguments. */ 195 196 if (nargs < max) 197 { 198 allargs = moreargs; 199 200 for (pos = 0; pos < nargs; pos++) 201 allargs[pos] = args[pos]; 202 203 /* Erase the remaining arguments. */ 204 205 for (pos = nargs; pos < max; pos++) 206 allargs[pos].value = 0; 207 208 /* Fill keyword arguments. */ 209 210 for (kwpos = 0; kwpos < nkwargs; kwpos++) 211 { 212 pos = __HASPARAM(ptable, kwcodes[kwpos].pos, kwcodes[kwpos].code); 213 214 /* Check the table entry against the supplied argument details. 215 Set the argument but only if it does not overwrite positional 216 arguments. */ 217 /* NOTE: Should use a more specific exception. */ 218 219 if ((pos == -1) || (pos < nargs)) 220 __raise_type_error(); 221 222 /* Set the argument using the appropriate position. */ 223 224 allargs[pos] = kwargs[kwpos]; 225 } 226 227 /* Fill the defaults. */ 228 229 for (pos = nargs; pos < max; pos++) 230 { 231 if (allargs[pos].value == 0) 232 allargs[pos] = __GETDEFAULT(target.value, pos - min); 233 } 234 } 235 236 /* Call with the prepared arguments via a special adaptor function that 237 converts the array to an argument list. */ 238 239 return __call_with_args( 240 always_callable ? 241 __get_function(allargs[0].value, target) : 242 __check_and_get_function(allargs[0].value, target), 243 allargs, max); 244 } 245 246 /* Error routines. */ 247 248 __attr __unbound_method(__attr __self) 249 { 250 __Raise(__new___builtins___core_UnboundMethodInvocation(__NULL)); 251 return __builtins___none_None; /* superfluous */ 252 } 253 254 /* Generic operations depending on specific program details. */ 255 256 void __SETDEFAULT(__ref obj, int pos, __attr value) 257 { 258 __store_via_object__(obj, __FUNCTION_INSTANCE_SIZE + pos, value); 259 } 260 261 __attr __GETDEFAULT(__ref obj, int pos) 262 { 263 return __load_via_object__(obj, __FUNCTION_INSTANCE_SIZE + pos); 264 } 265 266 int __BOOL(__attr attr) 267 { 268 /* Invoke the bool function with the object and test against True. */ 269 270 return (attr.value == __builtins___boolean_True.value) || 271 (__fn___builtins___boolean_bool(__NULL, attr).value == __builtins___boolean_True.value); 272 }