Lichen

templates/ops.c

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