Lichen

templates/progops.c

923:d5f80f46d267
13 months ago Paul Boddie Fixed integer instance tests. int-as-function
     1 /* Operations depending on program specifics.     2      3 Copyright (C) 2015, 2016, 2017, 2018 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_unbound_method_error()   155 {   156     __Raise(__new___builtins___core_UnboundMethodInvocation(__NULL));   157 }   158    159 void __raise_type_error()   160 {   161     __Raise(__new___builtins___core_TypeError(__NULL));   162 }   163    164 void __raise_zero_division_error()   165 {   166     __Raise(__new___builtins___core_ZeroDivisionError(__NULL));   167 }   168    169 /* Helper for raising exception instances. */   170    171 __attr __ensure_instance(__attr arg)   172 {   173     /* Reserve space for the instance. */   174    175     __attr args[1] = {__NULL};   176    177     /* Return instances as provided. */   178    179     if (__is_instance(__VALUE(arg)))   180         return arg;   181    182     /* Invoke non-instances to produce instances. */   183    184     else   185         return __invoke(arg, 0, 0, 0, 0, 1, args);   186 }   187    188 /* Generic invocation operations. */   189    190 /* Invoke the given callable, supplying keyword argument details in the given   191    codes and arguments arrays, indicating the number of arguments described.   192    The number of positional arguments is specified, and such arguments then   193    follow as conventional function arguments. Typically, at least one argument   194    is specified, starting with any context argument.   195 */   196    197 __attr __invoke(__attr callable, int always_callable,   198                 unsigned int nkwargs, __param kwcodes[], __attr kwargs[],   199                 unsigned int nargs, __attr args[])   200 {   201     /* Unwrap any wrapped function. */   202    203     __attr target = __unwrap_callable(callable);   204    205     /* Obtain the __args__ special member, referencing the parameter table. */   206     /* Refer to the table and minimum/maximum. */   207    208     const __ptable *ptable = __check_and_load_via_object(__VALUE(target), __args__).ptable;   209     const unsigned int min = ptable->min, max = ptable->max;   210    211     /* Reserve enough space for the arguments. */   212    213     __attr *allargs = args, moreargs[max];   214    215     /* Traverse the arguments. */   216    217     unsigned int pos, kwpos;   218    219     /* Check the number of arguments. */   220    221     if ((nargs == max) && (nkwargs == 0))   222     {   223         /* pass */   224     }   225    226     /* NOTE: Should use a more specific exception. */   227    228     else if ((min > (nargs + nkwargs)) || ((nargs + nkwargs) > max))   229     {   230         __raise_type_error();   231     }   232    233     /* Copy the arguments. */   234    235     else if (nargs < max)   236     {   237         allargs = moreargs;   238    239         for (pos = 0; pos < nargs; pos++)   240             allargs[pos] = args[pos];   241    242         /* Erase the remaining arguments. */   243    244         for (pos = nargs; pos < max; pos++)   245             __SETNULL(allargs[pos]);   246    247         /* Fill keyword arguments. */   248    249         for (kwpos = 0; kwpos < nkwargs; kwpos++)   250         {   251             pos = __HASPARAM(ptable, kwcodes[kwpos].pos, kwcodes[kwpos].code);   252    253             /* Check the table entry against the supplied argument details.   254                Set the argument but only if it does not overwrite positional   255                arguments. */   256             /* NOTE: Should use a more specific exception. */   257    258             if ((pos == -1) || (pos < nargs))   259                 __raise_type_error();   260    261             /* Set the argument using the appropriate position. */   262    263             allargs[pos] = kwargs[kwpos];   264         }   265    266         /* Fill the defaults. */   267    268         for (pos = nargs; pos < max; pos++)   269         {   270             if (__ISNULL(allargs[pos]))   271                 allargs[pos] = __GETDEFAULT(__VALUE(target), pos - min);   272         }   273     }   274    275     /* Call with the prepared arguments via a special adaptor function that   276        converts the array to an argument list. */   277    278     return __call_with_args(   279         always_callable ?   280         __get_function_unwrapped(allargs[0], target) :   281         __check_and_get_function_unwrapped(allargs[0], target),   282         allargs, max);   283 }   284    285 /* Error routines. */   286    287 __attr __unbound_method(__attr __self)   288 {   289     __Raise(__new___builtins___core_UnboundMethodInvocation(__NULL));   290     return __builtins___none_None; /* superfluous */   291 }   292    293 /* Generic operations depending on specific program details. */   294    295 void __SETDEFAULT(__ref obj, int pos, __attr value)   296 {   297     __store_via_object__(obj, __FUNCTION_INSTANCE_SIZE + pos, value);   298 }   299    300 __attr __GETDEFAULT(__ref obj, int pos)   301 {   302     return __load_via_object__(obj, __FUNCTION_INSTANCE_SIZE + pos);   303 }   304    305 int __BOOL(__attr attr)   306 {   307     __ref value;   308    309     /* Integers can be used directly as truth values. */   310    311     if (__INTEGER(attr))   312         return __TOINT(attr);   313    314     /* Test against True and False explicitly. If necessary, invoke the bool   315        function with the object and test against True. */   316    317     value = attr.value;   318    319     return value == &__predefined___builtins___boolean_True ? 1 :   320            value == &__predefined___builtins___boolean_False ? 0 :   321            __VALUE(__fn___builtins___boolean_bool(__NULL, attr)) == &__predefined___builtins___boolean_True;   322 }