Lichen

Annotated templates/progops.c

1022:582d834d392d
14 months ago Paul Boddie Merged changes from the value-replacement branch. value-replacement-for-wrapper
paul@126 1
/* Operations depending on program specifics.
paul@353 2
paul@971 3
Copyright (C) 2015-2019, 2021, 2023 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@1018 35
    __store_via_attr_ref__(__get_object_attr_ref(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@971 47
    return __new___builtins___core_wrapper(__NULL, __NULL, context, attr);
paul@126 48
}
paul@126 49
paul@159 50
/* Generic internal data allocation. */
paul@159 51
paul@941 52
__fragment *__new_fragment(__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@941 65
void __newdata_sequence(__int number, __fragment *data, __attr args[])
paul@159 66
{
paul@941 67
    __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@941 77
__attr __newdata_list(__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@1018 84
    __store_via_attr_ref__(__get_object_attr_ref(__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@941 89
__attr __newdata_tuple(__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@1018 100
    __store_via_attr_ref__(__get_object_attr_ref(__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@941 106
__attr __newdata_dict(__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@971 116
    __fn___builtins___dict_dict___init__(__NULL, 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@971 126
    __Raise(__new___builtins___exception_io_EOFError(__NULL, __NULL));
paul@382 127
#endif /* __HAVE___builtins___exception_io_EOFError */
paul@336 128
}
paul@336 129
paul@879 130
void __raise_floating_point_error()
paul@879 131
{
paul@971 132
    __Raise(__new___builtins___core_FloatingPointError(__NULL, __NULL));
paul@879 133
}
paul@879 134
paul@331 135
void __raise_io_error(__attr value)
paul@327 136
{
paul@382 137
#ifdef __HAVE___builtins___exception_io_IOError
paul@971 138
    __Raise(__new___builtins___exception_io_IOError(__NULL, __NULL, value));
paul@382 139
#endif /* __HAVE___builtins___exception_io_IOError */
paul@327 140
}
paul@327 141
paul@306 142
void __raise_memory_error()
paul@306 143
{
paul@971 144
    __Raise(__new___builtins___core_MemoryError(__NULL, __NULL));
paul@306 145
}
paul@306 146
paul@379 147
void __raise_os_error(__attr value, __attr arg)
paul@379 148
{
paul@379 149
#ifdef __HAVE___builtins___exception_system_OSError
paul@971 150
    __Raise(__new___builtins___exception_system_OSError(__NULL, __NULL, value, arg));
paul@379 151
#endif /* __HAVE___builtins___exception_system_OSError */
paul@379 152
}
paul@379 153
paul@306 154
void __raise_overflow_error()
paul@306 155
{
paul@971 156
    __Raise(__new___builtins___core_OverflowError(__NULL, __NULL));
paul@306 157
}
paul@233 158
paul@852 159
void __raise_unbound_method_error()
paul@852 160
{
paul@971 161
    __Raise(__new___builtins___core_UnboundMethodInvocation(__NULL, __NULL));
paul@852 162
}
paul@852 163
paul@233 164
void __raise_type_error()
paul@233 165
{
paul@971 166
    __Raise(__new___builtins___core_TypeError(__NULL, __NULL));
paul@233 167
}
paul@233 168
paul@850 169
void __raise_underflow_error()
paul@850 170
{
paul@971 171
    __Raise(__new___builtins___core_UnderflowError(__NULL, __NULL));
paul@850 172
}
paul@850 173
paul@928 174
void __raise_value_error(__attr value)
paul@928 175
{
paul@928 176
#ifdef __HAVE___builtins___exception_base_ValueError
paul@971 177
    __Raise(__new___builtins___exception_base_ValueError(__NULL, __NULL, value));
paul@928 178
#endif /* __HAVE___builtins___exception_base_ValueError */
paul@928 179
}
paul@928 180
paul@306 181
void __raise_zero_division_error()
paul@260 182
{
paul@971 183
    __Raise(__new___builtins___core_ZeroDivisionError(__NULL, __NULL));
paul@260 184
}
paul@260 185
paul@317 186
/* Helper for raising exception instances. */
paul@317 187
paul@317 188
__attr __ensure_instance(__attr arg)
paul@317 189
{
paul@971 190
    /* Reserve space for the result target and instance. */
paul@317 191
paul@971 192
    __attr args[2] = {__NULL, __NULL};
paul@317 193
paul@317 194
    /* Return instances as provided. */
paul@317 195
paul@757 196
    if (__is_instance(__VALUE(arg)))
paul@317 197
        return arg;
paul@317 198
paul@317 199
    /* Invoke non-instances to produce instances. */
paul@317 200
paul@317 201
    else
paul@971 202
        return __invoke(arg, 0, 0, 0, 0, 2, args);
paul@317 203
}
paul@317 204
paul@126 205
/* Generic invocation operations. */
paul@126 206
paul@126 207
/* Invoke the given callable, supplying keyword argument details in the given
paul@126 208
   codes and arguments arrays, indicating the number of arguments described.
paul@126 209
   The number of positional arguments is specified, and such arguments then
paul@126 210
   follow as conventional function arguments. Typically, at least one argument
paul@126 211
   is specified, starting with any context argument.
paul@126 212
*/
paul@126 213
paul@156 214
__attr __invoke(__attr callable, int always_callable,
paul@126 215
                unsigned int nkwargs, __param kwcodes[], __attr kwargs[],
paul@126 216
                unsigned int nargs, __attr args[])
paul@126 217
{
paul@577 218
    /* Unwrap any wrapped function. */
paul@577 219
paul@577 220
    __attr target = __unwrap_callable(callable);
paul@577 221
paul@126 222
    /* Obtain the __args__ special member, referencing the parameter table. */
paul@126 223
    /* Refer to the table and minimum/maximum. */
paul@126 224
paul@757 225
    const __ptable *ptable = __check_and_load_via_object(__VALUE(target), __args__).ptable;
paul@579 226
    const unsigned int min = ptable->min, max = ptable->max;
paul@126 227
paul@126 228
    /* Reserve enough space for the arguments. */
paul@126 229
paul@661 230
    __attr *allargs = args, moreargs[max];
paul@126 231
paul@126 232
    /* Traverse the arguments. */
paul@126 233
paul@126 234
    unsigned int pos, kwpos;
paul@126 235
paul@126 236
    /* Check the number of arguments. */
paul@760 237
paul@760 238
    if ((nargs == max) && (nkwargs == 0))
paul@760 239
    {
paul@760 240
        /* pass */
paul@760 241
    }
paul@760 242
paul@546 243
    /* NOTE: Should use a more specific exception. */
paul@126 244
paul@760 245
    else if ((min > (nargs + nkwargs)) || ((nargs + nkwargs) > max))
paul@760 246
    {
paul@546 247
        __raise_type_error();
paul@760 248
    }
paul@126 249
paul@126 250
    /* Copy the arguments. */
paul@126 251
paul@760 252
    else if (nargs < max)
paul@661 253
    {
paul@661 254
        allargs = moreargs;
paul@126 255
paul@661 256
        for (pos = 0; pos < nargs; pos++)
paul@661 257
            allargs[pos] = args[pos];
paul@661 258
paul@661 259
        /* Erase the remaining arguments. */
paul@126 260
paul@661 261
        for (pos = nargs; pos < max; pos++)
paul@758 262
            __SETNULL(allargs[pos]);
paul@126 263
paul@661 264
        /* Fill keyword arguments. */
paul@126 265
paul@661 266
        for (kwpos = 0; kwpos < nkwargs; kwpos++)
paul@661 267
        {
paul@661 268
            pos = __HASPARAM(ptable, kwcodes[kwpos].pos, kwcodes[kwpos].code);
paul@126 269
paul@661 270
            /* Check the table entry against the supplied argument details.
paul@661 271
               Set the argument but only if it does not overwrite positional
paul@661 272
               arguments. */
paul@661 273
            /* NOTE: Should use a more specific exception. */
paul@126 274
paul@661 275
            if ((pos == -1) || (pos < nargs))
paul@661 276
                __raise_type_error();
paul@126 277
paul@661 278
            /* Set the argument using the appropriate position. */
paul@126 279
paul@661 280
            allargs[pos] = kwargs[kwpos];
paul@661 281
        }
paul@126 282
paul@661 283
        /* Fill the defaults. */
paul@126 284
paul@661 285
        for (pos = nargs; pos < max; pos++)
paul@661 286
        {
paul@758 287
            if (__ISNULL(allargs[pos]))
paul@757 288
                allargs[pos] = __GETDEFAULT(__VALUE(target), pos - min);
paul@661 289
        }
paul@126 290
    }
paul@126 291
paul@664 292
    /* Call with the prepared arguments via a special adaptor function that
paul@664 293
       converts the array to an argument list. */
paul@126 294
paul@664 295
    return __call_with_args(
paul@664 296
        always_callable ?
paul@971 297
paul@971 298
        /* Remember that the arguments start with the result target and then
paul@971 299
           the context. */
paul@971 300
paul@971 301
        __get_function_unwrapped(allargs[1], target) :
paul@971 302
        __check_and_get_function_unwrapped(allargs[1], target),
paul@664 303
        allargs, max);
paul@126 304
}
paul@126 305
paul@126 306
/* Error routines. */
paul@126 307
paul@971 308
__attr __unbound_method(__attr __result, __attr __self)
paul@126 309
{
paul@971 310
    __Raise(__new___builtins___core_UnboundMethodInvocation(__NULL, __NULL));
paul@193 311
    return __builtins___none_None; /* superfluous */
paul@126 312
}
paul@126 313
paul@126 314
/* Generic operations depending on specific program details. */
paul@126 315
paul@126 316
void __SETDEFAULT(__ref obj, int pos, __attr value)
paul@126 317
{
paul@1018 318
    __store_via_attr_ref__(__get_object_attr_ref__(obj, __FUNCTION_INSTANCE_SIZE + pos), value);
paul@126 319
}
paul@126 320
paul@126 321
__attr __GETDEFAULT(__ref obj, int pos)
paul@126 322
{
paul@624 323
    return __load_via_object__(obj, __FUNCTION_INSTANCE_SIZE + pos);
paul@126 324
}
paul@144 325
paul@144 326
int __BOOL(__attr attr)
paul@144 327
{
paul@893 328
    __ref value;
paul@893 329
paul@941 330
    /* Non-zero integers yield a non-zero result. Since the integer type can be
paul@941 331
       larger than int, a conversion is performed. */
paul@164 332
paul@893 333
    if (__INTEGER(attr))
paul@941 334
        return __TOINT(attr) ? 1 : 0;
paul@893 335
paul@893 336
    /* Test against True and False explicitly. If necessary, invoke the bool
paul@893 337
       function with the object and test against True. */
paul@893 338
paul@893 339
    value = attr.value;
paul@834 340
paul@850 341
    return value == (__ref) &__predefined___builtins___boolean_True ? 1 :
paul@850 342
           value == (__ref) &__predefined___builtins___boolean_False ? 0 :
paul@971 343
           __VALUE(__fn___builtins___boolean_bool(__NULL, __NULL, attr)) == (__ref) &__predefined___builtins___boolean_True;
paul@144 344
}