Lichen

Annotated templates/progops.c

843:d305986d05c8
2018-07-05 Paul Boddie Employed sets for attributes and providers referenced by accesses. This causes various attributes to be identified definitively in the access plans and instruction sequences.
paul@126 1
/* Operations depending on program specifics.
paul@353 2
paul@834 3
Copyright (C) 2015, 2016, 2017, 2018 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@664 27
#include "calls.h"
paul@126 28
paul@126 29
/* Generic instantiation operations, defining common members. */
paul@126 30
paul@778 31
void __init(__ref obj, const __table * table, __ref cls)
paul@778 32
{
paul@778 33
    obj->table = table;
paul@778 34
    obj->pos = __INSTANCEPOS;
paul@778 35
    __store_via_object(obj, __class__, __ATTRVALUE(cls));
paul@778 36
}
paul@778 37
paul@756 38
__attr __new(const __table * table, __ref cls, size_t size, int immutable)
paul@126 39
{
paul@756 40
    __ref obj = (__ref) (immutable ? __ALLOCATEIM : __ALLOCATE)(1, size);
paul@778 41
    __init(obj, table, cls);
paul@757 42
    return __ATTRVALUE(obj);
paul@577 43
}
paul@577 44
paul@757 45
__attr __new_wrapper(__attr context, __attr attr)
paul@577 46
{
paul@763 47
    return __new___builtins___core_wrapper(__NULL, context, attr);
paul@126 48
}
paul@126 49
paul@159 50
/* Generic internal data allocation. */
paul@159 51
paul@283 52
__fragment *__new_fragment(unsigned int n) 
paul@283 53
{
paul@283 54
    /* Allocate space for the list. */
paul@302 55
paul@283 56
    __fragment *data = (__fragment *) __ALLOCATE(1, __FRAGMENT_SIZE(n));
paul@283 57
paul@283 58
    /* The initial capacity is the same as the given size. */
paul@302 59
paul@283 60
    data->size = 0;
paul@283 61
    data->capacity = n;
paul@283 62
    return data;
paul@283 63
}
paul@283 64
paul@786 65
void __newdata_sequence(unsigned int number, __fragment *data, __attr args[])
paul@159 66
{
paul@669 67
    unsigned int i;
paul@159 68
paul@669 69
    /* Copy the given number of values. */
paul@159 70
paul@770 71
    for (i = 0; i < number; i++)
paul@669 72
        data->attrs[i] = args[i];
paul@159 73
paul@159 74
    data->size = number;
paul@786 75
}
paul@786 76
paul@786 77
__attr __newdata_list(unsigned int number, __attr args[])
paul@786 78
{
paul@786 79
    __attr self = __NEWINSTANCE(__builtins___list_list);
paul@786 80
    __fragment *data = __new_fragment(number);
paul@283 81
paul@283 82
    /* Store a reference to the data in the object's __data__ attribute. */
paul@283 83
paul@786 84
    __store_via_object(__VALUE(self), __data__, (__attr) {.seqvalue=data});
paul@786 85
    __newdata_sequence(number, data, args);
paul@778 86
    return self;
paul@778 87
}
paul@778 88
paul@786 89
__attr __newdata_tuple(unsigned int number, __attr args[])
paul@778 90
{
paul@778 91
    /* Allocate the tuple and fragment together. */
paul@778 92
paul@785 93
    __attr self = __new(&__INSTANCETABLE(__builtins___tuple_tuple),
paul@786 94
                        &__builtins___tuple_tuple,
paul@786 95
                        __INSTANCESIZE(__builtins___tuple_tuple) + __FRAGMENT_SIZE(number), 0);
paul@786 96
    __fragment *data = (__fragment *) ((void *) __VALUE(self) + __INSTANCESIZE(__builtins___tuple_tuple));
paul@778 97
paul@786 98
    /* Store a reference to the data in the object's __data__ attribute. */
paul@778 99
paul@786 100
    __store_via_object(__VALUE(self), __data__, (__attr) {.seqvalue=data});
paul@786 101
    __newdata_sequence(number, data, args);
paul@669 102
    return self;
paul@283 103
}
paul@283 104
paul@291 105
#ifdef __HAVE___builtins___dict_dict
paul@786 106
__attr __newdata_dict(unsigned int number, __attr args[])
paul@283 107
{
paul@778 108
    __attr self = __NEWINSTANCE(__builtins___dict_dict);
paul@778 109
paul@304 110
    /* Create a temporary list using the arguments. */
paul@283 111
paul@790 112
    __attr tmp = __newdata_list(number, args);
paul@283 113
paul@304 114
    /* Call __init__ with the dict object and list argument. */
paul@283 115
paul@669 116
    __fn___builtins___dict_dict___init__(self, tmp);
paul@669 117
    return self;
paul@159 118
}
paul@291 119
#endif /* __HAVE___builtins___dict_dict */
paul@291 120
paul@306 121
/* Helpers for raising errors within common operations. */
paul@306 122
paul@336 123
void __raise_eof_error()
paul@336 124
{
paul@382 125
#ifdef __HAVE___builtins___exception_io_EOFError
paul@669 126
    __Raise(__new___builtins___exception_io_EOFError(__NULL));
paul@382 127
#endif /* __HAVE___builtins___exception_io_EOFError */
paul@336 128
}
paul@336 129
paul@331 130
void __raise_io_error(__attr value)
paul@327 131
{
paul@382 132
#ifdef __HAVE___builtins___exception_io_IOError
paul@669 133
    __Raise(__new___builtins___exception_io_IOError(__NULL, value));
paul@382 134
#endif /* __HAVE___builtins___exception_io_IOError */
paul@327 135
}
paul@327 136
paul@306 137
void __raise_memory_error()
paul@306 138
{
paul@669 139
    __Raise(__new___builtins___core_MemoryError(__NULL));
paul@306 140
}
paul@306 141
paul@379 142
void __raise_os_error(__attr value, __attr arg)
paul@379 143
{
paul@379 144
#ifdef __HAVE___builtins___exception_system_OSError
paul@669 145
    __Raise(__new___builtins___exception_system_OSError(__NULL, value, arg));
paul@379 146
#endif /* __HAVE___builtins___exception_system_OSError */
paul@379 147
}
paul@379 148
paul@306 149
void __raise_overflow_error()
paul@306 150
{
paul@669 151
    __Raise(__new___builtins___core_OverflowError(__NULL));
paul@306 152
}
paul@233 153
paul@233 154
void __raise_type_error()
paul@233 155
{
paul@669 156
    __Raise(__new___builtins___core_TypeError(__NULL));
paul@233 157
}
paul@233 158
paul@306 159
void __raise_zero_division_error()
paul@260 160
{
paul@669 161
    __Raise(__new___builtins___core_ZeroDivisionError(__NULL));
paul@260 162
}
paul@260 163
paul@317 164
/* Helper for raising exception instances. */
paul@317 165
paul@317 166
__attr __ensure_instance(__attr arg)
paul@317 167
{
paul@317 168
    /* Reserve space for the instance. */
paul@317 169
paul@582 170
    __attr args[1] = {__NULL};
paul@317 171
paul@317 172
    /* Return instances as provided. */
paul@317 173
paul@757 174
    if (__is_instance(__VALUE(arg)))
paul@317 175
        return arg;
paul@317 176
paul@317 177
    /* Invoke non-instances to produce instances. */
paul@317 178
paul@317 179
    else
paul@317 180
        return __invoke(arg, 0, 0, 0, 0, 1, args);
paul@317 181
}
paul@317 182
paul@126 183
/* Generic invocation operations. */
paul@126 184
paul@126 185
/* Invoke the given callable, supplying keyword argument details in the given
paul@126 186
   codes and arguments arrays, indicating the number of arguments described.
paul@126 187
   The number of positional arguments is specified, and such arguments then
paul@126 188
   follow as conventional function arguments. Typically, at least one argument
paul@126 189
   is specified, starting with any context argument.
paul@126 190
*/
paul@126 191
paul@156 192
__attr __invoke(__attr callable, int always_callable,
paul@126 193
                unsigned int nkwargs, __param kwcodes[], __attr kwargs[],
paul@126 194
                unsigned int nargs, __attr args[])
paul@126 195
{
paul@577 196
    /* Unwrap any wrapped function. */
paul@577 197
paul@577 198
    __attr target = __unwrap_callable(callable);
paul@577 199
paul@126 200
    /* Obtain the __args__ special member, referencing the parameter table. */
paul@126 201
    /* Refer to the table and minimum/maximum. */
paul@126 202
paul@757 203
    const __ptable *ptable = __check_and_load_via_object(__VALUE(target), __args__).ptable;
paul@579 204
    const unsigned int min = ptable->min, max = ptable->max;
paul@126 205
paul@126 206
    /* Reserve enough space for the arguments. */
paul@126 207
paul@661 208
    __attr *allargs = args, moreargs[max];
paul@126 209
paul@126 210
    /* Traverse the arguments. */
paul@126 211
paul@126 212
    unsigned int pos, kwpos;
paul@126 213
paul@126 214
    /* Check the number of arguments. */
paul@760 215
paul@760 216
    if ((nargs == max) && (nkwargs == 0))
paul@760 217
    {
paul@760 218
        /* pass */
paul@760 219
    }
paul@760 220
paul@546 221
    /* NOTE: Should use a more specific exception. */
paul@126 222
paul@760 223
    else if ((min > (nargs + nkwargs)) || ((nargs + nkwargs) > max))
paul@760 224
    {
paul@546 225
        __raise_type_error();
paul@760 226
    }
paul@126 227
paul@126 228
    /* Copy the arguments. */
paul@126 229
paul@760 230
    else if (nargs < max)
paul@661 231
    {
paul@661 232
        allargs = moreargs;
paul@126 233
paul@661 234
        for (pos = 0; pos < nargs; pos++)
paul@661 235
            allargs[pos] = args[pos];
paul@661 236
paul@661 237
        /* Erase the remaining arguments. */
paul@126 238
paul@661 239
        for (pos = nargs; pos < max; pos++)
paul@758 240
            __SETNULL(allargs[pos]);
paul@126 241
paul@661 242
        /* Fill keyword arguments. */
paul@126 243
paul@661 244
        for (kwpos = 0; kwpos < nkwargs; kwpos++)
paul@661 245
        {
paul@661 246
            pos = __HASPARAM(ptable, kwcodes[kwpos].pos, kwcodes[kwpos].code);
paul@126 247
paul@661 248
            /* Check the table entry against the supplied argument details.
paul@661 249
               Set the argument but only if it does not overwrite positional
paul@661 250
               arguments. */
paul@661 251
            /* NOTE: Should use a more specific exception. */
paul@126 252
paul@661 253
            if ((pos == -1) || (pos < nargs))
paul@661 254
                __raise_type_error();
paul@126 255
paul@661 256
            /* Set the argument using the appropriate position. */
paul@126 257
paul@661 258
            allargs[pos] = kwargs[kwpos];
paul@661 259
        }
paul@126 260
paul@661 261
        /* Fill the defaults. */
paul@126 262
paul@661 263
        for (pos = nargs; pos < max; pos++)
paul@661 264
        {
paul@758 265
            if (__ISNULL(allargs[pos]))
paul@757 266
                allargs[pos] = __GETDEFAULT(__VALUE(target), pos - min);
paul@661 267
        }
paul@126 268
    }
paul@126 269
paul@664 270
    /* Call with the prepared arguments via a special adaptor function that
paul@664 271
       converts the array to an argument list. */
paul@126 272
paul@664 273
    return __call_with_args(
paul@664 274
        always_callable ?
paul@764 275
        __get_function_unwrapped(allargs[0], target) :
paul@764 276
        __check_and_get_function_unwrapped(allargs[0], target),
paul@664 277
        allargs, max);
paul@126 278
}
paul@126 279
paul@126 280
/* Error routines. */
paul@126 281
paul@664 282
__attr __unbound_method(__attr __self)
paul@126 283
{
paul@669 284
    __Raise(__new___builtins___core_UnboundMethodInvocation(__NULL));
paul@193 285
    return __builtins___none_None; /* superfluous */
paul@126 286
}
paul@126 287
paul@126 288
/* Generic operations depending on specific program details. */
paul@126 289
paul@126 290
void __SETDEFAULT(__ref obj, int pos, __attr value)
paul@126 291
{
paul@624 292
    __store_via_object__(obj, __FUNCTION_INSTANCE_SIZE + pos, value);
paul@126 293
}
paul@126 294
paul@126 295
__attr __GETDEFAULT(__ref obj, int pos)
paul@126 296
{
paul@624 297
    return __load_via_object__(obj, __FUNCTION_INSTANCE_SIZE + pos);
paul@126 298
}
paul@144 299
paul@144 300
int __BOOL(__attr attr)
paul@144 301
{
paul@164 302
    /* Invoke the bool function with the object and test against True. */
paul@164 303
paul@834 304
    __ref value = __VALUE(attr);
paul@834 305
paul@834 306
    return value == &__predefined___builtins___boolean_True ? 1 :
paul@834 307
           value == &__predefined___builtins___boolean_False ? 0 :
paul@772 308
           __VALUE(__fn___builtins___boolean_bool(__NULL, attr)) == &__predefined___builtins___boolean_True;
paul@144 309
}