Lichen

templates/progops.c

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