Lichen

templates/progops.c

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