Lichen

templates/ops.c

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