Lichen

templates/progops.c

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