Lichen

Annotated templates/progops.c

601:adcdaeb19307
2017-02-19 Paul Boddie Fixed the context test and set operation to replace the local context with any applicable attribute context. Added a test of method rebinding that requires this fix. method-wrapper-for-context
paul@126 1
/* Operations depending on program specifics.
paul@353 2
paul@523 3
Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
paul@353 4
paul@353 5
This program is free software; you can redistribute it and/or modify it under
paul@353 6
the terms of the GNU General Public License as published by the Free Software
paul@353 7
Foundation; either version 3 of the License, or (at your option) any later
paul@353 8
version.
paul@353 9
paul@353 10
This program is distributed in the hope that it will be useful, but WITHOUT
paul@353 11
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
paul@353 12
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
paul@353 13
details.
paul@353 14
paul@353 15
You should have received a copy of the GNU General Public License along with
paul@353 16
this program.  If not, see <http://www.gnu.org/licenses/>.
paul@126 17
*/
paul@126 18
paul@126 19
#include <stdlib.h>
paul@126 20
#include "types.h"
paul@126 21
#include "ops.h"
paul@126 22
#include "progconsts.h"
paul@126 23
#include "progops.h"
paul@126 24
#include "progtypes.h"
paul@164 25
#include "main.h"
paul@193 26
#include "exceptions.h"
paul@126 27
paul@126 28
/* Generic instantiation operations, defining common members. */
paul@126 29
paul@162 30
__attr __new(const __table * table, __ref cls, size_t size)
paul@126 31
{
paul@260 32
    __ref obj = (__ref) __ALLOCATE(1, size);
paul@126 33
    obj->table = table;
paul@577 34
    __store_via_object(obj, __ATTRPOS(__class__), (__attr) {.value=cls});
paul@577 35
    return (__attr) {.value=obj};
paul@577 36
}
paul@577 37
paul@577 38
__attr __new_wrapper(__ref context, __attr attr)
paul@577 39
{
paul@577 40
    return __new___builtins___core_wrapper((__attr[]) {__NULL, {.value=context}, attr});
paul@126 41
}
paul@126 42
paul@159 43
/* Generic internal data allocation. */
paul@159 44
paul@283 45
__fragment *__new_fragment(unsigned int n) 
paul@283 46
{
paul@283 47
    /* Allocate space for the list. */
paul@302 48
paul@283 49
    __fragment *data = (__fragment *) __ALLOCATE(1, __FRAGMENT_SIZE(n));
paul@283 50
paul@283 51
    /* The initial capacity is the same as the given size. */
paul@302 52
paul@283 53
    data->size = 0;
paul@283 54
    data->capacity = n;
paul@283 55
    return data;
paul@283 56
}
paul@283 57
paul@283 58
void __newdata_sequence(__attr args[], unsigned int number)
paul@159 59
{
paul@206 60
    /* Calculate the size of the fragment. */
paul@206 61
paul@283 62
    __fragment *data = __new_fragment(number);
paul@569 63
    __attr attr = {.seqvalue=data};
paul@159 64
    unsigned int i, j;
paul@159 65
paul@159 66
    /* Copy the given number of values, starting from the second element. */
paul@159 67
paul@159 68
    for (i = 1, j = 0; i <= number; i++, j++)
paul@159 69
        data->attrs[j] = args[i];
paul@159 70
paul@159 71
    data->size = number;
paul@283 72
paul@283 73
    /* Store a reference to the data in the object's __data__ attribute. */
paul@283 74
paul@570 75
    __store_via_object(args[0].value, __ATTRPOS(__data__), attr);
paul@283 76
}
paul@283 77
paul@291 78
#ifdef __HAVE___builtins___dict_dict
paul@283 79
void __newdata_mapping(__attr args[], unsigned int number)
paul@283 80
{
paul@304 81
    __attr dict = args[0];
paul@304 82
    __attr callargs[2];
paul@283 83
paul@304 84
    /* Create a temporary list using the arguments. */
paul@283 85
paul@304 86
    __newliteral___builtins___list_list(args, number);
paul@283 87
paul@304 88
    /* Call __init__ with the dict object and list argument. */
paul@283 89
paul@304 90
    callargs[0] = dict;
paul@304 91
    callargs[1] = args[0];
paul@283 92
paul@304 93
    __fn___builtins___dict_dict___init__(callargs);
paul@304 94
    args[0] = dict;
paul@159 95
}
paul@291 96
#endif /* __HAVE___builtins___dict_dict */
paul@291 97
paul@306 98
/* Helpers for raising errors within common operations. */
paul@306 99
paul@336 100
void __raise_eof_error()
paul@336 101
{
paul@382 102
#ifdef __HAVE___builtins___exception_io_EOFError
paul@336 103
    __attr args[1];
paul@336 104
    __attr exc = __new___builtins___exception_io_EOFError(args);
paul@336 105
    __Raise(exc);
paul@382 106
#endif /* __HAVE___builtins___exception_io_EOFError */
paul@336 107
}
paul@336 108
paul@331 109
void __raise_io_error(__attr value)
paul@327 110
{
paul@382 111
#ifdef __HAVE___builtins___exception_io_IOError
paul@477 112
    __attr args[2] = {__NULL, value};
paul@327 113
    __attr exc = __new___builtins___exception_io_IOError(args);
paul@327 114
    __Raise(exc);
paul@382 115
#endif /* __HAVE___builtins___exception_io_IOError */
paul@327 116
}
paul@327 117
paul@306 118
void __raise_memory_error()
paul@306 119
{
paul@306 120
    __attr args[1];
paul@327 121
    __attr exc = __new___builtins___core_MemoryError(args);
paul@306 122
    __Raise(exc);
paul@306 123
}
paul@306 124
paul@379 125
void __raise_os_error(__attr value, __attr arg)
paul@379 126
{
paul@379 127
#ifdef __HAVE___builtins___exception_system_OSError
paul@477 128
    __attr args[3] = {__NULL, value, arg};
paul@379 129
    __attr exc = __new___builtins___exception_system_OSError(args);
paul@379 130
    __Raise(exc);
paul@379 131
#endif /* __HAVE___builtins___exception_system_OSError */
paul@379 132
}
paul@379 133
paul@306 134
void __raise_overflow_error()
paul@306 135
{
paul@306 136
    __attr args[1];
paul@327 137
    __attr exc = __new___builtins___core_OverflowError(args);
paul@306 138
    __Raise(exc);
paul@306 139
}
paul@233 140
paul@233 141
void __raise_type_error()
paul@233 142
{
paul@233 143
    __attr args[1];
paul@327 144
    __attr exc = __new___builtins___core_TypeError(args);
paul@233 145
    __Raise(exc);
paul@233 146
}
paul@233 147
paul@306 148
void __raise_zero_division_error()
paul@260 149
{
paul@260 150
    __attr args[1];
paul@327 151
    __attr exc = __new___builtins___core_ZeroDivisionError(args);
paul@260 152
    __Raise(exc);
paul@260 153
}
paul@260 154
paul@317 155
/* Helper for raising exception instances. */
paul@317 156
paul@317 157
__attr __ensure_instance(__attr arg)
paul@317 158
{
paul@317 159
    /* Reserve space for the instance. */
paul@317 160
paul@582 161
    __attr args[1] = {__NULL};
paul@317 162
paul@317 163
    /* Return instances as provided. */
paul@317 164
paul@317 165
    if (__is_instance(arg.value))
paul@317 166
        return arg;
paul@317 167
paul@317 168
    /* Invoke non-instances to produce instances. */
paul@317 169
paul@317 170
    else
paul@317 171
        return __invoke(arg, 0, 0, 0, 0, 1, args);
paul@317 172
}
paul@317 173
paul@126 174
/* Generic invocation operations. */
paul@126 175
paul@126 176
/* Invoke the given callable, supplying keyword argument details in the given
paul@126 177
   codes and arguments arrays, indicating the number of arguments described.
paul@126 178
   The number of positional arguments is specified, and such arguments then
paul@126 179
   follow as conventional function arguments. Typically, at least one argument
paul@126 180
   is specified, starting with any context argument.
paul@126 181
*/
paul@126 182
paul@156 183
__attr __invoke(__attr callable, int always_callable,
paul@126 184
                unsigned int nkwargs, __param kwcodes[], __attr kwargs[],
paul@126 185
                unsigned int nargs, __attr args[])
paul@126 186
{
paul@577 187
    /* Unwrap any wrapped function. */
paul@577 188
paul@577 189
    __attr target = __unwrap_callable(callable);
paul@577 190
paul@126 191
    /* Obtain the __args__ special member, referencing the parameter table. */
paul@126 192
    /* Refer to the table and minimum/maximum. */
paul@126 193
paul@579 194
    const __ptable *ptable = __check_and_load_via_object(target.value, __ATTRPOS(__args__), __ATTRCODE(__args__)).ptable;
paul@579 195
    const unsigned int min = ptable->min, max = ptable->max;
paul@126 196
paul@126 197
    /* Reserve enough space for the arguments. */
paul@126 198
paul@126 199
    __attr allargs[max];
paul@126 200
paul@126 201
    /* Traverse the arguments. */
paul@126 202
paul@126 203
    unsigned int pos, kwpos;
paul@126 204
paul@126 205
    /* Check the number of arguments. */
paul@546 206
    /* NOTE: Should use a more specific exception. */
paul@126 207
paul@126 208
    if ((min > (nargs + nkwargs)) || ((nargs + nkwargs) > max))
paul@546 209
        __raise_type_error();
paul@126 210
paul@126 211
    /* Copy the arguments. */
paul@126 212
paul@126 213
    for (pos = 0; pos < nargs; pos++)
paul@126 214
        allargs[pos] = args[pos];
paul@126 215
paul@126 216
    /* Erase the remaining arguments. */
paul@126 217
paul@126 218
    for (pos = nargs; pos < max; pos++)
paul@126 219
    {
paul@126 220
        allargs[pos].value = 0;
paul@126 221
    }
paul@126 222
paul@126 223
    /* Fill keyword arguments. */
paul@126 224
paul@126 225
    for (kwpos = 0; kwpos < nkwargs; kwpos++)
paul@126 226
    {
paul@126 227
        pos = __HASPARAM(ptable, kwcodes[kwpos].pos, kwcodes[kwpos].code);
paul@126 228
paul@126 229
        /* Check the table entry against the supplied argument details.
paul@126 230
           Set the argument but only if it does not overwrite positional
paul@126 231
           arguments. */
paul@546 232
        /* NOTE: Should use a more specific exception. */
paul@126 233
paul@126 234
        if ((pos == -1) || (pos < nargs))
paul@546 235
            __raise_type_error();
paul@126 236
paul@126 237
        /* Set the argument using the appropriate position. */
paul@126 238
paul@126 239
        allargs[pos] = kwargs[kwpos];
paul@126 240
    }
paul@126 241
paul@126 242
    /* Fill the defaults. */
paul@126 243
paul@126 244
    for (pos = nargs; pos < max; pos++)
paul@126 245
    {
paul@126 246
        if (allargs[pos].value == 0)
paul@577 247
            allargs[pos] = __GETDEFAULT(target.value, pos - min);
paul@126 248
    }
paul@126 249
paul@126 250
    /* Call with the prepared arguments. */
paul@126 251
paul@577 252
    return (always_callable ? __get_function(allargs[0].value, target) : __check_and_get_function(allargs[0].value, target))(allargs);
paul@126 253
}
paul@126 254
paul@126 255
/* Error routines. */
paul@126 256
paul@126 257
__attr __unbound_method(__attr args[])
paul@126 258
{
paul@193 259
    __attr excargs[1];
paul@193 260
    __attr exc = __new___builtins___core_UnboundMethodInvocation(excargs);
paul@193 261
    __Raise(exc);
paul@193 262
    return __builtins___none_None; /* superfluous */
paul@126 263
}
paul@126 264
paul@126 265
/* Generic operations depending on specific program details. */
paul@126 266
paul@126 267
void __SETDEFAULT(__ref obj, int pos, __attr value)
paul@126 268
{
paul@126 269
    __store_via_object(obj, __FUNCTION_INSTANCE_SIZE + pos, value);
paul@126 270
}
paul@126 271
paul@126 272
__attr __GETDEFAULT(__ref obj, int pos)
paul@126 273
{
paul@126 274
    return __load_via_object(obj, __FUNCTION_INSTANCE_SIZE + pos);
paul@126 275
}
paul@144 276
paul@144 277
int __BOOL(__attr attr)
paul@144 278
{
paul@477 279
    __attr args[2] = {__NULL, attr};
paul@164 280
paul@164 281
    /* Invoke the bool function with the object and test against True. */
paul@164 282
paul@164 283
    return __fn___builtins___boolean_bool(args).value == __builtins___boolean_True.value;
paul@144 284
}