Lichen

templates/progops.c

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