Lichen

templates/progops.c

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