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 __attr callargs[2]; 85 86 /* Create a temporary list using the arguments. */ 87 88 __attr tmp = __newliteral___builtins___list_list(args, number); 89 90 /* Call __init__ with the dict object and list argument. */ 91 92 __fn___builtins___dict_dict___init__(self, tmp); 93 return self; 94 } 95 #endif /* __HAVE___builtins___dict_dict */ 96 97 /* Helpers for raising errors within common operations. */ 98 99 void __raise_eof_error() 100 { 101 #ifdef __HAVE___builtins___exception_io_EOFError 102 __Raise(__new___builtins___exception_io_EOFError(__NULL)); 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 __Raise(__new___builtins___exception_io_IOError(__NULL, value)); 110 #endif /* __HAVE___builtins___exception_io_IOError */ 111 } 112 113 void __raise_memory_error() 114 { 115 __Raise(__new___builtins___core_MemoryError(__NULL)); 116 } 117 118 void __raise_os_error(__attr value, __attr arg) 119 { 120 #ifdef __HAVE___builtins___exception_system_OSError 121 __Raise(__new___builtins___exception_system_OSError(__NULL, value, arg)); 122 #endif /* __HAVE___builtins___exception_system_OSError */ 123 } 124 125 void __raise_overflow_error() 126 { 127 __Raise(__new___builtins___core_OverflowError(__NULL)); 128 } 129 130 void __raise_type_error() 131 { 132 __Raise(__new___builtins___core_TypeError(__NULL)); 133 } 134 135 void __raise_zero_division_error() 136 { 137 __Raise(__new___builtins___core_ZeroDivisionError(__NULL)); 138 } 139 140 /* Helper for raising exception instances. */ 141 142 __attr __ensure_instance(__attr arg) 143 { 144 /* Reserve space for the instance. */ 145 146 __attr args[1] = {__NULL}; 147 148 /* Return instances as provided. */ 149 150 if (__is_instance(arg.value)) 151 return arg; 152 153 /* Invoke non-instances to produce instances. */ 154 155 else 156 return __invoke(arg, 0, 0, 0, 0, 1, args); 157 } 158 159 /* Generic invocation operations. */ 160 161 /* Invoke the given callable, supplying keyword argument details in the given 162 codes and arguments arrays, indicating the number of arguments described. 163 The number of positional arguments is specified, and such arguments then 164 follow as conventional function arguments. Typically, at least one argument 165 is specified, starting with any context argument. 166 */ 167 168 __attr __invoke(__attr callable, int always_callable, 169 unsigned int nkwargs, __param kwcodes[], __attr kwargs[], 170 unsigned int nargs, __attr args[]) 171 { 172 /* Unwrap any wrapped function. */ 173 174 __attr target = __unwrap_callable(callable); 175 176 /* Obtain the __args__ special member, referencing the parameter table. */ 177 /* Refer to the table and minimum/maximum. */ 178 179 const __ptable *ptable = __check_and_load_via_object(target.value, __args__).ptable; 180 const unsigned int min = ptable->min, max = ptable->max; 181 182 /* Reserve enough space for the arguments. */ 183 184 __attr *allargs = args, moreargs[max]; 185 186 /* Traverse the arguments. */ 187 188 unsigned int pos, kwpos; 189 190 /* Check the number of arguments. */ 191 /* NOTE: Should use a more specific exception. */ 192 193 if ((min > (nargs + nkwargs)) || ((nargs + nkwargs) > max)) 194 __raise_type_error(); 195 196 /* Copy the arguments. */ 197 198 if (nargs < max) 199 { 200 allargs = moreargs; 201 202 for (pos = 0; pos < nargs; pos++) 203 allargs[pos] = args[pos]; 204 205 /* Erase the remaining arguments. */ 206 207 for (pos = nargs; pos < max; pos++) 208 allargs[pos].value = 0; 209 210 /* Fill keyword arguments. */ 211 212 for (kwpos = 0; kwpos < nkwargs; kwpos++) 213 { 214 pos = __HASPARAM(ptable, kwcodes[kwpos].pos, kwcodes[kwpos].code); 215 216 /* Check the table entry against the supplied argument details. 217 Set the argument but only if it does not overwrite positional 218 arguments. */ 219 /* NOTE: Should use a more specific exception. */ 220 221 if ((pos == -1) || (pos < nargs)) 222 __raise_type_error(); 223 224 /* Set the argument using the appropriate position. */ 225 226 allargs[pos] = kwargs[kwpos]; 227 } 228 229 /* Fill the defaults. */ 230 231 for (pos = nargs; pos < max; pos++) 232 { 233 if (allargs[pos].value == 0) 234 allargs[pos] = __GETDEFAULT(target.value, pos - min); 235 } 236 } 237 238 /* Call with the prepared arguments via a special adaptor function that 239 converts the array to an argument list. */ 240 241 return __call_with_args( 242 always_callable ? 243 __get_function(allargs[0].value, target) : 244 __check_and_get_function(allargs[0].value, target), 245 allargs, max); 246 } 247 248 /* Error routines. */ 249 250 __attr __unbound_method(__attr __self) 251 { 252 __Raise(__new___builtins___core_UnboundMethodInvocation(__NULL)); 253 return __builtins___none_None; /* superfluous */ 254 } 255 256 /* Generic operations depending on specific program details. */ 257 258 void __SETDEFAULT(__ref obj, int pos, __attr value) 259 { 260 __store_via_object__(obj, __FUNCTION_INSTANCE_SIZE + pos, value); 261 } 262 263 __attr __GETDEFAULT(__ref obj, int pos) 264 { 265 return __load_via_object__(obj, __FUNCTION_INSTANCE_SIZE + pos); 266 } 267 268 int __BOOL(__attr attr) 269 { 270 /* Invoke the bool function with the object and test against True. */ 271 272 return (attr.value == __builtins___boolean_True.value) || 273 (__fn___builtins___boolean_bool(__NULL, attr).value == __builtins___boolean_True.value); 274 }