Lichen

Annotated templates/progops.c

503:644952535f7a
2017-01-23 Paul Boddie Added another, shorter test of get_using, commenting the existing test slightly.
paul@126 1
/* Operations depending on program specifics.
paul@353 2
paul@353 3
Copyright (C) 2015, 2016 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@477 33
    __attr self = {.context=obj, .value=obj};
paul@477 34
    __attr tmp = {.context=0, .value=cls};
paul@126 35
    obj->table = table;
paul@126 36
    __store_via_object(obj, __pos___class__, tmp);
paul@126 37
    return self;
paul@126 38
}
paul@126 39
paul@159 40
/* Generic internal data allocation. */
paul@159 41
paul@283 42
__fragment *__new_fragment(unsigned int n) 
paul@283 43
{
paul@283 44
    /* Allocate space for the list. */
paul@302 45
paul@283 46
    __fragment *data = (__fragment *) __ALLOCATE(1, __FRAGMENT_SIZE(n));
paul@283 47
paul@283 48
    /* The initial capacity is the same as the given size. */
paul@302 49
paul@283 50
    data->size = 0;
paul@283 51
    data->capacity = n;
paul@283 52
    return data;
paul@283 53
}
paul@283 54
paul@283 55
void __newdata_sequence(__attr args[], unsigned int number)
paul@159 56
{
paul@206 57
    /* Calculate the size of the fragment. */
paul@206 58
paul@283 59
    __fragment *data = __new_fragment(number);
paul@477 60
    __attr attr = {{0}, .seqvalue=data};
paul@159 61
    unsigned int i, j;
paul@159 62
paul@159 63
    /* Copy the given number of values, starting from the second element. */
paul@159 64
paul@159 65
    for (i = 1, j = 0; i <= number; i++, j++)
paul@159 66
        data->attrs[j] = args[i];
paul@159 67
paul@159 68
    data->size = number;
paul@283 69
paul@283 70
    /* Store a reference to the data in the object's __data__ attribute. */
paul@283 71
paul@283 72
    __store_via_object(args[0].value, __pos___data__, attr);
paul@283 73
}
paul@283 74
paul@291 75
#ifdef __HAVE___builtins___dict_dict
paul@283 76
void __newdata_mapping(__attr args[], unsigned int number)
paul@283 77
{
paul@304 78
    __attr dict = args[0];
paul@304 79
    __attr callargs[2];
paul@283 80
paul@304 81
    /* Create a temporary list using the arguments. */
paul@283 82
paul@304 83
    __newliteral___builtins___list_list(args, number);
paul@283 84
paul@304 85
    /* Call __init__ with the dict object and list argument. */
paul@283 86
paul@304 87
    callargs[0] = dict;
paul@304 88
    callargs[1] = args[0];
paul@283 89
paul@304 90
    __fn___builtins___dict_dict___init__(callargs);
paul@304 91
    args[0] = dict;
paul@159 92
}
paul@291 93
#endif /* __HAVE___builtins___dict_dict */
paul@291 94
paul@306 95
/* Helpers for raising errors within common operations. */
paul@306 96
paul@336 97
void __raise_eof_error()
paul@336 98
{
paul@382 99
#ifdef __HAVE___builtins___exception_io_EOFError
paul@336 100
    __attr args[1];
paul@336 101
    __attr exc = __new___builtins___exception_io_EOFError(args);
paul@336 102
    __Raise(exc);
paul@382 103
#endif /* __HAVE___builtins___exception_io_EOFError */
paul@336 104
}
paul@336 105
paul@331 106
void __raise_io_error(__attr value)
paul@327 107
{
paul@382 108
#ifdef __HAVE___builtins___exception_io_IOError
paul@477 109
    __attr args[2] = {__NULL, value};
paul@327 110
    __attr exc = __new___builtins___exception_io_IOError(args);
paul@327 111
    __Raise(exc);
paul@382 112
#endif /* __HAVE___builtins___exception_io_IOError */
paul@327 113
}
paul@327 114
paul@306 115
void __raise_memory_error()
paul@306 116
{
paul@306 117
    __attr args[1];
paul@327 118
    __attr exc = __new___builtins___core_MemoryError(args);
paul@306 119
    __Raise(exc);
paul@306 120
}
paul@306 121
paul@379 122
void __raise_os_error(__attr value, __attr arg)
paul@379 123
{
paul@379 124
#ifdef __HAVE___builtins___exception_system_OSError
paul@477 125
    __attr args[3] = {__NULL, value, arg};
paul@379 126
    __attr exc = __new___builtins___exception_system_OSError(args);
paul@379 127
    __Raise(exc);
paul@379 128
#endif /* __HAVE___builtins___exception_system_OSError */
paul@379 129
}
paul@379 130
paul@306 131
void __raise_overflow_error()
paul@306 132
{
paul@306 133
    __attr args[1];
paul@327 134
    __attr exc = __new___builtins___core_OverflowError(args);
paul@306 135
    __Raise(exc);
paul@306 136
}
paul@233 137
paul@233 138
void __raise_type_error()
paul@233 139
{
paul@233 140
    __attr args[1];
paul@327 141
    __attr exc = __new___builtins___core_TypeError(args);
paul@233 142
    __Raise(exc);
paul@233 143
}
paul@233 144
paul@306 145
void __raise_zero_division_error()
paul@260 146
{
paul@260 147
    __attr args[1];
paul@327 148
    __attr exc = __new___builtins___core_ZeroDivisionError(args);
paul@260 149
    __Raise(exc);
paul@260 150
}
paul@260 151
paul@317 152
/* Helper for raising exception instances. */
paul@317 153
paul@317 154
__attr __ensure_instance(__attr arg)
paul@317 155
{
paul@317 156
    /* Reserve space for the instance. */
paul@317 157
paul@317 158
    __attr args[1];
paul@317 159
paul@317 160
    /* Return instances as provided. */
paul@317 161
paul@317 162
    if (__is_instance(arg.value))
paul@317 163
        return arg;
paul@317 164
paul@317 165
    /* Invoke non-instances to produce instances. */
paul@317 166
paul@317 167
    else
paul@317 168
        return __invoke(arg, 0, 0, 0, 0, 1, args);
paul@317 169
}
paul@317 170
paul@126 171
/* Generic invocation operations. */
paul@126 172
paul@126 173
/* Invoke the given callable, supplying keyword argument details in the given
paul@126 174
   codes and arguments arrays, indicating the number of arguments described.
paul@126 175
   The number of positional arguments is specified, and such arguments then
paul@126 176
   follow as conventional function arguments. Typically, at least one argument
paul@126 177
   is specified, starting with any context argument.
paul@126 178
*/
paul@126 179
paul@156 180
__attr __invoke(__attr callable, int always_callable,
paul@126 181
                unsigned int nkwargs, __param kwcodes[], __attr kwargs[],
paul@126 182
                unsigned int nargs, __attr args[])
paul@126 183
{
paul@126 184
    /* Obtain the __args__ special member, referencing the parameter table. */
paul@126 185
paul@241 186
    __attr minparams = __check_and_load_via_object(callable.value, __pos___args__, __code___args__);
paul@126 187
paul@126 188
    /* Refer to the table and minimum/maximum. */
paul@126 189
paul@126 190
    const __ptable *ptable = minparams.ptable;
paul@126 191
    const unsigned int min = minparams.min, max = ptable->size;
paul@126 192
paul@126 193
    /* Reserve enough space for the arguments. */
paul@126 194
paul@126 195
    __attr allargs[max];
paul@126 196
paul@126 197
    /* Traverse the arguments. */
paul@126 198
paul@126 199
    unsigned int pos, kwpos;
paul@126 200
paul@126 201
    /* Check the number of arguments. */
paul@126 202
paul@126 203
    if ((min > (nargs + nkwargs)) || ((nargs + nkwargs) > max))
paul@148 204
        return __NULL;
paul@126 205
paul@126 206
    /* Copy the arguments. */
paul@126 207
paul@126 208
    for (pos = 0; pos < nargs; pos++)
paul@126 209
        allargs[pos] = args[pos];
paul@126 210
paul@126 211
    /* Erase the remaining arguments. */
paul@126 212
paul@126 213
    for (pos = nargs; pos < max; pos++)
paul@126 214
    {
paul@126 215
        allargs[pos].value = 0;
paul@126 216
    }
paul@126 217
paul@126 218
    /* Fill keyword arguments. */
paul@126 219
paul@126 220
    for (kwpos = 0; kwpos < nkwargs; kwpos++)
paul@126 221
    {
paul@126 222
        pos = __HASPARAM(ptable, kwcodes[kwpos].pos, kwcodes[kwpos].code);
paul@126 223
paul@126 224
        /* Check the table entry against the supplied argument details.
paul@126 225
           Set the argument but only if it does not overwrite positional
paul@126 226
           arguments. */
paul@126 227
paul@126 228
        if ((pos == -1) || (pos < nargs))
paul@148 229
            return __NULL;
paul@126 230
paul@126 231
        /* Set the argument using the appropriate position. */
paul@126 232
paul@126 233
        allargs[pos] = kwargs[kwpos];
paul@126 234
    }
paul@126 235
paul@126 236
    /* Fill the defaults. */
paul@126 237
paul@126 238
    for (pos = nargs; pos < max; pos++)
paul@126 239
    {
paul@126 240
        if (allargs[pos].value == 0)
paul@264 241
            allargs[pos] = __GETDEFAULT(callable.value, pos - min);
paul@126 242
    }
paul@126 243
paul@126 244
    /* Call with the prepared arguments. */
paul@126 245
paul@156 246
    return (always_callable ? __load_via_object(callable.value, __pos___fn__)
paul@156 247
                            : __check_and_load_via_object(callable.value, __pos___fn__, __code___fn__)
paul@156 248
                            ).fn(allargs);
paul@126 249
}
paul@126 250
paul@126 251
/* Error routines. */
paul@126 252
paul@126 253
__attr __unbound_method(__attr args[])
paul@126 254
{
paul@193 255
    __attr excargs[1];
paul@193 256
    __attr exc = __new___builtins___core_UnboundMethodInvocation(excargs);
paul@193 257
    __Raise(exc);
paul@193 258
    return __builtins___none_None; /* superfluous */
paul@126 259
}
paul@126 260
paul@126 261
/* Generic operations depending on specific program details. */
paul@126 262
paul@126 263
void __SETDEFAULT(__ref obj, int pos, __attr value)
paul@126 264
{
paul@126 265
    __store_via_object(obj, __FUNCTION_INSTANCE_SIZE + pos, value);
paul@126 266
}
paul@126 267
paul@126 268
__attr __GETDEFAULT(__ref obj, int pos)
paul@126 269
{
paul@126 270
    return __load_via_object(obj, __FUNCTION_INSTANCE_SIZE + pos);
paul@126 271
}
paul@144 272
paul@144 273
int __BOOL(__attr attr)
paul@144 274
{
paul@477 275
    __attr args[2] = {__NULL, attr};
paul@164 276
paul@164 277
    /* Invoke the bool function with the object and test against True. */
paul@164 278
paul@164 279
    return __fn___builtins___boolean_bool(args).value == __builtins___boolean_True.value;
paul@144 280
}