Lichen

templates/progops.c

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