Lichen

templates/progops.c

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