Lichen

templates/progops.c

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