Lichen

templates/progops.c

303:c07a749f5bd0
2016-12-02 Paul Boddie Use __data__ attributes with native functions apart from when __data__ needs replacing (such as in the list append and concatenation functions).
     1 /* Operations depending on program specifics.     2 */     3      4 #include <stdlib.h>     5 #include "types.h"     6 #include "ops.h"     7 #include "progconsts.h"     8 #include "progops.h"     9 #include "progtypes.h"    10 #include "main.h"    11 #include "exceptions.h"    12     13 /* Generic instantiation operations, defining common members. */    14     15 __attr __new(const __table * table, __ref cls, size_t size)    16 {    17     __ref obj = (__ref) __ALLOCATE(1, size);    18     __attr self = {obj, obj};    19     __attr tmp = {0, cls};    20     obj->table = table;    21     __store_via_object(obj, __pos___class__, tmp);    22     return self;    23 }    24     25 /* Generic internal data allocation. */    26     27 __fragment *__new_fragment(unsigned int n)     28 {    29     /* Allocate space for the list. */    30     31     __fragment *data = (__fragment *) __ALLOCATE(1, __FRAGMENT_SIZE(n));    32     33     /* The initial capacity is the same as the given size. */    34     35     data->size = 0;    36     data->capacity = n;    37     return data;    38 }    39     40 __mapping *__new_mapping(unsigned int n)     41 {    42     /* Allocate a number of buckets. */    43     44     __mapping *data = (__mapping *) __ALLOCATE(1, __MAPPING_SIZE(n));    45     unsigned int i;    46     47     /* Create arrays for key and value buckets. */    48     49     data->keys = (__fragment **) __ALLOCATE(n, sizeof(__fragment *));    50     data->values = (__fragment **) __ALLOCATE(n, sizeof(__fragment *));    51     52     /* Allocate fragments with an initial size of 2, assuming a mostly uniform    53        distribution of values across the buckets will occur. */    54     55     for (i = 0; i < n; i++)    56     {    57         data->keys[i] = __new_fragment(2);    58         data->values[i] = __new_fragment(2);    59     }    60     61     data->size = 0;    62     data->capacity = n;    63     return data;    64 }    65     66 void __newdata_sequence(__attr args[], unsigned int number)    67 {    68     /* Calculate the size of the fragment. */    69     70     __fragment *data = __new_fragment(number);    71     __attr attr = {0, .seqvalue=data};    72     unsigned int i, j;    73     74     /* Copy the given number of values, starting from the second element. */    75     76     for (i = 1, j = 0; i <= number; i++, j++)    77         data->attrs[j] = args[i];    78     79     data->size = number;    80     81     /* Store a reference to the data in the object's __data__ attribute. */    82     83     __store_via_object(args[0].value, __pos___data__, attr);    84 }    85     86 #ifdef __HAVE___builtins___dict_dict    87     88 void __newdata_mapping(__attr args[], unsigned int number)    89 {    90     __mapping *data = __new_mapping(number);    91     __attr attr = {0, .mapvalue=data};    92     __fragment *f;    93     __attr callargs[3];    94     unsigned int i;    95     96     /* Store a reference to the data in the object's __data__ attribute. */    97     98     __store_via_object(args[0].value, __pos___data__, attr);    99    100     /* Store the given number of values, starting from the second element. */   101    102     callargs[0] = args[0];   103    104     for (i = 1; i <= number; i++)   105     {   106         /* Obtain the tuple elements. */   107    108         f = __load_via_object(args[i].value, __pos___data__).seqvalue;   109         callargs[1] = f->attrs[0];   110         callargs[2] = f->attrs[1];   111    112         /* Call __setitem__ with the key and value. */   113    114         __fn___builtins___dict_dict___setitem__(callargs);   115     }   116 }   117    118 #endif /* __HAVE___builtins___dict_dict */   119    120 /* A helper for raising type errors within common operations. */   121    122 void __raise_type_error()   123 {   124     __attr args[1];   125     __attr exc = __TYPE_ERROR_INSTANTIATOR(args);   126     __Raise(exc);   127 }   128    129 /* A helper for raising memory errors within common operations. */   130    131 void __raise_memory_error()   132 {   133     __attr args[1];   134     __attr exc = __MEMORY_ERROR_INSTANTIATOR(args);   135     __Raise(exc);   136 }   137    138 /* Generic invocation operations. */   139    140 /* Invoke the given callable, supplying keyword argument details in the given   141    codes and arguments arrays, indicating the number of arguments described.   142    The number of positional arguments is specified, and such arguments then   143    follow as conventional function arguments. Typically, at least one argument   144    is specified, starting with any context argument.   145 */   146    147 __attr __invoke(__attr callable, int always_callable,   148                 unsigned int nkwargs, __param kwcodes[], __attr kwargs[],   149                 unsigned int nargs, __attr args[])   150 {   151     /* Obtain the __args__ special member, referencing the parameter table. */   152    153     __attr minparams = __check_and_load_via_object(callable.value, __pos___args__, __code___args__);   154    155     /* Refer to the table and minimum/maximum. */   156    157     const __ptable *ptable = minparams.ptable;   158     const unsigned int min = minparams.min, max = ptable->size;   159    160     /* Reserve enough space for the arguments. */   161    162     __attr allargs[max];   163    164     /* Traverse the arguments. */   165    166     unsigned int pos, kwpos;   167    168     /* Check the number of arguments. */   169    170     if ((min > (nargs + nkwargs)) || ((nargs + nkwargs) > max))   171         return __NULL;   172    173     /* Copy the arguments. */   174    175     for (pos = 0; pos < nargs; pos++)   176         allargs[pos] = args[pos];   177    178     /* Erase the remaining arguments. */   179    180     for (pos = nargs; pos < max; pos++)   181     {   182         allargs[pos].value = 0;   183     }   184    185     /* Fill keyword arguments. */   186    187     for (kwpos = 0; kwpos < nkwargs; kwpos++)   188     {   189         pos = __HASPARAM(ptable, kwcodes[kwpos].pos, kwcodes[kwpos].code);   190    191         /* Check the table entry against the supplied argument details.   192            Set the argument but only if it does not overwrite positional   193            arguments. */   194    195         if ((pos == -1) || (pos < nargs))   196             return __NULL;   197    198         /* Set the argument using the appropriate position. */   199    200         allargs[pos] = kwargs[kwpos];   201     }   202    203     /* Fill the defaults. */   204    205     for (pos = nargs; pos < max; pos++)   206     {   207         if (allargs[pos].value == 0)   208             allargs[pos] = __GETDEFAULT(callable.value, pos - min);   209     }   210    211     /* Call with the prepared arguments. */   212    213     return (always_callable ? __load_via_object(callable.value, __pos___fn__)   214                             : __check_and_load_via_object(callable.value, __pos___fn__, __code___fn__)   215                             ).fn(allargs);   216 }   217    218 /* Error routines. */   219    220 __attr __unbound_method(__attr args[])   221 {   222     __attr excargs[1];   223     __attr exc = __new___builtins___core_UnboundMethodInvocation(excargs);   224     __Raise(exc);   225     return __builtins___none_None; /* superfluous */   226 }   227    228 /* Generic operations depending on specific program details. */   229    230 void __SETDEFAULT(__ref obj, int pos, __attr value)   231 {   232     __store_via_object(obj, __FUNCTION_INSTANCE_SIZE + pos, value);   233 }   234    235 __attr __GETDEFAULT(__ref obj, int pos)   236 {   237     return __load_via_object(obj, __FUNCTION_INSTANCE_SIZE + pos);   238 }   239    240 int __BOOL(__attr attr)   241 {   242     __attr args[2] = {{0, 0}, attr};   243    244     /* Invoke the bool function with the object and test against True. */   245    246     return __fn___builtins___boolean_bool(args).value == __builtins___boolean_True.value;   247 }