Lichen

templates/ops.c

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