Lichen

templates/progops.c

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