Lichen

templates/ops.c

600:f92610e27e92
2017-02-19 Paul Boddie Merged changes from the default branch. 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         if (__test_common_instance(context, __TYPEPOS(attrcontext), __TYPECODE(attrcontext)))   218             return 1;   219         else   220             __raise_type_error();   221     }   222    223     /* Test for access to a type class attribute using a type instance. */   224    225     if (__test_specific_type(attrcontext, &__TYPE_CLASS_TYPE) && __is_type_instance(context))   226         return 1;   227    228     /* Otherwise, preserve the attribute as retrieved. */   229    230     return 0;   231 }   232    233 __attr __test_context(__ref context, __attr attr)   234 {   235     /* Update the context or return the unchanged attribute. */   236    237     if (__test_context_update(context, attr))   238         return __update_context(context, attr);   239     else   240         return attr;   241 }   242    243 __attr __update_context(__ref context, __attr attr)   244 {   245     return __new_wrapper(context, attr);   246 }   247    248 /* Context testing for invocations. */   249    250 int __type_method_invocation(__ref context, __attr target)   251 {   252     __ref targetcontext = __CONTEXT_AS_VALUE(target).value;   253    254     /* Require instances, not classes, where methods are function instances. */   255    256     if (!__is_instance(target.value))   257         return 0;   258    259     /* Access the context of the callable and test if it is the type object. */   260    261     return ((targetcontext != 0) && __test_specific_type(targetcontext, &__TYPE_CLASS_TYPE) && __is_type_instance(context));   262 }   263    264 __attr __unwrap_callable(__attr callable)   265 {   266     __attr value = __check_and_load_via_object_null(callable.value, __ATTRPOS(__value__), __ATTRCODE(__value__));   267     return value.value ? value : callable;   268 }   269    270 __attr (*__get_function(__ref context, __attr target))(__attr[])   271 {   272     target = __unwrap_callable(target);   273    274     /* Require null or instance contexts for functions and methods respectively,   275        or type instance contexts for type methods. */   276    277     if ((context == 0) || __is_instance(context) || __type_method_invocation(context, target))   278         return __load_via_object(target.value, __ATTRPOS(__fn__)).fn;   279     else   280         return __unbound_method;   281 }   282    283 __attr (*__check_and_get_function(__ref context, __attr target))(__attr[])   284 {   285     target = __unwrap_callable(target);   286    287     /* Require null or instance contexts for functions and methods respectively,   288        or type instance contexts for type methods. */   289    290     if ((context == 0) || __is_instance(context) || __type_method_invocation(context, target))   291         return __check_and_load_via_object(target.value, __ATTRPOS(__fn__), __ATTRCODE(__fn__)).fn;   292     else   293         return __unbound_method;   294 }   295    296 /* Basic structure tests. */   297    298 int __WITHIN(__ref obj, int pos)   299 {   300     return pos < obj->table->size;   301 }   302    303 int __HASATTR(__ref obj, int pos, int code)   304 {   305     return __WITHIN(obj, pos) && (obj->table->attrs[pos] == code);   306 }   307    308 /* Parameter position operations. */   309    310 int __HASPARAM(const __ptable *ptable, int ppos, int pcode)   311 {   312     __param param;   313    314     if (ppos < ptable->size)   315     {   316         param = ptable->params[ppos];   317         if (param.code == pcode)   318             return param.pos;   319     }   320    321     return -1;   322 }   323    324 /* Conversions. */   325    326 __attr __CONTEXT_AS_VALUE(__attr attr)   327 {   328     return __check_and_load_via_object_null(attr.value, __ATTRPOS(__context__), __ATTRCODE(__context__));   329 }   330    331 /* Type testing. */   332    333 __ref __ISFUNC(__ref obj)   334 {   335     return __test_specific_instance(obj, &__FUNCTION_TYPE);   336 }   337    338 int __ISNULL(__attr value)   339 {   340     return (value.value == 0); /* __NULL.value */   341 }   342    343 /* Attribute codes and positions for type objects. */   344    345 unsigned int __TYPECODE(__ref obj)   346 {   347     return obj->table->attrs[obj->pos];   348 }   349    350 unsigned int __TYPEPOS(__ref obj)   351 {   352     return obj->pos;   353 }   354    355 /* Memory allocation. */   356    357 void *__ALLOCATE(size_t nmemb, size_t size)   358 {   359     void *ptr = GC_MALLOC(nmemb * size); /* sets memory to zero */   360     if (ptr == NULL)   361         __raise_memory_error();   362     return ptr;   363 }   364    365 void *__REALLOCATE(void *ptr, size_t size)   366 {   367     void *nptr = GC_REALLOC(ptr, size);   368     if (nptr == NULL)   369         __raise_memory_error();   370     return nptr;   371 }   372    373 /* Copying of structures. */   374    375 __ref __COPY(__ref obj, int size)   376 {   377     __ref copy = (__ref) __ALLOCATE(1, size);   378     memcpy(copy, obj, size);   379     return copy;   380 }