Lichen

templates/ops.c

611:d1d907801d42
2017-02-23 Paul Boddie Replaced list comprehension usage. method-wrapper-for-context
     1 /* Common operations.     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 "gc.h" /* GC_MALLOC, GC_REALLOC */    20 #include "ops.h"    21 #include "progops.h" /* for raising errors */    22 #include "progconsts.h"    23 #include "progtypes.h"    24     25 /* Direct access and manipulation of static objects. */    26     27 __attr __load_static_ignore(__ref obj)    28 {    29     return (__attr) {.value=obj};    30 }    31     32 __attr __load_static_replace(__ref context, __ref obj)    33 {    34     return __update_context(context, (__attr) {.value=obj});    35 }    36     37 __attr __load_static_test(__ref context, __ref obj)    38 {    39     return __test_context(context, (__attr) {.value=obj});    40 }    41     42 /* Direct retrieval operations, returning and setting attributes. */    43     44 __attr __load_via_object(__ref obj, int pos)    45 {    46     return obj->attrs[pos];    47 }    48     49 __attr __load_via_class(__ref obj, int pos)    50 {    51     return __load_via_object(__get_class(obj), pos);    52 }    53     54 __attr __get_class_and_load(__ref obj, int pos)    55 {    56     if (__is_instance(obj))    57         return __load_via_class(obj, pos);    58     else    59         return __load_via_object(obj, pos);    60 }    61     62 /* Direct storage operations. */    63     64 int __store_via_object(__ref obj, int pos, __attr value)    65 {    66     obj->attrs[pos] = value;    67     return 1;    68 }    69     70 int __get_class_and_store(__ref obj, int pos, __attr value)    71 {    72     /* Forbid class-relative assignments. */    73     74     __raise_type_error();    75     return 0;    76 }    77     78 /* Introspection. */    79     80 int __is_instance(__ref obj)    81 {    82     return obj->pos == __INSTANCEPOS;    83 }    84     85 int __is_type_instance(__ref obj)    86 {    87     return __HASATTR(__get_class(obj), __TYPE_CLASS_POS, __TYPE_CLASS_CODE);    88 }    89     90 __ref __get_class(__ref obj)    91 {    92     return __load_via_object(obj, __pos___class__).value;    93 }    94     95 __attr __get_class_attr(__ref obj)    96 {    97     return __load_via_object(obj, __pos___class__);    98 }    99    100 /* Attribute testing operations. */   101    102 __ref __test_specific_instance(__ref obj, __ref type)   103 {   104     return __get_class(obj) == type ? obj : 0;   105 }   106    107 __ref __test_specific_object(__ref obj, __ref type)   108 {   109     return __test_specific_type(obj, type) || __test_specific_instance(obj, type) ? obj : 0;   110 }   111    112 __ref __test_specific_type(__ref obj, __ref type)   113 {   114     return obj == type ? obj : 0;   115 }   116    117 __ref __test_common_instance(__ref obj, int pos, int code)   118 {   119     return __HASATTR(__get_class(obj), pos, code) ? obj : 0;   120 }   121    122 __ref __test_common_object(__ref obj, int pos, int code)   123 {   124     return __test_common_type(obj, pos, code) || __test_common_instance(obj, pos, code) ? obj : 0;   125 }   126    127 __ref __test_common_type(__ref obj, int pos, int code)   128 {   129     return __HASATTR(obj, pos, code) ? obj : 0;   130 }   131    132 /* Attribute testing and retrieval operations. */   133    134 __attr __check_and_load_via_object_null(__ref obj, int pos, int code)   135 {   136     if (__HASATTR(obj, pos, code))   137         return __load_via_object(obj, pos);   138     else   139         return __NULL;   140 }   141    142 __attr __check_and_load_via_class(__ref obj, int pos, int code)   143 {   144     return __check_and_load_via_object(__get_class(obj), pos, code);   145 }   146    147 __attr __check_and_load_via_object(__ref obj, int pos, int code)   148 {   149     if (__HASATTR(obj, pos, code))   150         return __load_via_object(obj, pos);   151    152     __raise_type_error();   153     return __NULL;   154 }   155    156 __attr __check_and_load_via_any(__ref obj, int pos, int code)   157 {   158     __attr out = __check_and_load_via_object_null(obj, pos, code);   159     if (out.value == 0)   160         out = __check_and_load_via_class(obj, pos, code);   161     return out;   162 }   163    164 /* Attribute testing and storage operations. */   165    166 int __check_and_store_via_class(__ref obj, int pos, int code, __attr value)   167 {   168     /* Forbid class-relative assignments. */   169    170     __raise_type_error();   171     return 0;   172 }   173    174 int __check_and_store_via_object(__ref obj, int pos, int code, __attr value)   175 {   176     if (__HASATTR(obj, pos, code))   177     {   178         __store_via_object(obj, pos, value);   179         return 1;   180     }   181    182     /* No suitable attribute. */   183    184     __raise_type_error();   185     return 0;   186 }   187    188 int __check_and_store_via_any(__ref obj, int pos, int code, __attr value)   189 {   190     if (__check_and_store_via_object(obj, pos, code, value))   191         return 1;   192    193     /* Forbid class-relative assignments. */   194    195     __raise_type_error();   196     return 0;   197 }   198    199 /* Context-related operations. */   200    201 int __test_context_update(__ref context, __attr attr)   202 {   203     /* Return whether the context should be updated for the attribute. */   204    205     __ref attrcontext = __CONTEXT_AS_VALUE(attr).value;   206    207     /* Preserve any existing null or instance context. */   208    209     if ((attrcontext == 0) || __is_instance(attrcontext))   210         return 0;   211    212     /* Test any instance context against the context employed by the   213        attribute. */   214    215     if (__is_instance(context))   216     {   217         /* Obtain the special class attribute position and code identifying the   218            attribute context's class, inspecting the context instance for   219            compatibility. */   220    221         if (__test_common_instance(context, __TYPEPOS(attrcontext), __TYPECODE(attrcontext)))   222             return 1;   223         else   224             __raise_type_error();   225     }   226    227     /* Test for access to a type class attribute using a type instance. */   228    229     if (__test_specific_type(attrcontext, &__TYPE_CLASS_TYPE) && __is_type_instance(context))   230         return 1;   231    232     /* Otherwise, preserve the attribute as retrieved. */   233    234     return 0;   235 }   236    237 __attr __test_context(__ref context, __attr attr)   238 {   239     /* Update the context or return the unchanged attribute. */   240    241     if (__test_context_update(context, attr))   242         return __update_context(context, attr);   243     else   244         return attr;   245 }   246    247 __attr __update_context(__ref context, __attr attr)   248 {   249     return __new_wrapper(context, attr);   250 }   251    252 __attr __test_context_revert(int target, __ref context, __attr attr, __ref contexts[])   253 {   254     /* Revert the local context to that employed by the attribute if the   255        supplied context is not appropriate. */   256    257     if (!__test_context_update(context, attr))   258         contexts[target] = __CONTEXT_AS_VALUE(attr).value;   259     return attr;   260 }   261    262 __attr __test_context_static(int target, __ref context, __ref value, __ref contexts[])   263 {   264     /* Set the local context to the specified context if appropriate. */   265    266     if (__test_context_update(context, (__attr) {.value=value}))   267         contexts[target] = context;   268     return (__attr) {.value=value};   269 }   270    271 /* Context testing for invocations. */   272    273 int __type_method_invocation(__ref context, __attr target)   274 {   275     __ref targetcontext = __CONTEXT_AS_VALUE(target).value;   276    277     /* Require instances, not classes, where methods are function instances. */   278    279     if (!__is_instance(target.value))   280         return 0;   281    282     /* Access the context of the callable and test if it is the type object. */   283    284     return ((targetcontext != 0) && __test_specific_type(targetcontext, &__TYPE_CLASS_TYPE) && __is_type_instance(context));   285 }   286    287 __attr __unwrap_callable(__attr callable)   288 {   289     __attr value = __check_and_load_via_object_null(callable.value, __ATTRPOS(__value__), __ATTRCODE(__value__));   290     return value.value ? value : callable;   291 }   292    293 __attr (*__get_function(__ref context, __attr target))(__attr[])   294 {   295     target = __unwrap_callable(target);   296    297     /* Require null or instance contexts for functions and methods respectively,   298        or type instance contexts for type methods. */   299    300     if ((context == 0) || __is_instance(context) || __type_method_invocation(context, target))   301         return __load_via_object(target.value, __ATTRPOS(__fn__)).fn;   302     else   303         return __unbound_method;   304 }   305    306 __attr (*__check_and_get_function(__ref context, __attr target))(__attr[])   307 {   308     target = __unwrap_callable(target);   309    310     /* Require null or instance contexts for functions and methods respectively,   311        or type instance contexts for type methods. */   312    313     if ((context == 0) || __is_instance(context) || __type_method_invocation(context, target))   314         return __check_and_load_via_object(target.value, __ATTRPOS(__fn__), __ATTRCODE(__fn__)).fn;   315     else   316         return __unbound_method;   317 }   318    319 /* Basic structure tests. */   320    321 int __WITHIN(__ref obj, int pos)   322 {   323     return pos < obj->table->size;   324 }   325    326 int __HASATTR(__ref obj, int pos, int code)   327 {   328     return __WITHIN(obj, pos) && (obj->table->attrs[pos] == code);   329 }   330    331 /* Parameter position operations. */   332    333 int __HASPARAM(const __ptable *ptable, int ppos, int pcode)   334 {   335     __param param;   336    337     if (ppos < ptable->size)   338     {   339         param = ptable->params[ppos];   340         if (param.code == pcode)   341             return param.pos;   342     }   343    344     return -1;   345 }   346    347 /* Conversions. */   348    349 __attr __CONTEXT_AS_VALUE(__attr attr)   350 {   351     return __check_and_load_via_object_null(attr.value, __ATTRPOS(__context__), __ATTRCODE(__context__));   352 }   353    354 /* Type testing. */   355    356 __ref __ISFUNC(__ref obj)   357 {   358     return __test_specific_instance(obj, &__FUNCTION_TYPE);   359 }   360    361 int __ISNULL(__attr value)   362 {   363     return (value.value == 0); /* __NULL.value */   364 }   365    366 /* Attribute codes and positions for type objects. */   367    368 unsigned int __TYPECODE(__ref obj)   369 {   370     return obj->table->attrs[obj->pos];   371 }   372    373 unsigned int __TYPEPOS(__ref obj)   374 {   375     return obj->pos;   376 }   377    378 /* Memory allocation. */   379    380 void *__ALLOCATE(size_t nmemb, size_t size)   381 {   382     void *ptr = GC_MALLOC(nmemb * size); /* sets memory to zero */   383     if (ptr == NULL)   384         __raise_memory_error();   385     return ptr;   386 }   387    388 void *__REALLOCATE(void *ptr, size_t size)   389 {   390     void *nptr = GC_REALLOC(ptr, size);   391     if (nptr == NULL)   392         __raise_memory_error();   393     return nptr;   394 }   395    396 /* Copying of structures. */   397    398 __ref __COPY(__ref obj, int size)   399 {   400     __ref copy = (__ref) __ALLOCATE(1, size);   401     memcpy(copy, obj, size);   402     return copy;   403 }