Lichen

templates/progops.c

334:c3aadc0a672d
2016-12-06 Paul Boddie Attempt to handle module ordering dependencies caused by function defaults.
     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 void __newdata_mapping(__attr args[], unsigned int number)    62 {    63     __attr dict = args[0];    64     __attr callargs[2];    65     66     /* Create a temporary list using the arguments. */    67     68     __newliteral___builtins___list_list(args, number);    69     70     /* Call __init__ with the dict object and list argument. */    71     72     callargs[0] = dict;    73     callargs[1] = args[0];    74     75     __fn___builtins___dict_dict___init__(callargs);    76     args[0] = dict;    77 }    78 #endif /* __HAVE___builtins___dict_dict */    79     80 /* Helpers for raising errors within common operations. */    81     82 #ifdef __HAVE___builtins___exception_io_IOError    83 void __raise_io_error(__attr value)    84 {    85     __attr args[2] = {{0, 0}, value};    86     __attr exc = __new___builtins___exception_io_IOError(args);    87     __Raise(exc);    88 }    89 #endif /* __HAVE___builtins___exception_io_IOError */    90     91 void __raise_memory_error()    92 {    93     __attr args[1];    94     __attr exc = __new___builtins___core_MemoryError(args);    95     __Raise(exc);    96 }    97     98 void __raise_overflow_error()    99 {   100     __attr args[1];   101     __attr exc = __new___builtins___core_OverflowError(args);   102     __Raise(exc);   103 }   104    105 void __raise_type_error()   106 {   107     __attr args[1];   108     __attr exc = __new___builtins___core_TypeError(args);   109     __Raise(exc);   110 }   111    112 void __raise_zero_division_error()   113 {   114     __attr args[1];   115     __attr exc = __new___builtins___core_ZeroDivisionError(args);   116     __Raise(exc);   117 }   118    119 /* Helper for raising exception instances. */   120    121 __attr __ensure_instance(__attr arg)   122 {   123     /* Reserve space for the instance. */   124    125     __attr args[1];   126    127     /* Return instances as provided. */   128    129     if (__is_instance(arg.value))   130         return arg;   131    132     /* Invoke non-instances to produce instances. */   133    134     else   135         return __invoke(arg, 0, 0, 0, 0, 1, args);   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 }