Lichen

templates/progops.c

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